🤖 roboto_origin_03 Wiki
首页 / 推理子模块 / 硬件准备与电机初始化

本页面向初次接触本系统的开发者,讲解如何完成机器人底层硬件的连接、配置以及电机的安全初始化。理解这一流程是后续进行策略推理和动作执行的基础。阅读完本页后,你应当能够独立完成硬件接线、理解 robot.yaml 的每一项配置含义,并掌握通过手柄按键或 ROS 2 服务启停电机的正确方法。

硬件架构概览

在启动任何软件之前,需要先明确机器人底层的硬件拓扑。本系统采用 多路 CAN 总线 + 串口 IMU 的架构:22 台电机按数量均衡分配到 4 条 CAN 总线(can0 ~ can3),IMU 则通过串口与上位机通信。以下 Mermaid 图展示了这一拓扑关系,帮助你建立对硬件布局的整体认知。

graph TD
    A[上位机 / Compute Unit] -->|CAN| B[can0: 6台电机]
    A -->|CAN| C[can1: 7台电机]
    A -->|CAN| D[can2: 5台电机]
    A -->|CAN| E[can3: 5台电机]
    A -->|串口 921600bps| F[IMU /dev/ttyUSB0]
    
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333
    style C fill:#bbf,stroke:#333
    style D fill:#bbf,stroke:#333
    style E fill:#bbf,stroke:#333
    style F fill:#bfb,stroke:#333

从软件角度看,RobotInterface 是硬件抽象的核心枢纽。它在构造阶段读取 config/robot.yaml,随后分别为电机和 IMU 创建设备驱动实例。电机驱动采用工厂模式创建,统一封装了不同通信协议(CAN / CANFD)和电机型号的差异。所有电机通过线程池并发操作,以降低多总线场景下的指令延迟。

Sources: robot_interface.hpp, robot_interface.cpp

配置文件详解:robot.yaml

config/robot.yaml 是硬件层的唯一配置文件,包含三大顶层节点:imumotorsrobot。初学者最容易出错的地方在于电机 ID 与总线数量的对应关系、以及 motor_sign 的方向校准。下表逐项说明每个字段的含义与典型配置值。

顶层节点 字段 含义 示例值
imu imu_id IMU 设备逻辑 ID 8
imu imu_interface_type 接口类型,当前为串口 "serial"
imu imu_interface 串口设备路径 "/dev/ttyUSB0"
imu imu_type IMU 型号 "HIPNUC"
imu baudrate 串口波特率 921600
motors motor_id 所有电机的全局 ID 列表(共 23 个) [1..23]
motors motor_interface_type 总线协议类型:cancanfd "can"
motors motor_interface 各总线对应的 Linux 网络接口名 ["can0","can1","can2","can3"]
motors motor_num 每条总线上挂载的电机数量,顺序与 motor_interface 对应 [6,7,5,5]
motors motor_type 每条总线上的电机品牌/系列 ["DM","DM","DM","DM"]
motors motor_model 每台电机的具体型号编码(0/1) 长度与 motor_id 相同
motors master_id_offset 主站 ID 偏移量 16
motors motor_zero_offset 每台电机的机械零偏(rad) 多数为 0.0
robot type 机器人构型类型,决定闭环解耦算法 "atom01"
robot kp 各关节位置环比例增益 长度与电机数相同
robot kd 各关节位置环微分增益 长度与电机数相同
robot motor_sign 电机旋转方向符号(1 或 -1) 长度与电机数相同
robot close_chain_motor_id 踝关节闭环电机 ID(atom01 为 5,6,11,12) [5,6,11,12]
robot urdf2motor URDF 关节索引到电机索引的映射 [0..22]
robot extrinsic_R IMU 到机体坐标系的旋转矩阵(行主序 3×3) 单位矩阵

需要特别注意的是 motor_num 数组必须与 motor_interface 数组一一对应,且其总和必须等于 motor_id 的长度。若数量不匹配,setup_motors() 在遍历创建驱动实例时会发生索引越界或遗漏电机。此外,motor_sign 用于校准电机物理安装方向与 URDF 正方向的差异,初始化前务必通过手动旋转关节并观察反馈值符号来确认配置正确。

Sources: robot.yaml, robot_interface.cpp

电机初始化流程

电机初始化并非单步操作,而是由 构造期准备 → 显式初始化 → 关节回零 三个阶段组成的完整流程。理解每个阶段的作用有助于在出现问题时快速定位。

flowchart TD
    A[启动 inference_node] --> B[构造 RobotInterface]
    B --> C[解析 robot.yaml]
    C --> D[setup_motors: 创建 23 个 MotorDriver 实例]
    C --> E[setup_imu: 创建 IMUDriver 实例]
    D --> F[等待用户触发 init_motors]
    F -->|手柄 X 键 / ROS 服务| G[init_motors 并行下发]
    G --> H[各电机进入使能状态]
    H --> I[is_init_ 设为 true]
    I -->|手柄 A 键 / reset_joints 服务| J[reset_joints 关节回零]
    J --> K[先以 kp/2.5 缓控]
    K --> L[等待 1 秒]
    L --> M[再以全 kp 锁定到 default_angle]

