Python API Usage Guide
This section shows how to use the Python API to communicate with the NML Hand Exoskeleton. Each function sends a specific serial command to the device, which is also documented here for transparency and debugging.
Installation
Install the package locally using:
git clone https://github.com/Neuro-Mechatronics-Interfaces/NML_Hand_Exo.git
cd NML_Hand_Exo
pip install -e .
Creating an Instance
To connect to the device:
from hand_exo import HandExo
exo = HandExo(port='COM3', baudrate=57600, verbose=True)
Common Commands
Below is a list of common Python methods and the serial commands they send:
First lets see if we can see the motor LED turn on:
exo.enable_led(1) # Sends "led:1:on"
If this works the LED on that motor will now be on. Let’s turn it off and enable the motor torque for the motor with the ID 1:
exo.disable_led(1) # Sends "led:1:off"
exo.enable_torque(1) # Sends "enable:1"
You should feel the motor engage. If you want to disable the torque, you can do so with:
exo.disable_torque(1) # Sends "disable:1"
Let’s keep the torque enabled for now. We can get the motor’s current position relatve to the zero position offset (different from the absolute position):
angle = exo.get_motor_angle(1) # Sends "get_angle:1"
To reset the motor position to its zero position, you can use the home command:
exo.home(1) # Sends "home:1",
# You can also reset all motor positions
# exo.home('all')
To set the motor to a specific angle, you can use:
exo.set_motor_angle(1, 45) # Sends "set_angle:1:45" # Counter-Clockwise
exo.set_motor_angle(1, -45) # Sends "set_angle:1:-45" # Clockwise
Note
The angle is relative to the zero position offset, not the absolute position.
There are joint limits configured in the Arduino code that will prevent the angle commands from moving past these limits.
The zero position for every motor configured on the microcontroller is stored in the firmware. You can see what the current value is with:
zero_position = exo.get_zero(1) # Sends "get_zero:1"
If you want to set the current position as the new zero position, you can use:
exo.set_zero(1) # Sends "set_zero:1"
Now the home command will set the motor to this new zero position.
If you want to see the absolute position of the motor, you can use:
abs_angle = exo.get_absolute_motor_angle(1) # Sends "get_absangle:1"
Setting the absolute position of the motor is possible too:
exo.set_absolute_motor_angle(1, 90) # Sends "set_absangle:1:90"
Warning
Setting the absolute angle will not change the zero position offset. Please be careful when using this command after installing motors to prevent damage.
The exo firmware has a built-in safety feature that prevents the motors from moving past their limits. These limits can be accessed with:
limits = exo.get_motor_limits(1) # Sends "get_limits:1"
This returns a tuple with the minimum and maximum angle limits for the motor, for example: (-90, 90)) You can also set new limits for the motor:
exo.set_motor_upper_limit(1, 90) # Sends "set_upper_limit:1:90"
exo.set_motor_lower_limit(1, -90) # Sends "set_lower_limit:1:-90"
exo.set_motor_limits(1, -100, 100) # Sends "set_limits:1:-100:100"
Warning
The programatic joint limits are set to prevent the motors from colliding with the exo device. Please be careful when using this command after installing motors to prevent damage.
All motors have a default velocity and acceleration component to them
vel = exo.get_motor_velocity(1) # Sends "get_vel:1"
accel = exo.get_motor_acceleration(1) # Sends "get_accel:1"
We can adjust the speed and acceleration of the motors. Let’s increase both by 20%
vel = vel + 0.2*vel
accel = accel + 0.2*accel
exo.set_motor_velocity(1, vel) # Sends "set_vel:1:{vel}"
exo.set_motor_acceleration(1, accel) # Sends "set_accel:1:{accel}"
The motors can also provide torque and current readings. You can retrieve these values with:
torque = exo.get_motor_torque(1) current = exo.get_motor_current(1)
If the motor reaches its stall torque and disables itself, the LED will begin flashing every second. The only way to continue using the motor is to reboot it. You can do this with:
exo.reboot_motor(1) # Sends "reboot:1"
All the information regarding the status info of the exo can be retrieved with:
info = exo.info() # Sends "info"
This returns a dictionary with the following keys:
version: Firmware version
n_motors: Number of motors connected
motor_xx: Dictionary with motor information, created for each motor ID
id: Motor ID
angle: Current angle of the motor
zero: Zero position offset
velocity: Current velocity setting
acceleration: Current acceleration setting
torque: Current torque reading
current: Current current reading
Anytime you need to know which commands are available you can use the help command:
help_text = exo.help()
This returns a string with all available commands and their descriptions.
When you’re all done with the exoskeleton, you can close the connection:
exo.close() # No command is sent to the device.
—
Additional Notes
The verbose=True option prints sent and received commands to the terminal with debugging output. Enable this upon initialization or by sending the debug:on command.
The port parameter should be set to the correct serial port for your device (e.g., ‘COM3’ on Windows, ‘/dev/ttyUSB0’ on Linux).
The baudrate parameter should match the baud rate set in the firmware (default is 57600).