Skip to main content

教程 07:完整接口总指南

模块概览

导入主要组件

from motorbridge import (
    # ===== 核心类 =====
    Controller,    # 控制器 - 管理通信和电机
    Motor,         # 电机 - 控制单个电机

    # ===== 枚举和数据类 =====
    Mode,          # 模式枚举 - 控制模式
    MotorState,    # 状态数据类 - 电机状态

    # ===== 寄存器工具 =====
    RegisterSpec,  # 寄存器规格
    DAMIAO_RW_REGISTERS,       # 达妙可读写寄存器字典
    DAMIAO_HIGH_IMPACT_RIDS,   # 高影响寄存器 ID 列表
    DAMIAO_PROTECTION_RIDS,    # 保护寄存器 ID 列表
    get_damiao_register_spec,  # 获取寄存器规格函数

    # ===== 寄存器 ID 常量 =====
    RID_CTRL_MODE,  # 10 - 控制模式
    RID_MST_ID,     # 7  - 反馈 ID
    RID_ESC_ID,     # 8  - 电机 ID
    RID_TIMEOUT,    # 9  - 通信超时
    RID_PMAX,       # 21 - 位置映射范围
    RID_VMAX,       # 22 - 速度映射范围
    RID_TMAX,       # 23 - 力矩映射范围
    RID_KP_ASR,     # 25 - 速度环 Kp
    RID_KI_ASR,     # 26 - 速度环 Ki
    RID_KP_APR,     # 27 - 位置环 Kp
    RID_KI_APR,     # 28 - 位置环 Ki

    # ===== 模式常量 =====
    MODE_MIT,       # 1 - MIT 模式
    MODE_POS_VEL,   # 2 - 位置-速度模式
    MODE_VEL,       # 3 - 速度模式
    MODE_FORCE_POS, # 4 - 力位置模式
)

导入错误类

from motorbridge.errors import (
    MotorBridgeError,  # 基础错误类
    AbiLoadError,      # ABI 加载错误
    CallError,         # API 调用错误
)

Controller 控制器类

控制器是整个 SDK 的入口点,负责管理 CAN 通信和电机注册。

构造函数

Controller(channel="can0")

标准 SocketCAN 传输,适用于大多数场景。
from motorbridge import Controller

# 基本用法
ctrl = Controller("can0")

# 使用 with 语句(推荐)
with Controller("can0") as ctrl:
    motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")
    # ... 控制代码
参数详解:
参数类型默认值说明
channelstr"can0"CAN 接口名称
可能抛出的异常:
异常说明
AbiLoadError无法加载底层库
CallError无法打开 CAN 接口

Controller.from_socketcanfd(channel="can0")

CAN-FD 传输,Hexfellow 电机必须使用此方法
from motorbridge import Controller

with Controller.from_socketcanfd("can0") as ctrl:
    # Hexfellow 必须用 CAN-FD
    motor = ctrl.add_hexfellow_motor(0x01, 0x00, "hexfellow")
参数详解:
参数类型默认值说明
channelstr"can0"CAN-FD 接口名称

Controller.from_dm_serial(serial_port="/dev/ttyACM0", baud=921600)

达妙串口桥传输,仅适用于达妙电机。
from motorbridge import Controller

with Controller.from_dm_serial("/dev/ttyACM0", baud=921600) as ctrl:
    motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")
参数详解:
参数类型默认值说明
serial_portstr"/dev/ttyACM0"串口设备路径
baudint921600波特率(达妙固定 921600)

电机注册方法

add_damiao_motor(motor_id, feedback_id, model)

注册达妙电机。
motor = ctrl.add_damiao_motor(
    motor_id=0x01,      # 命令 ID
    feedback_id=0x11,   # 反馈 ID
    model="4340P"       # 型号
)
参数详解:
参数类型说明范围
motor_idint命令帧 CAN ID0x01 - 0x20
feedback_idint反馈帧 CAN ID通常 motor_id + 0x10
modelstr电机型号见型号表
支持的达妙型号:
型号字符串电机型号
"4310"DM4310
"4340P"DM4340P
"6001"DM6001
"6006"DM6006
"8006"DM8006
"8009"DM8009

