{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "82162890", "metadata": {}, "outputs": [], "source": [ "from pyfirmata import Arduino\n", "import serial\n", "import time" ] }, { "cell_type": "code", "execution_count": 2, "id": "2fc2905a", "metadata": {}, "outputs": [], "source": [ "class SimpleFeeder(Arduino):\n", " pin_diode = 12\n", " pin_feeder = 8\n", " \n", " def __init__(self, *args, **kwargs):\n", " super(SimpleFeeder, self).__init__(*args, **kwargs)\n", " self.digital[SimpleFeeder.pin_feeder].write(0)\n", " self.digital[SimpleFeeder.pin_diode].write(0)\n", "\n", " def blink(self):\n", " self.digital[SimpleFeeder.pin_diode].write(1)\n", " time.sleep(1)\n", " self.digital[SimpleFeeder.pin_diode].write(0) \n", "\n", " def on(self):\n", " self.digital[SimpleFeeder.pin_diode].write(1)\n", " \n", " def off(self):\n", " self.digital[SimpleFeeder.pin_diode].write(0)\n", " \n", " def feed(self):\n", " self.digital[SimpleFeeder.pin_feeder].write(1)\n", " time.sleep(0.01)\n", " print(0.01)\n", " self.digital[SimpleFeeder.pin_feeder].write(0)" ] }, { "cell_type": "code", "execution_count": 3, "id": "fe78b7d4", "metadata": {}, "outputs": [], "source": [ "class MCSArduino(Arduino):\n", " pin_diode = 13\n", " pin_TTL_1 = 6\n", " pin_TTL_2 = 5\n", " pin_LED_lights = 7\n", " pin_feeder = 8\n", " \n", " def __init__(self, *args, **kwargs):\n", " self.last_cmd = False # False - Arduino LOW, True - Arduino HIGH\n", " self.is_light_off = False\n", " super(MCSArduino, self).__init__(*args, **kwargs)\n", " \n", " def start_or_stop(self): # acquisition\n", " self.last_cmd = not self.last_cmd\n", " self.digital[MCSArduino.pin_diode].write(self.last_cmd)\n", " self.digital[MCSArduino.pin_TTL_1].write(self.last_cmd)\n", " self.digital[MCSArduino.pin_TTL_2].write(self.last_cmd)\n", "\n", " def switch_light(self):\n", " self.is_light_off = not self.is_light_off\n", " self.digital[MCSArduino.pin_LED_lights].write(self.is_light_off)\n", " \n", " def feed(self):\n", " self.digital[MCSArduino.pin_feeder].write(True)\n", " time.sleep(0.02)\n", " self.digital[MCSArduino.pin_feeder].write(False)\n", " \n", " \n", "class FakeArduino():\n", " def __init__(self):\n", " self.is_light_off = False\n", " \n", " def start_or_stop(self):\n", " print(\"Fake Arduino - sending a TTL pulse\")\n", " \n", " def exit(self):\n", " print(\"Fake Arduino - exiting...\")\n", " \n", " def switch_light(self):\n", " self.is_light_off = not self.is_light_off\n", " print(\"Fake Arduino - switching light on/off...\")\n", " \n", " def feed(self):\n", " print(\"Fake Arduino - feeding...\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "99209a2c", "metadata": {}, "outputs": [], "source": [ "class FakeDevice:\n", " def write(self):\n", " pass\n", " def close(self):\n", " pass\n", "\n", "class Feeder:\n", " def __init__(self, port, baudrate=9600):\n", " if port == 'fake':\n", " self.device = FakeDevice()\n", " else:\n", " self.device = serial.Serial(port, baudrate=baudrate)\n", " \n", " def feed(self):\n", " self.device.write('SP200\\r'.encode())\n", " self.device.write('LR6175\\r'.encode())\n", " self.device.write('m\\r'.encode())\n", " \n", " def exit(self):\n", " self.device.close()" ] }, { "cell_type": "code", "execution_count": 5, "id": "4b6156b5", "metadata": {}, "outputs": [], "source": [ "class ArduinoDevice(object):\n", " \"\"\"\n", " NOTE for LINUX users! Include user in the 'dialout' group and restart to\n", " access USB devices.\n", " \"\"\"\n", "\n", " def __init__(self, port=None, baud=9600):\n", " self.device = serial.Serial(port, baud, timeout=.1)\n", "\n", " @staticmethod\n", " def serial_ports():\n", " \"\"\"\n", " Lists available serial ports\n", "\n", " :raises EnvironmentError:\n", " On unsupported or unknown platforms\n", " :returns:\n", " A list of the serial ports available on the system\n", " \"\"\"\n", " return comports()\n", "\n", " def read(self):\n", " return self.device.readline()\n", "\n", " def write(self, data):\n", " return self.device.write(data)\n", "\n", " def close(self):\n", " self.device.close()\n" ] }, { "cell_type": "markdown", "id": "56d33a31", "metadata": {}, "source": [ "### Testing Arduino TTL pulses" ] }, { "cell_type": "code", "execution_count": 19, "id": "a8ee4492", "metadata": {}, "outputs": [], "source": [ "board = MCSArduino('COM10') # Windows - 'COM10', Linux - '/dev/ttyACM0', check /dev/tty*" ] }, { "cell_type": "code", "execution_count": 10, "id": "8aef8b20", "metadata": {}, "outputs": [], "source": [ "# check the light on-off\n", "board.switch_light()" ] }, { "cell_type": "code", "execution_count": 23, "id": "94466a46", "metadata": {}, "outputs": [], "source": [ "# testing sync with acquisition system\n", "board.start_or_stop()" ] }, { "cell_type": "code", "execution_count": 7, "id": "31ee1a03", "metadata": {}, "outputs": [], "source": [ "board.feed()" ] }, { "cell_type": "code", "execution_count": 25, "id": "015a0777", "metadata": {}, "outputs": [], "source": [ "board.digital[8].write(0)" ] }, { "cell_type": "code", "execution_count": 27, "id": "a221e00c", "metadata": {}, "outputs": [], "source": [ "board.digital[13].write(True)" ] }, { "cell_type": "code", "execution_count": 22, "id": "aaf301bc", "metadata": {}, "outputs": [], "source": [ "board.digital[8].write(1)\n", "board.digital[13].write(1)" ] }, { "cell_type": "code", "execution_count": 16, "id": "8887f991", "metadata": {}, "outputs": [], "source": [ "for i in range(10):\n", " time.sleep(5)\n", " board.feed()" ] }, { "cell_type": "code", "execution_count": 5, "id": "c0687f02", "metadata": {}, "outputs": [], "source": [ "# Arduino should blink 2 times\n", "for i in range(4):\n", " board.start_or_stop()\n", " time.sleep(2)" ] }, { "cell_type": "code", "execution_count": 14, "id": "bc432891", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board.digital[5].value" ] }, { "cell_type": "code", "execution_count": 17, "id": "e3445339", "metadata": {}, "outputs": [], "source": [ "board.exit()" ] }, { "cell_type": "markdown", "id": "ff6d72c0", "metadata": {}, "source": [ "## Testing blinking" ] }, { "cell_type": "code", "execution_count": 15, "id": "8e7610f3", "metadata": {}, "outputs": [], "source": [ "board = SimpleFeeder('COM5')" ] }, { "cell_type": "code", "execution_count": 24, "id": "c06dd049", "metadata": {}, "outputs": [], "source": [ "board.on()" ] }, { "cell_type": "code", "execution_count": 25, "id": "fa65a126", "metadata": {}, "outputs": [], "source": [ "board.off()" ] }, { "cell_type": "code", "execution_count": 26, "id": "4be6a3b7", "metadata": {}, "outputs": [], "source": [ "board.exit()" ] }, { "cell_type": "markdown", "id": "89b10d38", "metadata": {}, "source": [ "### Testing feeder" ] }, { "cell_type": "code", "execution_count": 7, "id": "7f0affc0", "metadata": {}, "outputs": [], "source": [ "feeder = SimpleFeeder('COM6')" ] }, { "cell_type": "code", "execution_count": 11, "id": "608b6193", "metadata": {}, "outputs": [], "source": [ "feeder.feed()" ] }, { "cell_type": "code", "execution_count": 7, "id": "9579b355", "metadata": {}, "outputs": [], "source": [ "feeder.exit()" ] }, { "cell_type": "code", "execution_count": 4, "id": "990f5a4f", "metadata": {}, "outputs": [], "source": [ "feeder = Feeder('COM8')\n", "\n", "time.sleep(5) # time to get inside the chamber and see that it works\n", "feeder.feed()\n", "\n", "feeder.exit()" ] }, { "cell_type": "markdown", "id": "e6df6e15", "metadata": {}, "source": [ "### Motors - speaker position calibration" ] }, { "cell_type": "code", "execution_count": 2, "id": "7aac6801", "metadata": {}, "outputs": [], "source": [ "class SpeakerMotor:\n", " \"\"\"\n", " example command to the arduino: +20:600\n", " \n", " +/- direction\n", " 20 number of steps to rotate\n", " 600 speed in steps per second\n", " \"\"\"\n", " \n", " def __init__(self, port, baud=9600):\n", " self.port = port\n", " self.baud = baud\n", " self.diodes_on = False\n", " self.device = serial.Serial(port, baud, timeout=.1)\n", "\n", " def microstep_left(self):\n", " self.device.write('-10:200\\n'.encode('utf-8')) # 90deg is 17120 steps\n", " #time.sleep(0.05)\n", " #print(self.device.readline())\n", "\n", " def microstep_right(self):\n", " self.device.write('+10:200\\n'.encode('utf-8'))\n", "\n", " def switch_diodes(self):\n", " self.device.write('d\\n'.encode('utf-8'))\n", " self.diodes_on = not self.diodes_on\n", " \n", " def rotate(self, direction, degrees, duration):\n", " # direction True CCW, False CW\n", " # degrees in deg, 45, 90 etc.\n", " # duration in sec\n", " speed = 190 * (degrees / duration)\n", " steps = 190 * degrees\n", " \n", " self.turn(1 if direction else -1, int(steps), int(speed))\n", " time.sleep(0.1)\n", " \n", " def turn(self, direction, steps, speed):\n", " assert type(steps) == type(1)\n", " assert type(speed) == type(1)\n", " assert speed > 0\n", " assert speed < 1200\n", " assert steps < 20000\n", " assert abs(direction) == 1\n", " \n", " # +CCW, -CW\n", " command = '%s%s:%s\\n' % ('+' if direction > 0 else '-', str(steps), str(speed))\n", " print('sending ' + command)\n", " self.device.write(command.encode('utf-8'))\n", " \n", " def exit(self):\n", " self.device.close()" ] }, { "cell_type": "code", "execution_count": 9, "id": "f069063a", "metadata": {}, "outputs": [], "source": [ "class CableMotor:\n", " \"\"\"\n", " example command to the arduino: +800:600\n", " \n", " +/- direction\n", " 800 number of steps to rotate (1600 is one turn)\n", " 600 speed in steps per second\n", " \"\"\"\n", " \n", " def __init__(self, port, baud=9600):\n", " self.port = port\n", " self.baud = baud\n", " self.diodes_on = False\n", " self.device = serial.Serial(port, baud, timeout=.1)\n", "\n", " def turn_CW(self):\n", " self.device.write('+1600:800\\n'.encode('utf-8'))\n", "\n", " def turn_CCW(self):\n", " self.device.write('-1600:800\\n'.encode('utf-8'))\n", "\n", " def exit(self):\n", " self.device.close()" ] }, { "cell_type": "code", "execution_count": 1, "id": "6cb83682", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'SpeakerMotor' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;31m# r - rotate right, t - rotate left, q - quit\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0msm\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSpeakerMotor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'COM12'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 7\u001b[0m \u001b[0mout1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mNameError\u001b[0m: name 'SpeakerMotor' is not defined" ] } ], "source": [ "import keyboard\n", "import serial\n", "import time\n", "\n", "# r - rotate right, t - rotate left, q - quit\n", "sm = SpeakerMotor('COM12')\n", "out1 = ''\n", "\n", "try:\n", " while True:\n", " if keyboard.is_pressed('d'): # turn diodes on / off\n", " sm.device.write('d\\n'.encode('utf-8'))\n", " \n", " if keyboard.is_pressed('r'): # microstepping right\n", " sm.microstep_right()\n", " time.sleep(0.1)\n", " if keyboard.is_pressed('t'): # microstepping left\n", " sm.microstep_left()\n", " time.sleep(0.1)\n", "\n", " if keyboard.is_pressed('u'): # slow motion\n", " sm.turn(-1, 17120, 60)\n", " time.sleep(0.1)\n", " if keyboard.is_pressed('y'): # slow motion\n", " sm.turn(1, 17120, 60)\n", " time.sleep(0.1)\n", "\n", " if keyboard.is_pressed('i'): # fast motion\n", " sm.turn(-1, 17120, 200)\n", " time.sleep(0.1)\n", " if keyboard.is_pressed('o'): # fast motion\n", " sm.turn(1, 17120, 200)\n", " time.sleep(0.1)\n", "\n", " if keyboard.is_pressed('m'):\n", " print(\"Still running the thread\")\n", " time.sleep(0.1)\n", " \n", " if keyboard.is_pressed('q'):\n", " print(\"q pressed, ending loop\")\n", " break\n", " \n", "finally:\n", " sm.exit()" ] }, { "cell_type": "markdown", "id": "fdb584fe", "metadata": {}, "source": [ "## Rotate speakers manually" ] }, { "cell_type": "code", "execution_count": 3, "id": "97e091e6", "metadata": {}, "outputs": [], "source": [ "import keyboard\n", "import serial\n", "import time\n", "import threading\n", "\n", "degrees = 90\n", "duration = 30\n", "\n", "# 1st - CW\n", "direction = False\n", "\n", "# 2nd - CCW\n", "#direction = True" ] }, { "cell_type": "code", "execution_count": 4, "id": "e2e5b88d", "metadata": {}, "outputs": [], "source": [ "sm = SpeakerMotor('COM12')" ] }, { "cell_type": "code", "execution_count": 9, "id": "affd93ca", "metadata": {}, "outputs": [], "source": [ "sm.switch_diodes()" ] }, { "cell_type": "code", "execution_count": 24, "id": "822ff96a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sending +17100:570\n", "\n" ] } ], "source": [ "sm.rotate(direction, degrees, duration)" ] }, { "cell_type": "code", "execution_count": 5, "id": "8263dee5", "metadata": {}, "outputs": [], "source": [ "sm.exit()" ] }, { "cell_type": "code", "execution_count": null, "id": "7d4201fb", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "2c6a6aa2", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "ae2fe188", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": null, "id": "b6b43cc0", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "raw", "id": "f4a5438a", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.8" } }, "nbformat": 4, "nbformat_minor": 5 }