本页面向初次接触 roboto_motors 的 Python 开发者,演示如何从零开始通过 Python 接口创建电机实例、切换控制模式、发送运动指令并读取实时反馈。阅读本页前,请确保已完成 CAN 接口配置,且 Python 模块 motors_py 已通过编译安装到当前环境中。
Sources: CMakeLists.txt
前置准备
在编写代码之前,请确认以下两项前置工作已完成:一是系统 CAN 总线接口已正确启动,具体配置方法可参考 CAN总线接口配置;二是本项目的 C++ 核心库与 Python 绑定模块已编译并安装,安装流程请参考 编译依赖与安装。编译成功后,Python 模块名为 motors_py,通常会被安装到当前 Python 环境的 site-packages 路径下。
Sources: CMakeLists.txt
快速流程概览
下图展示了使用 Python SDK 控制一台电机的标准生命周期:从导入模块、实例化电机,到初始化使能、进入控制循环,最后安全关闭。初学者建议严格按照这一顺序编写代码,以避免因跳过初始化或遗漏失能步骤而导致的总线异常或电机失控。
flowchart TD
A[导入 motors_py] --> B[调用 create_motor 创建实例]
B --> C[调用 init_motor 初始化并使能]
C --> D[选择控制模式 MIT / POS / SPD]
D --> E[发送控制指令]
E --> F[调用 refresh_motor_status 更新状态]
F --> G[读取位置/速度/电流/温度]
G --> H{是否继续控制?}
H -->|是| E
H -->|否| I[调用 deinit_motor 失能并释放]
Sources: src/pybind_module.cpp
导入模块与核心类
Python SDK 基于 pybind11 将 C++ 核心库绑定为原生 Python 模块。使用时仅需导入 motors_py 包中的 MotorDriver 类和 MotorControlMode 枚举:
from motors_py import MotorDriver, MotorControlMode
MotorDriver 是对 C++ 抽象基类的 Python 封装,内部通过 std::shared_ptr 自动管理内存生命周期,用户无需手动释放。MotorControlMode 提供了三种电机控制模式的常量:MIT(阻抗控制)、POS(位置控制)和 SPD(速度控制)。
Sources: src/pybind_module.cpp
创建电机实例
所有品牌与型号的电机均通过工厂方法 MotorDriver.create_motor() 统一创建,该方法会根据 motor_type 参数在底层自动分派到对应的驱动实现类(DM、EVO 或 LRO)。
工厂方法参数说明
| 参数 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
motor_id |
int |
是 | 电机在 CAN/CAN-FD 总线上的节点 ID,例如 0x01 |
interface_type |
str |
是 | 通信协议类型,目前固定填 "can" 或 "canfd" |
interface |
str |
是 | SocketCAN 接口名,例如 "can0"、"can1" |
motor_type |
str |
是 | 电机品牌,可选 "DM"、"EVO"、"LRO" |
motor_model |
int |
是 | 电机型号枚举值,各品牌对应关系见下表 |
master_id_offset |
int |
否 | 主站 ID 偏移,仅 DM 电机有效,默认 0 |
motor_zero_offset |
float |
否 | 机械零位偏移量,单位 rad,默认 0.0 |
Sources: src/pybind_module.cpp
各品牌电机型号对照表
创建实例时,motor_model 参数需传入对应型号的整型枚举值。下表列出了当前 SDK 支持的所有型号:
| 品牌 | 型号 | motor_model 值 |
支持接口 |
|---|---|---|---|
| DM(达妙) | DM4340P-48V | 0 |
CAN |
| DM(达妙) | DM10010L-48V | 1 |
CAN |
| EVO | EVO431040 | 0 |
CAN |
| EVO | EVO811825 | 1 |
CAN |
| EVO | EVO811832 | 2 |
CAN |
| LRO(LeadRobot) | LRO-5550 | 0 |
CAN-FD |
| LRO(LeadRobot) | LRO-6562 | 1 |
CAN-FD |
| LRO(LeadRobot) | LRO-8462 | 2 |
CAN-FD |
| LRO(LeadRobot) | LRO-10062 | 3 |
CAN-FD |
Sources: src/drivers/dm/dm_motor_driver.hpp, src/drivers/evo/evo_motor_driver.hpp, src/drivers/lro/lro_motor_driver.hpp
创建示例
以下代码分别展示了达妙 DM 电机与 LeadRobot 电机的创建方式:
# 达妙 DM4340P-48V,挂载在 can0 上,CAN 节点 ID 为 0x01
dm_motor = MotorDriver.create_motor(
motor_id=0x01,
interface_type="can",
interface="can0",
motor_type="DM",
motor_model=0
)
# LeadRobot LRO-5550,挂载在 can0 上,CAN 节点 ID 为 0x02
lro_motor = MotorDriver.create_motor(
motor_id=0x02,
interface_type="canfd",
interface="can0",
motor_type="LRO",
motor_model=0
)
Sources: src/motor_driver.cpp
初始化与使能
电机实例创建后处于未激活状态,必须先调用 init_motor() 完成底层协议握手、总线回调注册和电机使能,之后才能接收运动指令。对应的,在程序结束或需要紧急停止时,应调用 deinit_motor() 将电机失能并清理总线资源。如果仅需临时禁止电机响应指令(而非完全释放资源),可使用 lock_motor() 和 unlock_motor() 组合。
# 初始化并使能
dm_motor.init_motor()
# ... 进行控制 ...
# 失能并释放资源
dm_motor.deinit_motor()
init_motor() 的返回值类型为 int,正常初始化成功时通常返回 1,若返回 0 则表示初始化失败,建议检查 CAN 接口是否已正确启动、电机供电是否正常以及 ID 是否冲突。
Sources: include/motor_driver.hpp, src/pybind_module.cpp
控制模式与指令发送
Python SDK 支持三种控制模式,使用 set_motor_control_mode() 进行切换,参数为 MotorControlMode 枚举值。各模式适用的电机品牌和典型场景如下表所示:
| 控制模式 | 枚举值 | 适用场景 | 支持的电机品牌 |
|---|---|---|---|
| MIT 阻抗控制 | MotorControlMode.MIT |
力控、柔顺交互、足式机器人关节 | DM、EVO、LRO |
| 位置控制 | MotorControlMode.POS |
精确角度定位、机械臂关节 | DM、LRO |
| 速度控制 | MotorControlMode.SPD |
恒速旋转、轮式驱动 | DM、LRO |
Sources: include/motor_driver.hpp, src/pybind_module.cpp
MIT 阻抗控制
MIT 模式通过同时指定目标位置、目标速度、位置刚度、速度阻尼和前馈力矩,实现类似弹簧-阻尼系统的阻抗特性。该模式对足式机器人和需要与环境交互的机械臂尤为重要。
dm_motor.set_motor_control_mode(MotorControlMode.MIT)
dm_motor.motor_mit_cmd(
f_p=0.0, # 目标位置 (rad)
f_v=0.0, # 目标速度 (rad/s)
f_kp=10.0, # 位置刚度 / 比例增益
f_kd=1.0, # 速度阻尼 / 微分增益
f_t=0.0 # 前馈力矩 (Nm)
)
Sources: src/pybind_module.cpp
位置控制
位置控制模式下,电机将自动规划轨迹并运动到指定角度。motor_pos_cmd() 接受目标位置、目标速度和是否忽略限位三个参数。第三个参数 ignore_limit 默认为 False,建议初学者保持默认,以避免机械结构超限。
dm_motor.set_motor_control_mode(MotorControlMode.POS)
dm_motor.motor_pos_cmd(
pos=1.57, # 目标位置 90°,单位 rad
spd=3.14, # 运动速度约 180°/s,单位 rad/s
ignore_limit=False
)
Sources: src/pybind_module.cpp
速度控制
速度控制模式使电机以指定角速度持续旋转,适用于轮式底盘或需要恒速运行的执行机构。
dm_motor.set_motor_control_mode(MotorControlMode.SPD)
dm_motor.motor_spd_cmd(spd=3.14) # 约 180°/s
Sources: src/pybind_module.cpp
读取实时状态反馈
电机在运行过程中会周期性返回当前状态。Python SDK 提供了一组线程安全的 getter 方法,用于获取最近一次解析后的反馈数据。需要注意的是,在控制循环中,建议先调用 refresh_motor_status() 向电机发送状态查询指令,以确保获取到的数据尽可能新鲜。
# 主动请求电机上报最新状态
dm_motor.refresh_motor_status()
# 读取反馈
pos = dm_motor.get_motor_pos() # 当前位置 (rad)
spd = dm_motor.get_motor_spd() # 当前速度 (rad/s)
current = dm_motor.get_motor_current() # 相电流 (A)
temp = dm_motor.get_motor_temperature() # 电机温度 (°C)
# 诊断信息
motor_id = dm_motor.get_motor_id() # 当前电机 CAN ID
error_id = dm_motor.get_error_id() # 错误码,非零表示存在故障
mode = dm_motor.get_motor_control_mode() # 当前控制模式
Sources: include/motor_driver.hpp, src/pybind_module.cpp
零位设置与错误处理
若需要将当前机械位置设为新的逻辑零点,可调用 set_motor_zero()。该操作在部分电机(如 EVO 系列)中可能与 write_motor_flash() 联合使用才能永久保存。当电机触发过流、过压或过热保护后,get_error_id() 将返回非零值,此时可调用 clear_motor_error() 尝试清除错误标志并恢复待机状态。
# 设置当前位置为零点
dm_motor.set_motor_zero()
# 清除错误(前提是导致错误的物理条件已解除)
dm_motor.clear_motor_error()
Sources: include/motor_driver.hpp, src/pybind_module.cpp
完整示例脚本
以下是一个面向初学者的完整可运行示例,展示如何连接一台达妙 DM 电机,依次执行初始化、MIT 模式运动、位置模式运动,最后读取状态并安全关闭的全过程:
import time
from motors_py import MotorDriver, MotorControlMode
def main():
# 1. 创建电机实例
motor = MotorDriver.create_motor(
motor_id=0x01,
interface_type="can",
interface="can0",
motor_type="DM",
motor_model=0,
motor_zero_offset=0.0
)
# 2. 初始化并使能
ret = motor.init_motor()
if ret == 0:
print("电机初始化失败,请检查 CAN 接口和硬件连接")
return
try:
# 3. MIT 模式示例:回到零位并保持刚性
motor.set_motor_control_mode(MotorControlMode.MIT)
for _ in range(100):
motor.motor_mit_cmd(0.0, 0.0, 10.0, 1.0, 0.0)
motor.refresh_motor_status()
print(f"MIT pos={motor.get_motor_pos():.3f}, "
f"spd={motor.get_motor_spd():.3f}, "
f"err={motor.get_error_id()}")
time.sleep(0.01)
# 4. 位置模式示例:旋转到 1.57 rad
motor.set_motor_control_mode(MotorControlMode.POS)
motor.motor_pos_cmd(1.57, 3.14)
time.sleep(2.0) # 等待运动完成
# 5. 读取最终状态
motor.refresh_motor_status()
print(f"最终位置: {motor.get_motor_pos():.3f} rad")
print(f"最终温度: {motor.get_motor_temperature():.1f} °C")
finally:
# 6. 确保电机失能并释放资源
motor.deinit_motor()
print("电机已安全关闭")
if __name__ == "__main__":
main()
Sources: README_CN.md
常见问题排查
初学者在使用 Python SDK 时,最常遇到的问题集中在 CAN 接口、权限和参数配置三个方面。下表整理了典型现象与对应的排查方法:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
ImportError: No module named 'motors_py' |
Python 模块未安装或环境路径错误 | 确认已通过 colcon/catkin 编译安装;检查 PYTHONPATH 是否包含 install 目录 |
RuntimeError: Motor type not supported |
motor_type 参数拼写错误 |
仅支持 "DM"、"EVO"、"LRO",注意大小写 |
init_motor() 返回 0 |
CAN 接口未启动或电机未上电 | 执行 ip link show can0 检查接口状态;确认电机供电正常 |
| 发送指令后电机无响应 | 控制模式未切换或电机处于锁定状态 | 确认已调用 set_motor_control_mode();检查是否误调用了 lock_motor() |
get_motor_pos() 始终为 0.0 |
未调用 refresh_motor_status() |
在读取反馈前主动调用 refresh_motor_status() 触发状态查询 |
| 提示权限不足 | 普通用户无 SocketCAN 操作权限 | 使用 sudo 运行脚本,或将当前用户加入 can 用户组 |
Sources: src/motor_driver.cpp, include/motor_driver.hpp
下一步
完成本页学习后,您已经掌握了 Python SDK 的基础用法。若希望深入理解底层实现细节,建议继续阅读以下文档:
- 了解 C++ 侧的抽象接口与工厂模式设计,请参阅 MotorDriver抽象基类与接口设计 和 工厂模式与多品牌电机实例化。
- 若需掌握 MIT 阻抗控制背后的数学原理与参数调参技巧,请参阅 MIT阻抗控制原理与实现。
- 若对
motors_py模块的 pybind11 绑定机制感兴趣,请参阅 Python pybind11绑定机制。 - 若您的项目主要基于 C++ 开发,可转阅 C++ SDK快速上手。