add_robstride_motor(motor_id, feedback_id, model)

注册 RobStride 电机。
motor = ctrl.add_robstride_motor(
    motor_id=127,       # 设备 ID
    feedback_id=0xFE,   # 响应者 ID
    model="rs-00"       # 型号
)
参数详解:
参数类型说明范围
motor_idint设备 ID1 - 127
feedback_idint响应者 ID0xFE 或 0xFF
modelstr电机型号”rs-00”, “rs-01” 等

add_myactuator_motor(motor_id, feedback_id, model)

注册 MyActuator 电机。
motor = ctrl.add_myactuator_motor(
    motor_id=1,         # 电机 ID
    feedback_id=0x241,  # 反馈 ID = 0x240 + motor_id
    model="AK60-6"      # 型号
)

add_hightorque_motor(motor_id, feedback_id, model)

注册 HighTorque 电机。
motor = ctrl.add_hightorque_motor(
    motor_id=1,         # 电机 ID
    feedback_id=0x01,   # 固定为 0x01
    model="HT01"        # 型号
)

add_hexfellow_motor(motor_id, feedback_id, model)

注册 Hexfellow 电机,必须使用 CAN-FD
# 必须用 CAN-FD
with Controller.from_socketcanfd("can0") as ctrl:
    motor = ctrl.add_hexfellow_motor(
        motor_id=0x01,
        feedback_id=0x00,  # 固定为 0x00
        model="hexfellow"
    )

全局操作方法

enable_all()

使能该控制器下的所有电机。
ctrl.enable_all()
# 所有电机现在可以响应命令

disable_all()

禁用该控制器下的所有电机。
ctrl.disable_all()
# 所有电机输出关闭,转子自由

poll_feedback_once()

手动轮询一次反馈(v0.1.6 及更早需要)。
# v0.1.6 及更早
motor.request_feedback()
ctrl.poll_feedback_once()  # 必须调用
state = motor.get_state()

# v0.1.7+ 通常不需要手动调用

生命周期方法

shutdown()

优雅关闭所有电机。
ctrl.shutdown()  # 禁用所有电机并清理

close_bus()

关闭 CAN 总线连接。
ctrl.close_bus()  # 释放 CAN 接口

close()

释放所有资源。
ctrl.close()  # 完全清理

Motor 电机类

电机类提供单个电机的所有控制方法。

生命周期方法

enable()

使能单个电机。
motor.enable()  # 电机开始输出扭矩

disable()

禁用单个电机。
motor.disable()  # 电机输出关闭

clear_error()

清除电机错误状态。
# 检测到错误后清除
if state.status_code != 0:
    motor.clear_error()

set_zero_position()

将当前位置设置为零点。
motor.set_zero_position()  # 当前位置变成 0

close()

释放电机句柄。
motor.close()  # 释放资源

模式控制方法

ensure_mode(mode, timeout_ms=1000)

确保电机处于指定模式,如果不是则切换。
from motorbridge import Mode

# 切换到 MIT 模式
motor.ensure_mode(Mode.MIT, timeout_ms=1000)
参数详解:
参数类型默认值说明
modeMode必填目标控制模式
timeout_msint1000超时时间(毫秒)

控制命令方法

send_mit(pos, vel, kp, kd, tau)

MIT 模式控制命令,最灵活的控制方式。
motor.send_mit(
    pos=1.0,    # 目标位置(rad)
    vel=0.0,    # 目标速度(rad/s)
    kp=30.0,    # 位置刚度(Nm/rad)
    kd=1.0,     # 速度阻尼(Nm·s/rad)
    tau=0.0     # 前馈力矩(Nm)
)
参数详解:
参数类型单位说明典型范围
posfloatrad目标位置-12.566 ~ +12.566
velfloatrad/s目标速度-30.0 ~ +30.0
kpfloatNm/rad位置刚度0.1 ~ 100.0
kdfloatNm·s/rad速度阻尼0.01 ~ 10.0
taufloatNm前馈力矩-10.0 ~ +10.0

