{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//import space.kscience.controls.jupyter.ControlsJupyter\n",
    "\n",
    "//USE(ControlsJupyter())\n",
    "USE{\n",
    "    repositories{\n",
    "        maven(\"https://repo.kotlin.link\")\n",
    "    }\n",
    "    dependencies{\n",
    "        implementation(\"space.kscience:controls-jupyter-jvm:0.3.0-dev-2\")\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class LinearDrive(\n",
    "    context: Context,\n",
    "    state: DoubleRangeState,\n",
    "    mass: Double,\n",
    "    pidParameters: PidParameters,\n",
    "    meta: Meta = Meta.EMPTY,\n",
    ") : DeviceConstructor(context.request(DeviceManager), meta) {\n",
    "\n",
    "    val drive by device(VirtualDrive.factory(mass, state))\n",
    "    val pid by device(PidRegulator(drive, pidParameters))\n",
    "\n",
    "    val start by device(LimitSwitch.factory(state.atStartState))\n",
    "    val end by device(LimitSwitch.factory(state.atEndState))\n",
    "\n",
    "\n",
    "    val position by property(state)\n",
    "    var target by mutableProperty(pid.mutablePropertyAsState(Regulator.target, 0.0))\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import kotlin.time.Duration.Companion.milliseconds\n",
    "import kotlin.time.Duration.Companion.seconds\n",
    "\n",
    "val state = DoubleRangeState(0.0, -5.0..5.0)\n",
    "\n",
    "val pidParameters = PidParameters(\n",
    "    kp = 2.5,\n",
    "    ki = 0.0,\n",
    "    kd = -0.1,\n",
    "    timeStep = 0.005.seconds\n",
    ")\n",
    "\n",
    "val device = context.install(\"device\", LinearDrive(context, state, 0.005, pidParameters))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\n",
    "val job = device.run {\n",
    "    val clock = context.clock\n",
    "    val clockStart = clock.now()\n",
    "    doRecurring(10.milliseconds) {\n",
    "        val timeFromStart = clock.now() - clockStart\n",
    "        val t = timeFromStart.toDouble(DurationUnit.SECONDS)\n",
    "        val freq = 0.1\n",
    "\n",
    "        target = 5 * sin(2.0 * PI * freq * t) +\n",
    "                sin(2 * PI * 21 * freq * t + 0.02 * (timeFromStart / pidParameters.timeStep))\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "val maxAge = 10.seconds\n",
    "\n",
    "\n",
    "VisionForge.fragment {\n",
    "    vision {\n",
    "        plotly {\n",
    "            \n",
    "            plotDeviceProperty(device.pid, Regulator.target.name, maxAge = maxAge) {\n",
    "                name = \"target\"\n",
    "            }\n",
    "            \n",
    "            plotNumberState(context, state, maxAge = maxAge) {\n",
    "                name = \"real position\"\n",
    "            }\n",
    "            \n",
    "            plotDeviceProperty(device.pid, Regulator.position.name, maxAge = maxAge) {\n",
    "                name = \"read position\"\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "\n",
    "    vision {\n",
    "        plotly {\n",
    "            plotDeviceProperty(device.start, LimitSwitch.locked.name, maxAge = maxAge) {\n",
    "                name = \"start measured\"\n",
    "                mode = ScatterMode.markers\n",
    "            }\n",
    "            plotDeviceProperty(device.end, LimitSwitch.locked.name, maxAge = maxAge) {\n",
    "                name = \"end measured\"\n",
    "                mode = ScatterMode.markers\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import kotlinx.coroutines.cancel\n",
    "\n",
    "job.cancel()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Kotlin",
   "language": "kotlin",
   "name": "kotlin"
  },
  "ktnbPluginMetadata": {
   "projectDependencies": [
    "controls-kt.controls-jupyter.jvmMain"
   ]
  },
  "language_info": {
   "codemirror_mode": "text/x-kotlin",
   "file_extension": ".kt",
   "mimetype": "text/x-kotlin",
   "name": "kotlin",
   "nbconvert_exporter": "",
   "pygments_lexer": "kotlin",
   "version": "1.8.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}