🤖 roboto_origin_03 Wiki
首页 / 项目根 / 安全操作与零位标定

在将强化学习策略从仿真环境迁移到物理机器人之前,零位标定是最后一道也是最关键的一道门槛。它直接决定了仿真中训练的关节角度能否被物理电机正确解读;若零位存在偏差,机器人启动瞬间就会出现姿态失控、电机过载甚至结构损坏的风险。本文档面向初次接触双足机器人硬件的开发者,系统梳理 ATOM01 的安全操作原则与两种零位标定方法,帮助你在通电前建立正确的安全意识和操作习惯。

Sources: README_cn.md


安全操作基本原则

ATOM01 V2.0 在硬件层面针对安全性做了三项核心改进:腰部机械限位背板物理电源开关以及限位销钉标定工艺。这些设计将大幅降低首次装机和日常调试中的意外风险。无论使用 V1.0 还是 V2.0 硬件,你都需要从机械、电气、软件三个维度建立安全操作意识。

机械安全方面,V2.0 在腰部旋转机构处新增了机械限位块,防止腰部 yaw 关节过度旋转导致线束缠绕或结构碰撞。进行零位标定前,请确认机器人处于稳定的支撑状态,建议使用专用标定件或至少保证机器人不会倾倒。BOM 清单中的限位销(ATOM-01-021,共 8 个)是 V2.0 标定工艺的核心耗材,用于在标定时锁定关节的绝对零位。

电气安全方面,机器人使用 48V 锂电池供电,BOM 中包含了急停继电器(ATOM-01-028),建议在总电源回路中串入急停开关。上电前务必测量主电源极性,确认无短路后再接通电池。V2.0 的背板新增了主控板物理开关,可在不插拔电池的情况下快速切断主控电源,这在软件卡死或电机失控时尤为重要。

软件安全方面,部署框架内置了多重保护。推理节点启动时会尝试设置实时线程优先级,确保控制循环不被系统调度打断;同时推理主线程会调用 mlockall 锁定内存页,防止运行时交换延迟。在关节控制层面,系统会在每次获取关节位置时检查 joint_limits,一旦某个关节超出预设的物理限位,节点会立即触发 RCLCPP_FATAL 并调用 rclcpp::shutdown() 停止整个推理流程,从而避免电机继续向危险位置运动。

Sources: README_cn.md, BOM.md, obs_manager.cpp, inference_node.cpp


零位标定的物理意义

在 Isaac Lab 仿真环境中,策略网络输出的是相对于默认姿态的关节偏移量。部署到真实机器人时,这些偏移量需要叠加到物理电机的编码器零点上,才能产生正确的目标位置。如果物理零位与仿真默认姿态不一致,就会出现"仿真能走、实物摔倒"的现象。

ATOM01 的 URDF 模型定义了 23 个旋转关节,涵盖左右腿(各 6 个,含 2 个闭链脚踝关节)、腰部 yaw(1 个)以及左右手臂(各 5 个)。在软件层面,robot.yaml 中的 motor_zero_offset 字段允许为每个电机单独施加一个固定的弧度偏移,用来补偿机械装配带来的系统性偏差。其中腰部 yaw 关节(电机 ID 13)的偏移量默认配置为 2.093 rad,这与 V2.0 的机械限位块标定工艺直接相关,后文将详细说明其含义。

Sources: robot.yaml, atom01.urdf


标定前的准备工作

在启动任何标定流程前,请按以下清单逐项确认:

检查项 说明 相关文档
硬件版本确认 V2.0 使用插销标定,V1.0 使用通用标定;两者机械结构不兼容 V2.0机械结构与装配工艺
电机 ID 与 CAN 映射 确认电机已按 can0 左腿、can1 右腿+腰、can2 左手、can3 右手的方式接线 电机驱动与CAN总线通信
udev 规则生效 确保 CAN 接口和 IMU 串口已自动绑定,无需手动顺序插拔 部署架构与实时内核配置
编译工作空间 执行 colcon build --symlink-install 并 source 环境 快速开始与仓库结构
机器人姿态固定 将机器人调整至标定姿态(站立或躺倒,视标定件而定),防止倾倒 本文档下文

准备工作完成后,你需要根据场景选择以下两种标定方式之一。第一种适合电机已经初始化且软件框架已启动的情况;第二种适合首次装机、检修后或只想对部分电机重新标定的情况。

Sources: README_cn.md, set_zero.yaml


方法一:ROS 服务批量标定(推荐用于日常维护)

当机器人软件已经启动、电机已经初始化且推理未运行时,可以通过 ROS2 服务将所有电机的当前位置一次性写入零点。该方式效率高,适合日常维护后的零点校准。

下图展示了服务标定的完整操作顺序。请注意,调用 /set_zeros 服务前,推理必须处于暂停状态;若推理正在运行,服务会明确拒绝并返回错误信息 "Inference is running, cannot set zeros."

flowchart TD
    A[启动终端并source环境] --> B[运行 ./tools/start_robot.sh]
    B --> C[等待推理节点和手柄节点就绪]
    C --> D[ros2 service call /init_motors]
    D --> E[手动将机器人摆到目标零位]
    E --> F{推理是否运行?}
    F -->|否| G[ros2 service call /set_zeros]
    F -->|是| H[先暂停推理或确保未启动]
    H --> G
    G --> I{服务返回success?}
    I -->|是| J[标定完成,可启动推理]
    I -->|否| K[查看错误信息并排查]

具体指令序列如下:

source /opt/ros/humble/setup.bash
source install/setup.bash
./tools/start_robot.sh
ros2 service call /init_motors std_srvs/srv/Trigger
ros2 service call /set_zeros std_srvs/srv/Trigger

在软件实现层面,InferenceNode::set_zeros_srv 会执行两项前置检查:首先确认 robot_->is_init_ 为真(电机已初始化),其次确认 is_running_ 为假(推理未运行)。只有通过这两项检查后,才会调用 RobotInterface::set_zeros(),进而通过线程池并行向所有电机发送 set_motor_zero() 指令。

Sources: README_cn.md, ros_interface.cpp, robot_interface.cpp


方法二:Python 脚本逐个标定(推荐用于首次装机)

对于首次组装、更换电机或只想对个别关节重新标定的场景,scripts/set_zero.py 提供了更安全的交互式逐个标定流程。该脚本会按 scripts/config/set_zero.yaml 中定义的顺序依次访问每个电机,自动将电机切换到阻尼模式,允许你手动自由转动关节;当关节到达标定位置后,按 Enter 键即可将该位置写入电机零点,按空格键则可跳过当前电机。

下图为脚本标定的交互流程。脚本在标定过程中会实时打印当前电机的位置(rad)和错误码,帮助你判断电机状态是否正常。

flowchart TD
    A[确认set_zero.yaml配置与硬件一致] --> B[source ROS2和工作空间环境]
    B --> C[python3 scripts/set_zero.py]
    C --> D[按Enter开始标定流程]
    D --> E[脚本自动使能电机并设为阻尼模式]
    E --> F[手动将该关节摆到零位]
    F --> G{用户按键}
    G -->|Enter| H[写入当前位置为零点]
    G -->|Space| I[跳过该电机]
    H --> J{是否还有未标定电机?}
    I --> J
    J -->|是| E
    J -->|否| K[汇总标定结果并退出]

set_zero.yaml 中定义了 23 个电机的基本参数。motor_num: [6, 7, 5, 5] 表示四条 CAN 总线上的电机数量,依次对应左腿 6 个、右腿与腰部共 7 个、左手 5 个、右手 5 个。motor_model 字段区分了电机型号:1 代表 DM 10010L(大功率,多用于大腿和腰部),0 代表 DM 4340P(小功率,多用于脚踝和手臂)。如果你的实际装机型号与配置不符,请务必在运行脚本前修改该文件。

Sources: README_cn.md, set_zero.py, set_zero.yaml


腰部 Yaw 轴的偏移配置

robot.yamlinference.yaml 中,motor_zero_offset 列表的第 13 项(索引 12,对应腰部 yaw 电机 ID 13)默认值为 2.093。这个数值来源于 V2.0 的机械设计:当腰部 yaw 关节旋转至机械限位块处时,电机编码器的读数与仿真默认零位之间存在约 2.093 弧度的固定偏差。因此,若你采用"将腰部转至限位块"的方式进行标定,必须保留该偏移量,以确保仿真策略中的 0 弧度对应物理上的直立姿态。

如果你使用的是打印件固定标定(例如通过 3D 打印的标定夹具将腰部锁定在绝对零位),则此时电机编码器读数已经与仿真零位一致,需要将 robot.yaml 中的 2.093 修改为 0.0。修改后需重新编译工作空间才能使配置生效。

标定方式 robot.yaml 中腰部偏移值 适用版本 备注
限位块标定 2.093 V2.0(推荐) 将腰部 yaw 转至机械限位处,利用结构自然定位
打印件固定标定 0.0 V1.0 / V2.0 使用 3D 打印标定件将腰部锁定在绝对零位

Sources: README_cn.md, robot.yaml


软件安全保护机制详解

除了硬件层面的急停和限位,部署软件在运行时也构建了多层安全防线,初学者应当了解这些机制的工作原理,以便在异常发生时快速判断原因。

服务层安全检查/set_zeros 服务并非无条件执行。InferenceNode::set_zeros_srv 明确拒绝两类非法调用:一是电机尚未初始化时(返回 "Motors are not initialized, cannot set zeros."),二是推理正在运行时(返回 "Inference is running, cannot set zeros.")。同理,/init_motors/deinit_motors 服务也会检查当前状态,防止重复初始化或非法去初始化。

运行时关节限位保护:在推理循环中,每次读取关节位置观测值时,get_dof_pos_obs 都会将当前关节位置与 joint_limits 进行对比。joint_limitsinference.yaml 中成对定义了 23 个关节的 [下限, 上限]。一旦某个关节超出范围,系统会立即打印致命错误日志 Joint X out of limit! Shutting down...,随后调用 rclcpp::shutdown() 终止整个节点。这是一种"fail-safe"设计:宁可停止运行,也不允许电机继续向机械极限运动。

手柄控制的紧急干预逻辑:手柄的按键映射遵循"先停推理、再操作电机"的安全顺序。当你按下 X 键(使能/失能电机)时,如果推理正在运行,系统会先自动暂停推理,然后再执行电机的初始化或去初始化;当你按下 A 键(复位电机)时,系统同样会先确保推理已暂停,再将所有关节重置到 joint_default_angle 定义的默认角度。这意味着在任何情况下,你都可以通过手柄快速让机器人回到可控的安全姿态。

Sources: ros_interface.cpp, ros_interface.cpp, obs_manager.cpp, inference.yaml


常见问题排查

下表总结了零位标定和安全操作中初学者最常遇到的问题及其排查方向:

现象 可能原因 排查方法
调用 /set_zeros 返回失败 推理正在运行或电机未初始化 确认推理已暂停,且已调用 /init_motors
set_zero.py 提示创建电机失败 CAN 接口未启用或 udev 规则未生效 执行 ip a 查看 can0~can3 是否存在;检查 udev 规则
标定后机器人站立姿态倾斜 robot.yaml 中腰部偏移值与标定方式不匹配 确认使用的是限位块标定(保留 2.093)还是打印件标定(改为 0.0)
启动推理后立刻报 Joint out of limit 零位标定错误,导致某关节实际位置已接近机械极限 重新执行标定,重点检查左右脚踝(ID 5,6,11,12)和膝盖(ID 4,10)
电机无法进入阻尼模式 电机型号配置错误 检查 set_zero.yaml 中的 motor_model 与实际硬件是否一致
推理循环打印 overran 警告 实时内核未正确配置或负载过高 确认已安装实时内核并正确配置 limits.conf;检查 ulimit -r 输出是否为 98

Sources: README_cn.md, set_zero.yaml, inference_node.cpp


下一步

完成零位标定并确认软件安全机制正常后,你可以继续阅读 部署架构与实时内核配置 深入了解 ROS2 部署框架的启动流程,或者直接前往 电机驱动与CAN总线通信 学习电机底层通信协议与调试技巧。如果你尚未完成机械组装,建议先回到 V2.0机械结构与装配工艺 确保机械限位和标定销安装到位。