Dynamixel Motors API
This module provides an API for controlling Dynamixel motors using FTDI devices.
You can list the FTDI devices connected to your computer using the following functions:
dynamixelmotorsapi.listFTDIDevices(): Lists all FTDI devices connected to the computer.dynamixelmotorsapi.listUnusedFTDIDevices(): Lists FTDI devices that are not currently used by any instance of DynamixelMotors in this process.dynamixelmotorsapi.listUsedFTDIDevices(): Lists FTDI devices that are currently used by an instance of DynamixelMotors in this process.
listFTDIDevices
@staticmethod
def listFTDIDevices() -> list
List all the FTDI devices connected to the computer.
Returns:
A list of device names (the ports).
listUnusedFTDIDevices
@staticmethod
def listUnusedFTDIDevices() -> list
List all the FTDI devices that are not currently used by any instance of DynamixelMotors in this process.
Returns:
A list of device names (the ports).
listUsedFTDIDevices
@staticmethod
def listUsedFTDIDevices() -> list
List all the FTDI devices that are currently used by an instance of DynamixelMotors in this process.
Returns:
A list of device names (the ports).
DynamixelMotorsAPI is a Python API to control Dynamixel motors, supporting heterogeneous motor groups where each motor can be a different series with different conversion parameters.
To install the API, run:
pip install https://github.com/SofaComplianceRobotics/DynamixelMotorsAPI@main
The motor group is configured via a list of MotorConfig objects, one per motor, which can be loaded from a dict or JSON file.
DynamixelMotors Class
class DynamixelMotors()
Abstract class to control Dynamixel motors, supporting heterogeneous motor groups where each motor can be a different series with different conversion parameters.
The motor group is configured via a list of MotorConfig objects, one per motor, which can be loaded from a dict or JSON file.
All the motors baud rates should be the same, an exception will raise if not
Example:
from dynamixelmotorsapi import DynamixelMotors
motors = DynamixelMotors.from_json("my_motors.json")
if motors.open():
print("Current angles (rad):", motors.angles)
motors.angles = [0.5, 1.0, -0.5, 1.0]
motors.printStatus()
motors.close()
else:
print("Failed to connect to motors.")
JSON format examples:
[
{
"id": 0,
"model": "XM430-W210",
"pulley_radius": 20, # radius of the pulley in mm
"pulse_center": 2048,
"max_vel": 1000,
"baud_rate": 57600
},
{
"id": 1,
"model": "P_SERIES",
"pulley_radius": 30, # radius of the pulley in mm
"pulse_center": 0,
"max_vel": 500,
"baud_rate": 57600
}
]
{
"id": [0, 1],
"model": ["XM430-W210", "P_SERIES"],
"pulley_radius": [20, 30],
"pulse_center": [2048, 0],
"max_vel": [1000, 500],
"baud_rate": 57600
}
listMotorsModels
@staticmethod
def listMotorsModels() -> list
List the models of Dynamixel motors supported by this API.
from_dicts
@classmethod
def from_dicts(cls, data: list) -> "DynamixelMotors"
Instantiate from a list of per-motor config dicts.
Arguments:
data- list of dicts, each containing the fields for one MotorConfig.
Returns:
A configured DynamixelMotors instance (not yet connected).
Example:
[
{
"id": 0,
"model": "XM430-W210",
"pulley_radius": 20, # radius of the pulley in mm
"pulse_center": 2048,
"max_vel": 1000,
"baud_rate": 57600
},
{
"id": [1, 2],
"model": ["XM430-W210", "P_SERIES"],
"pulley_radius": [0.05, 0.03],
"pulse_center": [0, 0],
"max_vel": [1000, 500],
"baud_rate": 57600
}
]
from_dict
@classmethod
def from_dict(cls, data: dict) -> "DynamixelMotors"
Instantiate from a list of per-motor config dicts.
Arguments:
data- dict of lists, each list containing the fields for the MotorConfig.
Returns:
A configured DynamixelMotors instance (not yet connected).
Example:
{
"id": 0,
"model": "XM430-W210",
"pulley_radius": 20, # radius of the pulley in mm
"pulse_center": 2048,
"max_vel": 1000,
"baud_rate": 57600
}
OR
{
"id": [0, 1],
"model": ["XM430-W210", "P_SERIES"],
"pulley_radius": [20, 30],
"pulse_center": [2048, 0],
"max_vel": [1000, 500],
"baud_rate": 57600
}
from_json
@classmethod
def from_json(cls, path: str) -> "DynamixelMotors"
Instantiate from a JSON file containing a list of per-motor config dicts.
Arguments:
path- path to the JSON file.
Returns:
A configured DynamixelMotors instance (not yet connected).
lengthToPulse
def lengthToPulse(displacement: list) -> list
Convert length (mm) to pulse, per motor.
Arguments:
displacement- list of length values in mm, one per motor.
Returns:
A list of pulse values for each motor.
pulseToLength
def pulseToLength(pulse: list) -> list
Convert pulse to length (mm), per motor.
Arguments:
pulse- list of pulse integer values, one per motor.
Returns:
A list of length values in mm for each motor.
pulseToRad
def pulseToRad(pulse: list) -> list
Convert pulse to radians, per motor.
Arguments:
pulse- list of pulse integer values, one per motor.
Returns:
A list of angles in radians for each motor.
pulseToDeg
def pulseToDeg(pulse: list) -> list
Convert pulse to degrees, per motor.
Arguments:
pulse- list of pulse values, one per motor.
Returns:
A list of angles in degrees for each motor.
open
def open(device_name: str = None, multi_turn: bool = False) -> bool
Open the connection to the motors.
Arguments:
device_name- if set, connect to this specific port; otherwise use the first available.multi_turn- enable multi-turn mode. Angle interval becomes [-2562π, 2562π].
findAndOpen
def findAndOpen(device_name: str = None, multi_turn: bool = False) -> int
Iterate over serial ports and connect to the first available FTDI device.
Arguments:
device_name- if set, try only this port.multi_turn- enable multi-turn mode.
Returns:
Index of the connected port, or -1 if no connection was possible.
emergency_stop
def emergency_stop() -> None
Immediately disable torque on all motors. Does NOT close the serial port — call close() afterwards if needed.
close
def close()
Close the connection to the motors.
printStatus
def printStatus()
Print the current position of the motors in radians, pulses, and degrees.
printConfig
def printConfig()
Print the current configuration of the motors.
current_to_torque
def current_to_torque(currents_mA: List[float] | float,
motor_idx: int = None) -> List[float] | float
Estimate torque (N·mm) from the measured currents (mA) using the polynomial T(I) fitted for the model of the given motor index.
The fit is quadratic in N·m (I in Amperes); the result is converted to N·mm. Returns 0 for currents below the no-load threshold.
Arguments:
current_mA- signed current in milliamps (as returned by getCurrent_mA).motor_idx- index into the active motor list (used to look up the motor model).
Returns:
Estimated torque(s) in N·mm (always >= 0).
torque
@property
def torque() -> list
Get the current torque status of the motors.
torque
@torque.setter
def torque(enable: bool)
Enable or disable torque for the motors.
goal_angles
@property
def goal_angles() -> list
Get the last commanded angles of the motors in radians.
angles
@property
def angles() -> list
Get the current angles of the motors in radians.
angles
@angles.setter
def angles(angles: list)
Set the goal angles of the motors in radians.
goal_positions
@property
def goal_positions() -> list
Get the last commanded positions of the motors in pulses.
positions
@property
def positions() -> list
Get the current positions of the motors in pulses.
positions
@positions.setter
def positions(positions: list)
Set the goal positions of the motors in pulses.
goal_velocities
@property
def goal_velocities() -> list
Get the last commanded velocity (rev/min) for each motor.
goal_velocities
@goal_velocities.setter
def goal_velocities(velocities: list)
Set the goal velocity (rev/min) for each motor.
goal_pwms
@property
def goal_pwms() -> list
Get the last commanded PWM for each motor.
pwms
@property
def pwms() -> list
Get the current PWM of the motors.
pwms
@pwms.setter
def pwms(pwms: list)
Set the goal PWM for each motor.
max_velocity
@property
def max_velocity() -> list
Get the maximum velocity profile (rev/min) for each motor.
max_velocity
@max_velocity.setter
def max_velocity(max_vel: list)
Set the maximum velocity profile (rev/min) in position mode, per motor.
Arguments:
max_vel- list of maximum velocities for each motor in rev/min.
position_p_gain
@property
def position_p_gain() -> list
Get the current position P gains of the motors.
position_p_gain
@position_p_gain.setter
def position_p_gain(p_gains: list)
Set the position P gains of the motors.
position_i_gain
@property
def position_i_gain() -> list
Get the current position I gains of the motors.
position_i_gain
@position_i_gain.setter
def position_i_gain(i_gains: list)
Set the position I gains of the motors.
position_d_gain
@property
def position_d_gain() -> list
Get the current position D gains of the motors.
position_d_gain
@position_d_gain.setter
def position_d_gain(d_gains: list)
Set the position D gains of the motors.
velocity_profile
@property
def velocity_profile() -> list
Get the velocity profile (rev/min) of the motors.
velocity_profile
@velocity_profile.setter
def velocity_profile(profile: list)
Set the velocity profile (rev/min) of the motors.
currents
@property
def currents() -> list
Get the current (mA) of the motors.
currents
@currents.setter
def currents(currents: list)
Set the current (mA) of the motors.
temp_limits
@property
def temp_limits()
Get the temperature limit set for the motors
temp_limits
@temp_limits.setter
def temp_limits(max_temp: list)
Set the maximum temperature of the motors before an overheating error is set
motor_configs
@property
def motor_configs() -> List[MotorConfig]
Get the list of per-motor configurations.
is_connected
@property
def is_connected() -> bool
Check if the motors are connected.
device_name
@property
def device_name() -> str
Get the name of the connected device port.
device_index
@property
def device_index() -> int
Get the index of the device in the list of available motor devices.
moving
@property
def moving() -> list
Check if the motors are moving.
moving_status
@property
def moving_status() -> list
Get the moving status byte of the motors.
See https://emanual.robotis.com/docs/en/dxl/x/xc330-t288/[`moving`](#dynamixelmotorsapi.dynamixelmotors.DynamixelMotors.moving)-status for details.
velocity
@property
def velocity() -> list
Get the current velocity (rev/min) of the motors.
velocity_trajectory
@property
def velocity_trajectory() -> list
Get the velocity (rev/min) trajectory of the motors.
position_trajectory
@property
def position_trajectory() -> list
Get the position (pulse) trajectory of the motors.
temperatures
@property
def temperatures() -> list
Get the temperature of the motors