在第一阶段,RobotInterface 的构造函数会读取 YAML 并完成所有驱动对象的实例化,但此时电机尚未使能。第二阶段通过调用 init_motors()deinit_motors() 来控制电机的上下电状态。这两个函数内部都使用 exec_motors_parallel(),将指令按总线分组后通过线程池并发下发,确保 4 路 CAN 总线同时通信,减少总线间的串行等待。第三阶段 reset_joints() 会将所有关节缓慢驱动到 joint_default_angle 指定的默认姿态,这一步骤必须在电机已初始化后执行,且执行期间推理线程应处于暂停状态。

Sources: robot_interface.cpp, inference_node.hpp, ros_interface.cpp

RobotInterface 核心职责与数据流

RobotInterface 作为硬件抽象层,向上为 InferenceNode 提供统一的关节状态读取与动作下发接口,向下管理具体的电机与 IMU 驱动。其内部维护了多组同步状态向量:joint_q_(位置)、joint_vel_(速度)、joint_tau_(力矩),并通过 joint_mutex_ 保证并发安全。

apply_action() 中,系统会先并行读取所有电机的当前状态,然后针对 atom01 构型执行 闭环踝关节解耦。具体来说,电机 ID 5/6 和 11/12 构成左右踝关节的闭环四连杆机构,实际关节空间的位置、速度、力矩需要通过 DecoupleAtom01 的正向运动学映射从电机空间转换而来;反之,下发的目标力矩也需要通过逆向映射折算回电机空间。如果你的机器人平台不涉及闭环 ankle 机构,则 type 字段可以留空,解耦模块将不会被实例化。

动作下发时,系统会根据 motor_interface_type_ 区分单电机 MIT 指令模式和 CANFD 广播模式。对于普通 CAN,每台电机单独调用 motor_mit_cmd;对于 CANFD,则按总线将最多 8 台电机的目标值打包为一次广播指令,进一步提升实时性。

Sources: robot_interface.hpp, robot_interface.cpp

实操:如何初始化与复位电机

系统为电机控制提供了手柄快捷键和 ROS 2 服务两种交互方式。下表列出了常用的控制入口及其安全约束。

操作 手柄按键 ROS 2 服务 前提条件 说明
初始化电机 X /init_motors 电机未初始化 使能所有电机,置 is_init_ = true
去初始化电机 X(再次按下) /deinit_motors 电机已初始化 断开所有电机使能
关节回零 A /reset_joints 电机已初始化,推理未运行 两步缓控到默认姿态
清除错误 /clear_errors RobotInterface 已创建 清除电机驱动报警
设置零位 /set_zeros 电机已初始化,推理未运行 将当前位置标定为机械零位
刷新关节状态 /refresh_joints 电机已初始化 重新读取一次电机状态并做解耦
读取关节 /read_joints 电机已初始化 发布 /joint_states
读取 IMU /read_imu IMU 已创建 发布 /imu

以手柄操作为例,启动节点后终端会打印提示信息:Press 'X' to initialize/deinitialize motors。按下 X 键后,ros_interface.cpp 中的手柄回调会检查当前 is_init_ 状态,并切换为相反状态。如果电机已初始化,再按 X 会调用 deinit_motors() 下电;如果未初始化,则调用 init_motors() 上电。按下 A 键会触发 reset_joints(),但回调逻辑会先暂停推理并检查电机是否已初始化,防止在电机未就绪时强行运动。

Sources: ros_interface.cpp, inference_node.cpp

闭环解耦与构型配置

atom01 机器人采用了踝关节闭环四连杆结构,这意味着 ankle roll 和 ankle pitch 两个自由度并非由单台电机独立驱动,而是由两台电机通过连杆耦合共同实现。为了让上层策略在关节空间操作,而底层在电机空间执行,RobotInterfaceapply_action()refresh_joints() 中嵌入了 DecoupleAtom01 的映射计算。

配置文件中 close_chain_motor_id 明确标识了参与闭环的电机(5、6 为左腿,11、12 为右腿)。urdf2motor 则定义了 URDF 关节顺序到电机列表索引的映射关系。初学者在适配新机型时,若关节顺序与电机接线顺序不一致,只需调整 urdf2motormotor_sign 即可,无需修改源码。

闭环解耦的具体数学实现(包括雅可比矩阵计算和数值迭代)属于运动学层面的深入内容,如果你需要了解其推导过程或为新机型编写解耦器,请参阅 闭环解耦与运动学映射 页面。

Sources: robot_interface.cpp, close_chain_mapping.hpp, decouple_atom01.hpp

安全提示与常见问题排查

电机初始化是物理交互的第一步,任何配置错误都可能导致机器人突然运动或电机报警。以下是初学者最常遇到的几个问题及排查方向。

1. 调用 init_motors 后电机无响应

2. reset_joints 时机器人抖动或运动过快

3. 关节反馈方向与预期相反

4. IMU 数据异常或无法读取

Sources: robot_interface.cpp, robot.yaml

下一步

完成硬件准备与电机初始化后,你已经具备了让机器人"动起来"的最小物理条件。接下来建议按以下顺序继续阅读:

  1. 手柄与指令控制入门 — 了解手柄按键映射和 /cmd_vel 指令控制的完整逻辑。
  2. Launch 文件与启动配置 — 学习如何组织 YAML 参数、配置多策略启动流程。
  3. RobotInterface 设计与实现 — 深入硬件抽象层的内部实现,包括电机驱动工厂和 IMU 坐标变换。

如果你需要为新的机器人平台适配本系统,重点修改的文件只有 config/robot.yaml 以及可能需要新增一个闭环解耦类(参考 DecoupleAtom01 的实现模式)。