diff --git a/Picomotor/picomotor-master/.gitignore b/Picomotor/picomotor-master/.gitignore new file mode 100644 index 0000000..eeb514c --- /dev/null +++ b/Picomotor/picomotor-master/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +.ipynb_checkpoints diff --git a/Picomotor/picomotor-master/Picomotor Control-GUI.ipynb b/Picomotor/picomotor-master/Picomotor Control-GUI.ipynb new file mode 100644 index 0000000..717e2db --- /dev/null +++ b/Picomotor/picomotor-master/Picomotor Control-GUI.ipynb @@ -0,0 +1,380 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Control Motor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-05T09:16:26.120393Z", + "start_time": "2017-04-05T09:16:26.063809" + }, + "collapsed": true + }, + "outputs": [], + "source": [ + "from picomotor import MSerial" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = MSerial('COM11', echo=True, wait=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-05T00:11:32.689144Z", + "start_time": "2017-04-05T00:11:32.679622" + }, + "collapsed": true + }, + "outputs": [], + "source": [ + "m.echo = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(m.status_msg())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "donor_unit = dict(x=787, y=588, detector='donor')\n", + "accept_unit = dict(x=625, y=641, detector='acceptor')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.unit = donor_unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.unit = accept_unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vel, acc = 500, 10000\n", + "settings = [\n", + " 'acc a1 0=%d' % acc,\n", + " 'acc a1 1=%d' % acc,\n", + " 'vel a1 0=%d' % vel,\n", + " 'vel a1 1=%d' % vel, \n", + "]\n", + "for s in settings:\n", + " m.serial.flush()\n", + " print(m.sendrecv(s))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.sendrecv('vel')\n", + "m.sendrecv('acc')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# GUI" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-04T22:36:26.442756Z", + "start_time": "2017-04-04T22:36:26.435364" + } + }, + "outputs": [], + "source": [ + "from IPython.display import display, Javascript\n", + "from ipywidgets import interact, interactive, fixed, interact_manual, Layout, HBox, VBox, Box, Label\n", + "import ipywidgets as widgets\n", + "widgets.__version__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-05T00:10:23.067393Z", + "start_time": "2017-04-05T00:10:22.857938" + } + }, + "outputs": [], + "source": [ + "items_base = dict(width='auto', height='40px', margin='6px')\n", + "items_layout = Layout(flex='1 1 auto', **items_base)\n", + "\n", + "detector = widgets.ToggleButton(description=\"Donor\", value=True, button_style='success',\n", + " layout=items_layout)\n", + "axis = widgets.ToggleButtons(\n", + " options=['X', 'Y'],\n", + " value='X',\n", + " description='Axis:',\n", + " disabled=False,\n", + " layout=Layout(flex='1 0 auto', height='auto', margin='5px'),\n", + ")\n", + "delta_wid = widgets.BoundedFloatText(description='Delta:', layout=items_layout)\n", + "movebutton = widgets.Button(description=\"Move!\", layout=items_layout)\n", + "out = widgets.Textarea(\n", + " value='',\n", + " description='Received:',\n", + " layout=Layout(flex='1 1 auto'),\n", + ")\n", + "\n", + "port = HBox([Label('Port:',\n", + " layout=Layout(flex='1 1 auto', width='6em', height='auto', margin='5px')), \n", + " widgets.Text(\n", + " value='COM11',\n", + " description='',\n", + " disabled=False,\n", + " layout=Layout(flex='1 1 auto', width='6em', height='auto', margin='5px'))]\n", + " )\n", + "connect = widgets.Button(description=\"Connect\", layout=items_layout)\n", + "status = widgets.Button(description=\"Check Status\", layout=items_layout)\n", + "status.button_style = 'info'\n", + "\n", + "vb_layout = Layout(flex='1 1 auto')\n", + "vbox = VBox([detector, axis, delta_wid, movebutton], layout=vb_layout)\n", + "\n", + "vba_layout = Layout(flex='1 1 auto', justify_content='space-between')\n", + "vboxa = VBox([port, connect, status], layout=vba_layout)\n", + "\n", + "ctrls = HBox([vboxa, vbox], layout=Layout(flex='1 0 auto'))\n", + "recv = widgets.Text(\n", + " value='',\n", + " description='Received:',\n", + " layout=Layout(flex='1 1 auto', width='95%'),\n", + ")\n", + "sent = widgets.Text(\n", + " value='',\n", + " description='Sent:',\n", + " layout=Layout(flex='1 1 auto', width='95%'),\n", + ")\n", + "sentrecv = VBox([sent, recv])\n", + "main = VBox([ctrls, recv])\n", + "tab = widgets.Tab(children=[vboxa, vbox])\n", + "tab.set_title(0, 'Configure')\n", + "tab.set_title(1, 'Move')\n", + "VBox([tab, sentrecv],\n", + " layout=Layout(overflow_x='scroll', max_width='45em', \n", + " flex='1 1 auto', ))#border='solid'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-05T00:10:23.505156Z", + "start_time": "2017-04-05T00:10:23.501027" + }, + "collapsed": true + }, + "outputs": [], + "source": [ + "js_dialog_code = \"\"\"require(\n", + " [\"base/js/dialog\"], \n", + " function(dialog) {\n", + " dialog.modal({\n", + " title: 'Driver Connection',\n", + " body: 'Please check that driver is connected to the %s detector!',\n", + " buttons: {\n", + " 'OK': {}\n", + " }\n", + " });\n", + " }\n", + ");\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-05T00:10:24.236336Z", + "start_time": "2017-04-05T00:10:24.227961" + } + }, + "outputs": [], + "source": [ + "def on_button_clicked(b):\n", + " if b['new']:\n", + " b['owner'].button_style = 'success'\n", + " b['owner'].description = 'Donor'\n", + " m.unit = donor_unit\n", + " else:\n", + " b['owner'].button_style = 'danger'\n", + " b['owner'].description = 'Acceptor'\n", + " m.unit = accept_unit\n", + " display(Javascript(js_dialog_code % b['owner'].description))\n", + "detector.observe(on_button_clicked, names='value')\n", + "\n", + "def on_move(b):\n", + " m.move(delta_wid.value, axis=axis.value.lower(), vel=200, acc=1000)\n", + "movebutton.on_click(on_move)\n", + "\n", + "def on_checkstatus(b):\n", + " m.status_msg()\n", + "status.on_click(on_checkstatus)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.sendwidget = sent\n", + "m.recvwidget = recv\n", + "m.echo = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.move(1, axis='x', vel=200, acc=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "hide_input": false, + "kernelspec": { + "display_name": "Python [default]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + }, + "nav_menu": {}, + "toc": { + "navigate_menu": true, + "number_sections": false, + "sideBar": true, + "threshold": 4, + "toc_cell": false, + "toc_section_display": "block", + "toc_window_display": false + }, + "widgets": { + "state": { + "e2e0008a58f84eec8ff65e7a4b08c54c": { + "views": [ + { + "cell_index": 1 + } + ] + } + }, + "version": "1.2.0" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Picomotor/picomotor-master/Picomotor Control.ipynb b/Picomotor/picomotor-master/Picomotor Control.ipynb new file mode 100644 index 0000000..46d0729 --- /dev/null +++ b/Picomotor/picomotor-master/Picomotor Control.ipynb @@ -0,0 +1,379 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2017-04-05T09:16:26.120393Z", + "start_time": "2017-04-05T09:16:26.063809" + } + }, + "outputs": [], + "source": [ + "from picomotor import MSerial" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = MSerial('COM11', echo=True, wait=0.1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.echo = True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "r = m.status()\n", + "r" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "donor_unit = dict(x=787, y=588, detector='donor')\n", + "accept_unit = dict(x=625, y=641, detector='acceptor')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.unit = donor_unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.unit = accept_unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# m.serial.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# m.echo = True\n", + "# m.wait = 0.1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vel, acc = 500, 10000\n", + "settings = [\n", + " 'acc a1 0=%d' % acc,\n", + " 'acc a1 1=%d' % acc,\n", + " 'vel a1 0=%d' % vel,\n", + " 'vel a1 1=%d' % vel, \n", + "]\n", + "for s in settings:\n", + " m.serial.flush()\n", + " print(m.sendrecv(s))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.sendrecv('vel')\n", + "m.sendrecv('acc')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.joystick_enable(True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.joystick_enable(False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.unit = donor_unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.unit = accept_unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "m.move(0.04, axis='x', vel=200, acc=1000)\n", + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "m.move(0.21, axis='y', vel=200, acc=1000)\n", + "m.unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m.halt()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "scrolled": false + }, + "outputs": [], + "source": [ + "steps, vel, acc = 1000, 1000, 10000\n", + "for ax in ('x', 'y'):\n", + " for s in (steps, -steps):\n", + " m.move(s, axis=ax, vel=vel, acc=acc)\n", + " while m.is_moving():\n", + " time.sleep(0.05)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "scrolled": false + }, + "outputs": [], + "source": [ + "m.move(1000, axis='x', vel=200, acc=1000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.halt()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.sendrecv('POS')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.sendrecv('SAV')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m.sendrecv('INI')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "hide_input": false, + "kernelspec": { + "display_name": "Python [default]", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + }, + "nav_menu": {}, + "toc": { + "colors": { + "hover_highlight": "#DAA520", + "running_highlight": "#FF0000", + "selected_highlight": "#FFD700" + }, + "moveMenuLeft": true, + "nav_menu": { + "height": "12px", + "width": "252px" + }, + "navigate_menu": true, + "number_sections": true, + "sideBar": true, + "threshold": 4, + "toc_cell": false, + "toc_section_display": "block", + "toc_window_display": false, + "widenNotebook": false + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Picomotor/picomotor-master/README.md b/Picomotor/picomotor-master/README.md new file mode 100644 index 0000000..22825af --- /dev/null +++ b/Picomotor/picomotor-master/README.md @@ -0,0 +1,6 @@ +# picomotor + +Software to control, via a serial port, one or more [Newport actuators 8302](https://www.newport.com/p/8302) (micropositioners) +using the open-loop controller 8752 and the ethernet controller 8753. + +Reference: [87XX_Manual_RevC.pdf](https://github.com/tritemio/picomotor/files/1039338/87XX_Manual_RevC.pdf) diff --git a/Picomotor/picomotor-master/picomotor.py b/Picomotor/picomotor-master/picomotor.py new file mode 100644 index 0000000..60a3a1d --- /dev/null +++ b/Picomotor/picomotor-master/picomotor.py @@ -0,0 +1,116 @@ +""" +Library to control the picomotor driver. +""" + +import serial, time + + +class MSerial: + axis_names = dict(x=0, y=1) + unit = dict(x=1, y=1) + + def __init__(self, port, echo=True, max_retry=2, wait=0.1, sendwidget=None, recvwidget=None, **serial_kws): + kws = dict(baudrate=19200, bytesize=serial.EIGHTBITS, + parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, + timeout=0, xonxoff=True, rtscts=False, dsrdtr=False) + kws.update(serial_kws) + self.serial = serial.Serial(port, **kws) + self.echo = echo + self.wait = wait + self.sendwidget = sendwidget + self.recvwidget = recvwidget + + def send(self, cmd): + """Send a command to the picomotor driver.""" + line = cmd + '\r\n' + retval = self.serial.write(bytes(line, encoding='ascii')) + self.serial.flush() + if self.echo: + self.log(cmd, widget=self.sendwidget) + return retval + + def readlines(self): + """Read response from picomotor driver.""" + return ''.join([l.decode('ASCII') for l in self.serial.readlines()]) + + def log(self, msg, widget=None): + if widget is None: + print(msg, flush=True) + else: + widget.value = msg + + def sendrecv(self, cmd): + """Send a command and (optionally) printing the picomotor driver's response.""" + res = self.send(cmd) + if self.echo: + time.sleep(self.wait) + ret_str = self.readlines() + self.log(ret_str, widget=self.recvwidget) + return res + + def set_axis(self, axis, vel=None, acc=None, driver='a1'): + """Set current axis ('x' or 'y') and (optionally) its velocity.""" + assert axis in self.axis_names + fmt = dict(driver=driver, axis=self.axis_names[axis]) + basecmd = '{cmd} {driver} {axis}={value}' + if acc is not None: + assert 0 < acc <= 32000, 'Acceleration out of range (1..32000).' + cmd = basecmd.format(cmd='ACC', value=acc, **fmt) + self.sendrecv(cmd) + if vel is not None: + assert 0 < vel <= 2000, 'Velocity out of range (1..2000).' + cmd = basecmd.format(cmd='VEL', value=vel, **fmt) + self.sendrecv(cmd) + cmd = 'chl {driver}={axis}'.format(**fmt) + return self.sendrecv(cmd) + + def move_steps(self, steps, axis, vel=None, acc=None, driver='a1', go=True): + """Send command to move `axis` of the given `steps`.""" + self.set_axis(axis, vel=vel, acc=acc, driver=driver) + cmd = 'rel {driver}={steps}'.format(driver=driver, steps=steps) + if go: + cmd = cmd + ' g' + return self.sendrecv(cmd) + + def move(self, units, axis, vel=None, acc=None, driver='a1', go=True): + """Send command to move `axis` of the given `units`. + Uses self.unit for conversion. + """ + steps = round(units * self.unit[axis]) + return self.move_steps(steps, axis, vel=None, acc=None, driver='a1', go=True) + + def go(self): + """Send 'go' command to execute all previously sent move commands.""" + return self.sendrecv('go') + + def halt(self): + """Send 'HAL' command to stop motion with deceleration.""" + return self.sendrecv('hal') + + def joystick_enable(self, enable=True): + """Enable or disable the joystick.""" + cmd = 'JON' if enable else 'JOF' + return self.sendrecv(cmd) + + def status_msg(self): + """Return the driver status byte as an integer (see manual pag. 185).""" + self.send('STA') + time.sleep(self.wait) + ret_str = self.readlines() + if self.echo: + self.log(repr(ret_str), widget=self.recvwidget) + return ret_str + + def status(self): + ret_str = self.status_msg() + i = ret_str.find('A1=') + if i >= 0: + status = int(ret_str[i+5:i+7], 16) + else: + raise IOError("Received: '%s'" % ret_str) + return status + + def is_moving(self): + """Return True if motor is moving, else False.""" + status = self.status() + return status & 0x01 \ No newline at end of file