🤖 roboto_origin_03 Wiki
首页 / 电机子模块 / Python SDK快速上手

本页面向初次接触 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 的基础用法。若希望深入理解底层实现细节,建议继续阅读以下文档: