-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
12 changed files
with
938 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# SPDX-FileCopyrightText: 2024 Idiap Research Institute <[email protected]> | ||
# | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
__pycache__ | ||
*.egg-info | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# SPDX-FileCopyrightText: 2024 Idiap Research Institute <[email protected]> | ||
# | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
default: | ||
image: python:3.12 | ||
tags: | ||
- docker | ||
- linux | ||
|
||
stages: | ||
- qa | ||
- build | ||
- test | ||
|
||
quality: | ||
stage: qa | ||
script: | ||
- pip install pre-commit | ||
- pre-commit run --all-files | ||
|
||
build-job: | ||
stage: build | ||
script: | ||
- pip install . --no-cache | ||
|
||
test-job: | ||
stage: test | ||
script: | ||
- pip install . | ||
- python3 -m unittest discover tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# SPDX-FileCopyrightText: 2024 Idiap Research Institute <[email protected]> | ||
# | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
repos: | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v5.0.0 | ||
hooks: | ||
- id: check-added-large-files | ||
- id: check-ast | ||
- id: check-case-conflict | ||
- id: check-docstring-first | ||
- id: check-yaml | ||
- id: debug-statements | ||
- id: end-of-file-fixer | ||
- id: trailing-whitespace | ||
- repo: https://github.com/astral-sh/ruff-pre-commit | ||
rev: v0.6.9 | ||
hooks: | ||
- id: ruff | ||
args: [ --fix ] | ||
- id: ruff-format | ||
- repo: https://github.com/fsfe/reuse-tool | ||
rev: v4.0.3 | ||
hooks: | ||
- id: reuse |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// SPDX-FileCopyrightText: 2024 Idiap Research Institute <[email protected]> | ||
// | ||
// SPDX-FileContributor: Michael Liebling <[email protected]> | ||
// | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
/* | ||
Firmware for Arduino connected to a Sparkfun stepper motor driver | ||
that interacts with a computer over a serial port and via | ||
the Python library arduino_twister. | ||
*/ | ||
|
||
const char FIRMWARE_NAME[] = "ArduinoPyTwister"; | ||
const char VERSION[] = "0.1"; | ||
|
||
/* Acceptable instruction codes */ | ||
const String RESET_CODE = "RES"; | ||
const String FIRMWARE_CODE = "FIR"; | ||
const String VERSION_CODE = "VER"; | ||
const unsigned char TURN_CODE_PREFIX = 'T'; | ||
|
||
/* Error and Acknowledgement codes (single byte) */ | ||
const unsigned char ACK = 0; | ||
const unsigned char ERR = 1; | ||
|
||
/* How Sparkfun Easy Driver stepper motor driver | ||
connectors are connected to Arduino */ | ||
const unsigned short PIN_ENABLE = 2; | ||
const unsigned short PIN_DIR = 3; | ||
const unsigned short PIN_STEP = 4; | ||
|
||
/* How long to wait between rotation steps */ | ||
const unsigned short stepDelayMs = 2; //ms | ||
/* How long to wait after rotation is complete */ | ||
const unsigned short stopDelayMs = 200; //ms | ||
|
||
void reset() | ||
{ /* Reset Easy Driver pins to default states */ | ||
digitalWrite(PIN_STEP, LOW); | ||
digitalWrite(PIN_DIR, LOW); | ||
digitalWrite(PIN_ENABLE, LOW); | ||
} | ||
|
||
void setup() | ||
{ /* This function is run automatically when Arduino is powered up */ | ||
pinMode(PIN_STEP, OUTPUT); | ||
pinMode(PIN_DIR, OUTPUT); | ||
pinMode(PIN_ENABLE, OUTPUT); | ||
pinMode(LED_BUILTIN, OUTPUT); | ||
reset(); | ||
//Serial.begin(19200); | ||
Serial.begin(9600); | ||
} | ||
|
||
void loop() | ||
{ /* This function loops over to accept instructions over the serial port | ||
Properly formatted commands are three characters long. If the first | ||
character is TURN_CODE_PREFIX the last two characters are interpreted as | ||
the number of steps and rotation direction direction. | ||
*/ | ||
char received_command[3]; | ||
if (Serial.available() >= 3) | ||
{ /* All commands are made of three characters; as soon as buffer contains | ||
three characters, we read themm in. */ | ||
received_command[0] = Serial.read(); | ||
received_command[1] = Serial.read(); | ||
received_command[2] = Serial.read(); | ||
/* DEBUG | ||
Serial.print("Received:"); | ||
Serial.println(received_command); | ||
DEBUG */ | ||
/* Next we interpret the commands */ | ||
if (String(received_command)==RESET_CODE){ // Reset Arduino | ||
reset(); | ||
}else if (String(received_command)==FIRMWARE_CODE){ | ||
/* Return the firmware name */ | ||
//Serial.println("Firmware"); | ||
Serial.println(FIRMWARE_NAME); | ||
} else if(String(received_command)==VERSION_CODE){ | ||
/* Return the firmare version number */ | ||
Serial.println(VERSION); | ||
} else if (received_command[0]==TURN_CODE_PREFIX){ | ||
/* Rotate the twister */ | ||
int16_t steps = rotation_code_to_int16(received_command); | ||
/* DEBUG | ||
Serial.print("Rotating by "); | ||
Serial.print(steps,DEC); | ||
Serial.println(" steps."); | ||
DEBUG */ | ||
rotate_by_steps(steps); | ||
Serial.write(ACK); | ||
}else{ | ||
/* The command is unrecognized. */ | ||
//Serial.write(ERR); | ||
/* DEBUG | ||
Serial.println("Unrecognized command."); | ||
DEBUG */ | ||
Serial.write(ERR); | ||
} | ||
} | ||
} | ||
|
||
int16_t rotation_code_to_int16(char* rotation_command ){ | ||
/* | ||
Extract the last two bytes of a 3-byte rotation command | ||
and convert them to a signed integer that represents | ||
the number of steps to take in the rotation. The first | ||
byte or the 3-byte rotation command, which contains the | ||
rotation code that serves to identify the instruction, | ||
is ignored by this function. | ||
The sign corresponds to the direction of the rotation. | ||
Returns: steps as an int16_t (signed 2-byte integer) | ||
*/ | ||
uint8_t steps_b[2]; | ||
steps_b[0] = rotation_command[1]; | ||
steps_b[1] = rotation_command[2]; | ||
int16_t steps = steps_b[0] | (int16_t)steps_b[1] << 8; | ||
return(steps); | ||
} | ||
|
||
void rotate_by_steps(int steps) | ||
{ | ||
/* | ||
Instruct the stepper motor to turn by | ||
`steps` times 0.225° degrees. | ||
Rotation table for Sparkfun Easy Driver | ||
in eigth-step mode: | ||
1 step: 1.8°/8 = 0.2250° | ||
8 steps: 1.8° | ||
1 step: 1.8°/8 = 0.2250° | ||
8 steps: 1.8° | ||
steps angle # steps # steps | ||
increment in 180° in 360° | ||
1 0.225° 800 1600 | ||
8 1.8° 100 200 | ||
16 3.6° 50 100 | ||
80 18° 10 20 | ||
100 22.5° 8 16 | ||
200 45° 4 8 | ||
400 90° 2 4 | ||
800 180° 1 2 | ||
*/ | ||
if (steps < 0) | ||
{ | ||
digitalWrite(PIN_DIR, HIGH); | ||
steps = -steps; | ||
} | ||
else | ||
{ | ||
digitalWrite(PIN_DIR, LOW); | ||
} | ||
for (int i = 0; i < steps; i++) | ||
{ | ||
digitalWrite(PIN_STEP, HIGH); | ||
delay(stepDelayMs); | ||
digitalWrite(PIN_STEP, LOW); | ||
delay(stepDelayMs); | ||
} | ||
delay(stopDelayMs); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Copyright (c) <year> <owner>. | ||
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
|
||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<!-- | ||
SPDX-FileCopyrightText: 2024 Idiap Research Institute <[email protected]> | ||
SPDX-License-Identifier: BSD-3-Clause | ||
--> | ||
|
||
# arduino_pytwister | ||
|
||
## Description | ||
|
||
This Python library allows interacting with a stepper motor that rotates a stage. The stepper motor is connected to a Sparkfun driver which is itself connected to an Arduino microcontroller. | ||
|
||
## Installation | ||
|
||
arduino_pytwister has been developed for Python 3. | ||
|
||
```bash | ||
conda create -n envname python>=3.7 | ||
conda activate envname | ||
pip install . | ||
``` | ||
|
||
On Linux, add yourself to the `dialout`group | ||
```bash | ||
sudo usermod -a -G dialout $USER | ||
``` | ||
|
||
### Arduino | ||
|
||
arduino_pytwister expects to interact with an Arduino Uno. The latter is connected to an [EasyDriver Stepper Motor Driver - ROB-12779 by SparkFun Electronics](https://www.sparkfun.com/products/12779). | ||
|
||
The wiring is as follows: | ||
|
||
![EasyDriverHookup](https://cdn.sparkfun.com/assets/learn_tutorials/2/4/1/EasyDriverHookup_bb2.png) | ||
|
||
Connect the arduino to the computer USB and to a power source. | ||
|
||
Open the `ArduinoPyTwisterFirmware/ArduinoPyTwisterFirmware.ino` with the [Arduino IDE software](https://www.arduino.cc/en/software) and upload it to the Arduino. | ||
|
||
## Usage | ||
|
||
The package provides the following key functions: | ||
|
||
1. `get_comport_list`: wrapper function to identify available serial ports | ||
2. `get_arduino_ports`: function to identify serial ports linked to connected arduinos | ||
3. `scan_list_for_arduinopytwister`: function to identify the serial port linked to a connected arduino with the correct `ArduinoPyTwisterFirmware.ino` code uploaded. | ||
4. `get_serial_object_to_arduino`: function to obtain a serial object that can be used to communicate with the arduino | ||
5. `rotate_by_steps`: the function to instruct rotation | ||
|
||
An example of a simple interation would be: | ||
|
||
```python | ||
import pytwister as pt | ||
port_list = pt.arduino.get_comport_list() | ||
arduino_ports = pt.arduino.get_arduino_ports(port_list) | ||
twister_port = pt.arduino.scan_list_for_arduinopytwister(arduino_ports) | ||
ser = pt.arduino.get_serial_object_to_arduino(twister_port) | ||
pt.arduino.rotate_by_steps(ser, -200) | ||
pt.arduino.rotate_by_steps(ser, 200) | ||
``` | ||
|
||
The number of steps can be any integer in the range [-32768,32767]. | ||
|
||
Each step corresponds to 0.225° (degrees). | ||
|
||
The `Twister` convenience class gives a high-level control interface. | ||
An example of the same simple iteration would be: | ||
|
||
```python | ||
import pytwister as pt | ||
twister = pt.Twister() | ||
twister.rotate_rel(45) | ||
twister.rotate_abs(0) | ||
``` | ||
|
||
Conversion table for Sparkfun Easy Driver in eigth-step mode: | ||
|
||
| steps | angle increment | | ||
| ----: | :---: | | ||
| 1 | 1.8°/8 =0.225° | | ||
| 8 | 1.8° | | ||
| 16 | 3.6° | | ||
| 80 | 18° | | ||
| 100 | 22.5° | | ||
| 200 | 45° | | ||
| 400 | 90° | | ||
| 800 | 180° | | ||
| 1600 | 360° | | ||
|
||
## Support | ||
|
||
This software is provided as-is. | ||
|
||
## Contributing | ||
|
||
Extensions should be accompanied by a test and clear function/class headers. Tests are gathered in `test_arduino_twister.py` | ||
|
||
```python | ||
python3 -m unittest discover tests | ||
``` | ||
|
||
The tests are run in "dummy" mode and there is currently no requirement that an arduino is connected. | ||
|
||
## Authors and acknowledgment | ||
|
||
Michael Liebling | ||
Idiap Research Institute | ||
April 2023 | ||
|
||
Francois Marelli | ||
Idiap Research Institute | ||
April 2023 | ||
|
||
inspired by related projects (µmanager, etc.) | ||
|
||
## License | ||
|
||
BSD-3 |
Oops, something went wrong.