send_pos_vel(pos, vlim)

位置-速度模式控制命令。
motor.send_pos_vel(
    pos=2.0,    # 目标位置(rad)
    vlim=1.5    # 最大速度限制(rad/s)
)
参数详解:
参数类型单位说明
posfloatrad目标位置
vlimfloatrad/s最大速度限制

send_vel(vel)

速度模式控制命令。
motor.send_vel(vel=2.0)  # 目标速度(rad/s)
参数详解:
参数类型单位说明
velfloatrad/s目标速度

send_force_pos(pos, vlim, ratio)

力位置模式控制命令,适合夹爪等需要力控制的应用。
motor.send_force_pos(
    pos=0.5,    # 目标位置(rad)
    vlim=1.0,   # 最大速度(rad/s)
    ratio=0.3   # 力比例(0.0 - 1.0)
)
参数详解:
参数类型单位说明
posfloatrad目标位置
vlimfloatrad/s最大速度限制
ratiofloat-力比例(0.0 = 无力,1.0 = 全力)

反馈方法

request_feedback()

请求电机发送反馈帧。
motor.request_feedback()  # 发送反馈请求

get_state()

获取缓存的状态,返回 MotorStateNone
state = motor.get_state()

if state:
    print(f"位置: {state.pos}")
else:
    print("未收到反馈")

寄存器访问方法

write_register_u32(rid, value)

写入 32 位无符号整数寄存器。
motor.write_register_u32(rid=10, value=2)  # 写入控制模式
参数详解:
参数类型说明
ridint寄存器 ID
valueint要写入的值(0 ~ 4294967295)

get_register_u32(rid, timeout_ms=1000)

读取 32 位无符号整数寄存器。
value = motor.get_register_u32(rid=8, timeout_ms=1000)
print(f"电机 ID: {value}")
参数详解:
参数类型默认值说明
ridint必填寄存器 ID
timeout_msint1000超时时间(毫秒)
返回值: int(0 ~ 4294967295)

write_register_f32(rid, value)

写入 32 位浮点数寄存器。
motor.write_register_f32(rid=21, value=12.566)  # 写入 PMAX
参数详解:
参数类型说明
ridint寄存器 ID
valuefloat要写入的值

get_register_f32(rid, timeout_ms=1000)

读取 32 位浮点数寄存器。
pmax = motor.get_register_f32(rid=21, timeout_ms=1000)
print(f"PMAX: {pmax}")
参数详解:
参数类型默认值说明
ridint必填寄存器 ID
timeout_msint1000超时时间(毫秒)
返回值: float

store_parameters()

将当前参数保存到闪存(永久保存)。
motor.store_parameters()
print("参数已保存到闪存")
频繁保存会磨损闪存。只在需要永久保存时调用。

set_can_timeout_ms(timeout_ms)

设置 CAN 通信超时时间。
motor.set_can_timeout_ms(5000)  # 5 秒超时

RobStride 专用方法

robstride_ping()

Ping RobStride 电机,获取设备信息。
device_id, responder_id = motor.robstride_ping()
print(f"设备 ID: {device_id}, 响应者 ID: {responder_id}")
返回值: (device_id: int, responder_id: int)

robstride_set_device_id(new_device_id)

设置 RobStride 电机的设备 ID。
motor.robstride_set_device_id(42)

RobStride 参数写入方法

# 写入不同类型的参数
motor.robstride_write_param_i8(param_id, value)    # 有符号 8 位
motor.robstride_write_param_u8(param_id, value)    # 无符号 8 位
motor.robstride_write_param_u16(param_id, value)   # 无符号 16 位
motor.robstride_write_param_u32(param_id, value)   # 无符号 32 位
motor.robstride_write_param_f32(param_id, value)   # 32 位浮点
参数详解:
参数类型说明
param_idint参数 ID(如 0x7019)
value根据类型要写入的值

