Skip to main content

教程 02:使能与状态读取

电机状态机

在理解使能之前,先了解电机的状态:
┌─────────────┐     enable()      ┌─────────────┐
│   禁用状态   │ ───────────────► │   使能状态   │
│  (无输出)    │                  │  (有扭矩)    │
│  转子自由    │                  │  锁定位置    │
└─────────────┘ ◄─────────────── └─────────────┘
                   disable()
禁用状态:
  • 电机绕组不通电
  • 转子可以用手自由转动
  • 发送命令无效
使能状态:
  • 电机绕组通电
  • 产生扭矩,会锁住位置
  • 可以响应控制命令

步骤一:创建控制器

首先创建一个控制器来管理 CAN 通信:
from motorbridge import Controller

# 方式1:标准 CAN
ctrl = Controller("can0")

# 方式2:CAN-FD(Hexfellow 必须用这个)
# ctrl = Controller.from_socketcanfd("can0")

# 方式3:达妙串口桥
# ctrl = Controller.from_dm_serial("/dev/ttyACM0", 921600)
Controller 参数详解:
参数类型默认值说明
channelstr"can0"CAN 接口名称
返回值: Controller 对象 可能抛出的异常:
  • CallError - CAN 接口无法打开

步骤二:添加电机

告诉控制器你要控制哪个电机:
# 达妙电机
motor = ctrl.add_damiao_motor(
    motor_id=0x01,      # 必填:电机的命令 ID
    feedback_id=0x11,   # 必填:电机的反馈 ID
    model="4340P"       # 必填:电机型号
)
add_damiao_motor 参数详解:
参数类型说明示例
motor_idint命令帧的 CAN ID0x01 - 0x20
feedback_idint反馈帧的 CAN ID通常是 motor_id + 0x10
modelstr电机型号字符串"4310", "4340P", "6001"

步骤三:使能电机

使能就是给电机”通电”,让它开始工作:
# 方式1:使能所有电机(推荐)
ctrl.enable_all()

# 方式2:只使能单个电机
motor.enable()
enable_all() vs enable() 的区别:
方法作用使用场景
ctrl.enable_all()使能该控制器下所有电机多电机系统,需要同步启动
motor.enable()只使能这一个电机单电机测试,或需要单独控制

步骤四:读取状态

获取电机的实时数据:
# 请求电机发送反馈帧
motor.request_feedback()

# 读取缓存的状态(可能为 None)
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")
else:
    print("未收到反馈")
MotorState 所有字段详解:
字段类型单位说明范围
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
弧度单位说明:
  • 1 圈 = 2π 弧度 ≈ 6.28 弧度
  • 90° = π/2 弧度 ≈ 1.57 弧度
  • 180° = π 弧度 ≈ 3.14 弧度

完整示例

import time
from motorbridge import Controller

# 配置
MOTOR_ID = 0x01
FEEDBACK_ID = 0x11
MODEL = "4340P"

with Controller("can0") as ctrl:
    # 添加电机
    motor = ctrl.add_damiao_motor(MOTOR_ID, FEEDBACK_ID, MODEL)
    print(f"已添加电机 ID=0x{MOTOR_ID:02X}")
    
    # 使能
    ctrl.enable_all()
    print("电机已使能")
    
    # 等待稳定
    time.sleep(0.5)
    
    # 读取状态
    motor.request_feedback()
    state = motor.get_state()
    
    if state:
        print("\n===== 电机状态 =====")
        print(f"位置: {state.pos:+.3f} rad ({state.pos * 57.3:+.1f}°)")
        print(f"速度: {state.vel:+.3f} rad/s")
        print(f"力矩: {state.torq:+.3f} Nm")
        print(f"MOS温度: {state.t_mos:.1f}°C")
        print(f"转子温度: {state.t_rotor:.1f}°C")
        print("====================")
    else:
        print("未收到反馈")
    
    # 自动清理(with 语句)

为什么 get_state() 返回 None?

这是初学者最常遇到的问题:

原因 1:没有调用 request_feedback()

# 错误:没有请求反馈
state = motor.get_state()  # 返回 None

# 正确:先请求,再读取
motor.request_feedback()
state = motor.get_state()  # 返回 MotorState

原因 2:反馈还没到达

CAN 通信有延迟,请求后需要等待:
motor.request_feedback()
time.sleep(0.01)  # 等待 10ms
state = motor.get_state()

原因 3:电机 ID 错误

motorbridge-cli scan 确认 ID 是否正确。

重试模式(推荐)

为了可靠读取状态,使用重试模式:
import time

def get_state_reliable(motor, max_retries=10):
    """可靠地读取电机状态,带重试。"""
    for i in range(max_retries):
        motor.request_feedback()
        time.sleep(0.05)
        state = motor.get_state()
        if state is not None:
            return state
    return None

# 使用
state = get_state_reliable(motor)
if state:
    print(f"位置: {state.pos:.3f}")
else:
    print("读取失败")

状态码含义

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

温度监控

TEMP_WARNING = 70.0
TEMP_CRITICAL = 85.0

def check_temperature(state):
    if state is None:
        return True
    
    if state.t_mos > TEMP_CRITICAL:
        print(f"危险!MOSFET温度: {state.t_mos:.1f}°C")
        return False
    
    if state.t_rotor > TEMP_CRITICAL:
        print(f"危险!转子温度: {state.t_rotor:.1f}°C")
        return False
    
    return True

禁用电机

用完后禁用电机:
# 禁用单个电机
motor.disable()

# 禁用所有电机
ctrl.disable_all()

poll_feedback_once() 说明

版本差异:
  • v0.1.6 及以前:需要手动调用 ctrl.poll_feedback_once()
  • v0.1.7+:后台自动处理,通常不需要手动调用
# v0.1.6 及以前
motor.request_feedback()
ctrl.poll_feedback_once()  # 必须调用
state = motor.get_state()

# v0.1.7+
motor.request_feedback()
# 可省略 poll_feedback_once()
state = motor.get_state()

下一步