RobStride 参数读取方法

# 读取不同类型的参数
v_i8  = motor.robstride_get_param_i8(param_id, timeout_ms=1000)
v_u8  = motor.robstride_get_param_u8(param_id, timeout_ms=1000)
v_u16 = motor.robstride_get_param_u16(param_id, timeout_ms=1000)
v_u32 = motor.robstride_get_param_u32(param_id, timeout_ms=1000)
v_f32 = motor.robstride_get_param_f32(param_id, timeout_ms=1000)

Mode 模式枚举

from motorbridge import Mode

class Mode(IntEnum):
    MIT = 1        # MIT 模式 - 全阻抗控制,最灵活
    POS_VEL = 2    # 位置-速度模式 - 简单位置控制
    VEL = 3        # 速度模式 - 纯速度控制
    FORCE_POS = 4  # 力位置模式 - 柔顺位置控制

使用示例

from motorbridge import Mode

# 切换模式
motor.ensure_mode(Mode.MIT, 1000)

# 检查模式值
if Mode.MIT == 1:
    print("MIT 模式的值是 1")

# 遍历所有模式
for mode in Mode:
    print(f"{mode.name} = {mode.value}")

模式常量

除了 Mode 枚举,还可以使用模块级常量:
from motorbridge import MODE_MIT, MODE_POS_VEL, MODE_VEL, MODE_FORCE_POS

# 这些值与 Mode 枚举相同
assert MODE_MIT == Mode.MIT == 1
assert MODE_POS_VEL == Mode.POS_VEL == 2
assert MODE_VEL == Mode.VEL == 3
assert MODE_FORCE_POS == Mode.FORCE_POS == 4

MotorState 状态数据类

from motorbridge import MotorState

@dataclass(frozen=True)
class MotorState:
    can_id: int          # 电机 CAN ID
    arbitration_id: int  # CAN 仲裁 ID
    status_code: int     # 状态/错误码
    pos: float           # 位置(rad)
    vel: float           # 速度(rad/s)
    torq: float          # 力矩(Nm)
    t_mos: float         # MOSFET 温度(°C)
    t_rotor: float       # 转子温度(°C)

字段详解

字段类型单位说明范围
can_idint-电机 CAN ID0x01 - 0x7F
arbitration_idint-CAN 仲裁 ID-
status_codeint-状态码(0=正常)0-255
posfloatrad电机位置-12.566 ~ +12.566
velfloatrad/s电机速度-30.0 ~ +30.0
torqfloatNm电机力矩-10.0 ~ +10.0
t_mosfloat°CMOSFET 温度20.0 ~ 100.0
t_rotorfloat°C转子温度20.0 ~ 100.0

使用示例

motor.request_feedback()
state = motor.get_state()

if state:
    # 访问字段
    print(f"位置: {state.pos:.3f} rad")
    print(f"速度: {state.vel:.3f} rad/s")
    print(f"力矩: {state.torq:.3f} Nm")

    # 检查状态码
    if state.status_code != 0:
        print(f"错误码: 0x{state.status_code:02X}")

    # 检查温度
    if state.t_mos > 70:
        print("温度过高!")

状态码含义

代码含义处理方法
0正常无需处理
1过压检查电源电压
2欠压检查电源电压
3过流减小负载
4MOSFET 过温停止运行,等待冷却
5转子过温停止运行,等待冷却
6通信超时检查 CAN 连接

Error 错误类

from motorbridge.errors import MotorBridgeError, AbiLoadError, CallError

类层次结构

MotorBridgeError (基类)
├── AbiLoadError    # ABI 库加载失败
└── CallError       # API 调用失败

MotorBridgeError

基础异常类,所有 motorbridge 异常的基类。
from motorbridge.errors import MotorBridgeError

try:
    # ... motorbridge 操作
    pass
except MotorBridgeError as e:
    print(f"MotorBridge 错误: {e}")

AbiLoadError

底层库加载失败时抛出。
from motorbridge.errors import AbiLoadError

try:
    from motorbridge import Controller
except AbiLoadError as e:
    print(f"无法加载底层库: {e}")
    print("请检查 libmotor_abi 是否正确安装")

CallError

API 调用返回非零状态时抛出。
from motorbridge.errors import CallError

try:
    motor.send_mit(1.0, 0.0, 30.0, 1.0, 0.0)
except CallError as e:
    print(f"API 调用失败: {e}")
    # 可能原因:电机未使能、通信超时等

错误处理最佳实践

from motorbridge import Controller, Mode
from motorbridge.errors import MotorBridgeError, CallError

try:
    with Controller("can0") as ctrl:
        motor = ctrl.add_damiao_motor(0x01, 0x11, "4340P")
        ctrl.enable_all()
        motor.ensure_mode(Mode.MIT, 1000)

        for i in range(100):
            motor.send_mit(0.5, 0.0, 30.0, 1.0, 0.0)

except CallError as e:
    print(f"API 调用失败: {e}")
    # 处理 API 错误

except MotorBridgeError as e:
    print(f"MotorBridge 错误: {e}")
    # 处理一般错误

except KeyboardInterrupt:
    print("\n用户中断")
    # 清理

finally:
    # 确保资源清理
    pass

RegisterSpec 寄存器规格类

from motorbridge import RegisterSpec

@dataclass(frozen=True)
class RegisterSpec:
    rid: int          # 寄存器 ID
    variable: str     # 变量名
    description: str  # 人类可读描述
    data_type: str    # 数据类型:"f32" 或 "u32"
    access: str       # 访问权限:"RW", "RO" 等
    range_str: str    # 范围描述

使用示例

from motorbridge import DAMIAO_RW_REGISTERS, get_damiao_register_spec

# 方法1:从字典获取
spec = DAMIAO_RW_REGISTERS[21]  # PMAX
print(f"RID {spec.rid}: {spec.variable}")
print(f"  描述: {spec.description}")
print(f"  类型: {spec.data_type}")
print(f"  访问: {spec.access}")
print(f"  范围: {spec.range_str}")

# 方法2:使用辅助函数
spec = get_damiao_register_spec(21)
if spec:
    print(f"找到: {spec.variable}")
else:
    print("寄存器不存在")

寄存器常量

寄存器 ID 常量

from motorbridge import (
    # ID 相关
    RID_MST_ID,     # 7  - 反馈 ID(MST_ID)
    RID_ESC_ID,     # 8  - 电机 ID(ESC_ID)

    # 通信相关
    RID_TIMEOUT,    # 9  - 通信超时(毫秒)

    # 模式相关
    RID_CTRL_MODE,  # 10 - 控制模式

    # 限制相关
    RID_PMAX,       # 21 - 位置映射范围
    RID_VMAX,       # 22 - 速度映射范围
    RID_TMAX,       # 23 - 力矩映射范围

    # PID 相关
    RID_KP_ASR,     # 25 - 速度环 Kp
    RID_KI_ASR,     # 26 - 速度环 Ki
    RID_KP_APR,     # 27 - 位置环 Kp
    RID_KI_APR,     # 28 - 位置环 Ki
)

寄存器表

RID常量名变量名类型说明范围
0-UV_Valuef32欠压保护值(10.0, 3.4E38]
2-OT_Valuef32过温保护值[80.0, 200)
3-OC_Valuef32过流保护值(0.0, 1.0)
7RID_MST_IDMST_IDu32反馈 ID[0, 0x7FF]
8RID_ESC_IDESC_IDu32电机 ID[0, 0x7FF]
9RID_TIMEOUTTIMEOUTu32通信超时(ms)[0, 2^32-1]
10RID_CTRL_MODECTRL_MODEu32控制模式[1, 4]
21RID_PMAXPMAXf32位置映射范围(0.0, 3.4E38]
22RID_VMAXVMAXf32速度映射范围(0.0, 3.4E38]
23RID_TMAXTMAXf32力矩映射范围(0.0, 3.4E38]
25RID_KP_ASRKP_ASRf32速度环 Kp[0.0, 3.4E38]
26RID_KI_ASRKI_ASRf32速度环 Ki[0.0, 3.4E38]
27RID_KP_APRKP_APRf32位置环 Kp[0.0, 3.4E38]
28RID_KI_APRKI_APRf32位置环 Ki[0.0, 3.4E38]

完整模板

这是一个包含所有功能的完整模板:
#!/usr/bin/env python3
"""motorbridge 完整模板"""

import time
from motorbridge import (
    Controller,
    Mode,
    MotorState,
    RID_PMAX,
    RID_VMAX,
    RID_TMAX,
    DAMIAO_RW_REGISTERS,
    get_damiao_register_spec,
)
from motorbridge.errors import CallError, MotorBridgeError

# ============ 配置区域 ============
CHANNEL = "can0"
MOTOR_ID = 0x01
FEEDBACK_ID = 0x11
MODEL = "4340P"
MODE = Mode.MIT
TARGET_POS = 1.0
CONTROL_RATE = 50  # Hz
DURATION = 2.0     # 秒
# =================================

def main():
    try:
        with Controller(CHANNEL) as ctrl:
            # ===== 注册电机 =====
            motor = ctrl.add_damiao_motor(MOTOR_ID, FEEDBACK_ID, MODEL)
            print(f"电机已注册: ID=0x{MOTOR_ID:02X}")

            # ===== 使能 =====
            ctrl.enable_all()
            print("电机已使能")

            # ===== 设置模式 =====
            motor.ensure_mode(MODE, timeout_ms=1000)
            print(f"模式已设置: {MODE.name}")

            # ===== 读取配置 =====
            pmax = motor.get_register_f32(RID_PMAX, 1000)
            vmax = motor.get_register_f32(RID_VMAX, 1000)
            tmax = motor.get_register_f32(RID_TMAX, 1000)
            print(f"限制: PMAX={pmax:.3f}, VMAX={vmax:.3f}, TMAX={tmax:.3f}")

            # ===== 控制循环 =====
            dt = 1.0 / CONTROL_RATE
            iterations = int(DURATION / dt)

            for i in range(iterations):
                t0 = time.time()

                # 发送命令
                motor.send_mit(TARGET_POS, 0.0, 30.0, 1.0, 0.0)

                # 读取状态
                motor.request_feedback()
                state = motor.get_state()

                if state:
                    print(
                        f"#{i:03d} "
                        f"pos={state.pos:+.3f} "
                        f"vel={state.vel:+.3f} "
                        f"torq={state.torq:+.2f} "
                        f"t_mos={state.t_mos:.1f}°C"
                    )
                else:
                    print(f"#{i:03d} 未收到反馈")

                # 保持固定频率
                elapsed = time.time() - t0
                if elapsed < dt:
                    time.sleep(dt - elapsed)

            # ===== 清理 =====
            motor.disable()
            print("电机已禁用")

    except CallError as e:
        print(f"API 调用失败: {e}")
    except MotorBridgeError as e:
        print(f"MotorBridge 错误: {e}")
    except KeyboardInterrupt:
        print("\n用户中断")

if __name__ == "__main__":
    main()

厂商规则速查

规则说明
同厂商 → 同控制器同一厂商的电机共享一个 Controller 实例
不同厂商 → 分开控制器每个厂商需要独立的 Controller
Hexfellow 必须用 CAN-FD使用 from_socketcanfd()
DM 串口仅支持达妙from_dm_serial() 只能用于达妙电机

版本兼容性

版本说明
v0.1.6 及更早需要手动调用 poll_feedback_once()
v0.1.7+后台轮询默认启用

参见