机器人功能安全与整机安全监控模块设计
1. 机器人功能安全概念
1.1 什么是机器人功能安全
功能安全:当系统发生硬件故障、软件缺陷、通讯失效、时序异常时,机器人不会产生危险动作,能够进入安全状态。安全状态包括减速、停机、抱闸、急停与断电。
区别于电气安全、机械安全:
- 电气安全:防漏电、过流
- 机械安全:防撞条、防护罩
- 功能安全:控制系统失效后的安全兜底,属于软件‑硬件协同安全
工业机器人常用标准:ISO 10218;移动机器人:ISO 3691‑4;通用功能安全标准:IEC 61508(SIL)、IEC 61511;ROS2 机器人常对标 SIL2/SIL3 等级安全需求。
1.2 功能安全要解决什么问题
一台能够行走的机器人,同时运行着感知、导航、运动规划与关节伺服。这些业务模块追求的是“如何完成任务”。功能安全追求的是另一件事:
当系统发生硬件故障、软件缺陷、通讯失效或时序异常时,机器人不会产生危险动作,并能够进入安全状态。
需要明确三条边界:
- 功能安全不是可靠性。 可靠性讨论的是系统少出错;功能安全讨论的是出错之后仍然不伤人、不毁机。
- 功能安全不是避障。 避障属于导航与环境感知的业务能力。障碍检测失效时,安全监控仍须能把速度指令清零、把关节切到阻尼或切断力矩。
- 功能安全必须独立于业务。 导航、运动规划、感知可以降级或崩溃;整机安全监控模块必须继续工作,并拥有高于业务链路的执行权。
因此,整机安全监控模块应被定义为:机器人的安全大脑。它独立于导航、运动规划、感知等业务模块,是功能安全的中枢节点。它只做诊断、分级、仲裁与安全执行,不参与步态生成,也不参与路径规划。
2. 总体架构:业务链路与安全链路分离
2.1 为什么必须双链路
若把安全判断写进强化学习策略、导航节点或关节控制器内部,会出现三类结构性问题:
- 故障域耦合。 策略推理超时会拖垮安全判断;雷达掉线会让安全节点一起退出。
- 权限倒置。 业务模块既可以产生危险指令,又负责判定该指令是否危险,无法构成独立监督。
- 无法分级。 业务代码通常只有“继续跑”和“退出进程”两种结果,缺少降功率、停机、急停锁定的中间形态。
正确的结构是两条并行链路:
- 业务链路: 感知 → 导航 → rl_sar 有限状态机与强化学习策略 → 关节 PD → 电机。
- 安全链路: 传感器与执行器原始状态 → 整机安全监控 → 故障分级 → 安全执行器(减速、阻尼停机、抱闸、切断力矩、断电)。
安全链路对业务链路具有单向否决权:可以限幅、替换或切断业务输出;业务链路不能关闭或改写安全链路的判定结果。
2.2 双链路总图

2.3 分层原则
| 原则 | 含义 |
|---|---|
| 独立 | 安全监控使用独立线程或独立控制器,不与策略推理共用故障域 |
| 否决 | 安全输出的优先级高于 /cmd_vel、策略动作和手柄速度 |
| 分级 | 故障按后果而不是按来源分级,避免“任何异常都急停” |
| 可恢复与不可恢复分离 | 降功率、停机允许自动或操作员恢复;急停锁定必须人工解锁 |
| 软硬件互补 | 软件负责精细分级与状态记录;硬件负责软件失效时的最终切断 |
3. 整机故障分级体系
3.1 分级目的
故障分级的目的不是给日志分类,而是给允许的运动能力分类。每一级对应明确的能力边界、进入条件、保持条件和退出条件。级别只允许往更安全方向上调,不允许在未满足恢复条件时下调。
| 级别 | 名称 | 允许的运动能力 | 典型触发 | 退出方式 |
|---|---|---|---|---|
| L0 | 正常 | 全速、全力矩、允许切换行走 | 诊断全部通过 | — |
| L1 | 降功率 | 限速、限力矩、禁止技能与导航加速 | 通讯抖动、温度偏高、观测异常、策略推理偶发超时 | 诊断连续通过后自动恢复 |
| L2 | 停机 | 速度为零;关节阻尼或受控趴下;保持供电 | 持续通讯中断、姿态超限前兆、策略初始化失败、看门狗超时 | 操作员确认后回到待机 |
| L3 | 急停锁定 | 切断力矩,必要时抱闸、断电;拒绝一切运动指令 | 硬件急停、驱动器严重故障、安全监控自身失效、未授权的危险动作 | 人工解锁 + 重新自检 |
3.2 升级规则
分级必须单调、可预测,避免在危险边界附近振荡。

规则如下:
- 就高不就低。 同一周期内多个诊断命中时,取最高故障级。
- L1 可自动恢复,L2 不可自动回到行走,L3 不可软件清零。
- 禁止跨级恢复。 L2 退出后进入待机,不得直接回到行走;L3 退出后必须完整自检。
- 安全执行必须可在当前级别内完成。 若 L2 要求趴下,而趴下轨迹本身已不安全,则立即升到 L3。
3.3 故障源与级别的对应关系
按故障物理来源列举,便于实现诊断表。级别仍按后果裁定,下表给出默认映射。
| 故障源 | 示例 | 默认级别 | 安全动作 |
|---|---|---|---|
| 硬件故障 | 电机过流、编码器丢失、驱动器过温、抱闸异常 | L2 或 L3 | 阻尼停机;严重则 STO / 断电 |
| 软件缺陷 | 策略输出 NaN、观测维度不匹配、状态机非法跳转 | L2 | 丢弃动作,进入 Passive |
| 通讯失效 | DDS LowState 中断、/cmd_vel 超时、手柄掉线 | L1 短时 / L2 持续 | 先清零速度,再停机 |
| 时序异常 | 控制周期超差、推理看门狗超时、关节指令陈旧 | L1 或 L2 | 保持上一安全指令或切阻尼 |
| 本体姿态异常 | 横滚 / 俯仰超阈值、摔倒 | L2(跌倒保护) | 阻尼落地,禁止站立与行走 |
| 操作员输入 | 硬件急停、键盘 / 手柄 Passive | L2 或 L3 | 立即执行对应安全状态 |
4. 整机状态机
故障分级描述“现在允许多大能力”;整机状态描述“机体当前处于哪一种工作形态”。二者正交:同一状态可以处于不同故障级,但并非所有组合都合法。
4.1 六种整机状态
| 状态 | 定义 | 电机行为 | 允许的故障级 |
|---|---|---|---|
| 自检 | 上电后检查通讯、传感器、模型、急停回路与驱动器就绪 | 禁止运动,kp=0,必要时弱阻尼 | 仅 L0 可通过;否则进入故障锁定 |
| 待机 | 自检通过,等待站立或任务 | 阻尼或保持默认站立姿态 | L0 / L1 |
| 行走 | 强化学习策略控制关节,跟踪速度指令 | PD 跟踪策略输出 | L0;L1 时限速限力矩继续行走 |
| 跌倒保护 | 姿态失稳或已摔倒,优先保护机体与周围人员 | 高阻尼、零前馈力矩,禁止起立 | L2 |
| 充电 | 对接充电或外部供电维护 | 禁止行走;关节锁定或阻尼 | L0 / L1;出现运动请求升至 L2 |
| 故障锁定 | 急停或不可恢复故障,等待人工处理 | STO / 抱闸 / 断电 | L3 |
4.2 状态转移

转移约束:
- 行走只能从待机进入。 自检、跌倒保护、充电、故障锁定均不得直接进入行走。
- 跌倒保护不得自行站立。 必须回到待机,由操作员或上层任务重新请求起立。
- 充电与行走互斥。 充电状态下任何非零速度指令视为故障。
- 故障锁定是吸收态。 除人工解锁外,没有软件出口。
4.3 状态与故障级的合法组合
| 状态 | L0 正常 | L1 降功率 | L2 停机 | L3 急停锁定 |
|---|---|---|---|---|
| 自检 | 允许(通过条件) | 不允许通过 | 失败,转故障锁定 | 立即故障锁定 |
| 待机 | 允许 | 允许 | 进入停机保持 | 转故障锁定 |
| 行走 | 允许 | 限速限力矩行走 | 退出行走并停机 | 转故障锁定 |
| 跌倒保护 | 不允许停留 | 不允许停留 | 允许 | 保护失败则锁定 |
| 充电 | 允许 | 允许 | 切断充电运动 | 转故障锁定 |
| 故障锁定 | 不允许 | 不允许 | 不允许 | 唯一合法级别 |
5. 整机安全监控模块设计
5.1 模块职责
整机安全监控模块只承担四项职责:
- 采集: 汇总电机、IMU、通讯心跳、控制周期、急停回路、电池与温度等原始证据。
- 诊断: 将证据与阈值比较,生成故障码,不解释业务语义。
- 仲裁: 按故障分级表得到当前级别,并选择目标整机状态。
- 执行: 向软件状态机下发安全请求,必要时直接驱动硬件安全回路。
不承担的职责:步态生成、路径规划、障碍物分类、策略推理、人机对话。
5.2 内部结构

5.3 输入、输出与周期
| 项目 | 约定 |
|---|---|
| 运行频率 | 不低于关节控制频率;在 rl_sar 中应对齐 loop_control(Go2 为 dt = 0.005 s,即 200 Hz) |
| 输入 | 电机状态、IMU、心跳时间戳、控制/推理周期耗时、急停触点、指令副本 |
| 软件输出 | fault_level、machine_state、速度/力矩限幅、FSM 强制跳转请求 |
| 硬件输出 | STO、抱闸、主电切断;仅 L3 或安全监控自身失活时使用 |
| 发布 | /safety/status:级别、状态、故障码、解锁许可 |
5.4 指令闸门
闸门位于业务指令与电机驱动之间,是安全大脑对执行层的唯一软件接口。优先级从高到低:
- L3: 不向电机写业务指令;置位硬件 STO。
- L2: 忽略策略队列与 /cmd_vel,改写为阻尼或受控趴下轨迹。
- L1: 允许策略输出,但叠加速度上限、力矩上限,并禁止导航加速。
- L0: 透传业务指令。
闸门必须对下列对象同时生效:键盘速度、手柄速度、/cmd_vel、强化学习动作、起立/趴下插值。漏掉任何一条入口,安全否决权就不完整。
5.5 一次故障处理时序

6. 以 rl_sar 为例:软硬件结合的功能安全实现
rl_sar 是仿真与实物共用的强化学习部署框架。它已经具备状态机、关节指令限幅、通讯校验和若干保护函数,但尚未形成独立的安全大脑。下面按“现有能力 → 缺口 → 结合方式”说明如何把功能安全落到该项目上。
6.1 现有控制闭环
Go2 实物路径是两条定时循环:关节控制 loop_control 按 dt 运行,策略推理 loop_rl 按 dt * decimation 运行。Go2 配置为 dt = 0.005、decimation = 4,即 200 Hz 写电机、50 Hz 推理。
// loop
this->loop_keyboard = std::make_shared<LoopFunc>("loop_keyboard", 0.05, std::bind(&RL_Real::KeyboardInterface, this));
this->loop_control = std::make_shared<LoopFunc>("loop_control", this->params.Get<float>("dt"), std::bind(&RL_Real::RobotControl, this));
this->loop_rl = std::make_shared<LoopFunc>("loop_rl", this->params.Get<float>("dt") * this->params.Get<int>("decimation"), std::bind(&RL_Real::RunModel, this));
this->loop_keyboard->start();
this->loop_control->start();
this->loop_rl->start();
RobotControl() 的顺序是:读状态 → 跑状态机 → 写电机。安全监控应插入在“跑状态机”之前,并在“写电机”之前拥有改写权。
void RL_Real::RobotControl()
{
this->GetState(&this->robot_state);
this->StateController(&this->robot_state, &this->robot_command);
this->control.ClearInput();
this->SetCommand(&this->robot_command);
}

6.2 现有软件机制与安全功能的对应
rl_sar 中已经存在若干可复用的安全相关机制。它们是安全监控的执行器,还不是安全监控本身。
| rl_sar 机制 | 位置 | 对应安全功能 | 现状 |
|---|---|---|---|
| RLFSMStatePassive | fsm_go2.hpp 等 | L2 停机:kp=0, kd=8, tau=0 阻尼 | 已实现,由键盘 P / 手柄 LB_X 进入 |
| RLFSMStateGetUp / GetDown | 同上 | 待机与受控趴下 | 已实现;插值使用 fixed_kp/kd |
| RLFSMStateRLLocomotion | 同上 | 行走 | 已实现;InitRL 失败会请求回到 Passive |
| TorqueProtect | rl_sdk.cpp | 力矩越限诊断 | 默认仅告警,切 Passive 的代码被注释 |
| AttitudeProtect | rl_sdk.cpp | 跌倒保护 | 横滚/俯仰超 75° 时置位 P;多数 RunModel 中被注释 |
| clip_obs / clip_actions | ComputeObservation / Forward | 软件缺陷防护 | 已实现,防止观测与动作爆炸 |
| torque_limits | ComputeOutput | L1 力矩限幅 | 已对计算力矩 clamp |
| robot_joint_controller 限位 | URDF limits | 仿真侧位置/速度/力矩饱和 | 仅 Gazebo 路径 |
| Crc32Core | rl_real_go2.cpp | 通讯完整性 | 发送侧已计算 CRC |
| InitLowCmd | 同上 | 上电安全默认值 | kp=0, kd=0, tau=0 |
| 避障 cmd_timeout | avoidance_node.cpp | 导航指令超时清零 | 仅业务层;rl_sar 本身不因 /cmd_vel 中断停车 |
Go2 的 Passive 状态已经是可用的软件安全状态:
void Run() override
{
for (int i = 0; i < rl.params.Get<int>("num_of_dofs"); ++i)
{
// fsm_command->motor_command.q[i] = fsm_state->motor_state.q[i];
fsm_command->motor_command.dq[i] = 0;
fsm_command->motor_command.kp[i] = 0;
fsm_command->motor_command.kd[i] = 8;
fsm_command->motor_command.tau[i] = 0;
}
}
InitRL 失败时拒绝进入行走,直接请求 Passive,符合“自检失败不得行走”:
try
{
rl.InitRL(robot_config_path);
rl.now_state = *fsm_state;
}
catch (const std::exception& e)
{
std::cout << LOGGER::ERROR << "InitRL() failed: " << e.what() << std::endl;
rl.rl_init_done = false;
rl.fsm.RequestStateChange("RLFSMStatePassive");
}
姿态保护把危险姿态映射为与操作员急停相同的输入,从而复用 Passive。但是,该函数挂在策略线程里,保护能力很有限。如果要在实机上用,把对应 RunModel() 里那一行打开即可,函数本身是通的。更稳妥的做法是不要再伪造 P 键,改为独立监控直接切 Passive,并按机型单独标定俯仰/横滚阈值。
void RL::AttitudeProtect(const std::vector<float> &quaternion, float pitch_threshold, float roll_threshold)
{
// Use QuaternionToEuler from vector_math.hpp
std::vector<float> euler = QuaternionToEuler(quaternion);
float roll = euler[0] * 57.2958f; // Convert to degrees
float pitch = euler[1] * 57.2958f;
if (std::fabs(roll) > roll_threshold)
{
this->control.SetKeyboard(Input::Keyboard::P);
std::cout << LOGGER::WARNING << "Roll exceeds " << roll_threshold << " degrees. Current: " << roll << " degrees." << std::endl;
}
if (std::fabs(pitch) > pitch_threshold)
{
this->control.SetKeyboard(Input::Keyboard::P);
std::cout << LOGGER::WARNING << "Pitch exceeds " << pitch_threshold << " degrees. Current: " << pitch << " degrees." << std::endl;
}
}
6.3 现有缺口
将上述机制当作完整功能安全是不够的,主要缺口有六点:
- 没有独立安全监控节点。 保护函数位于策略线程 RunModel 中,推理卡住时保护一起失效。
- 没有故障分级。 实际只有“继续行走”和“进 Passive”两档,缺少降功率与急停锁定。
- 保护默认关闭。 TorqueProtect、AttitudeProtect 在 Go2 / G1 / Lite3 等 RunModel 中被注释;TorqueProtect 即使启用也只打印告警。
- 没有指令看门狗。 RLControl 仅在队列有新动作时更新关节目标;推理停住后,上一拍 PD 目标会继续被 200 Hz 循环写出。
- /cmd_vel 中断不停车。 导航模式打开后,上游超时不会把 obs.commands 清零。
- 没有硬件安全回路接口。 软件 Passive 不能替代 STO、抱闸和急停触点;主控死机时电机仍可能保持最后一帧伺服指令。
6.4 软件侧:把安全大脑接到 rl_sar
建议在 loop_control 内增加独立于 FSM 的 SafetyMonitor,而不是把逻辑继续堆进 RunModel。原因是 loop_control 频率更高,且即使 rl_init_done == false 也会运行。
推荐的软件对象划分如下
| 对象 | 职责 | 建议挂载点 |
|---|---|---|
| SafetyMonitor | 诊断、分级、状态仲裁 | loop_control 中 GetState 之后 |
| CommandGate | 按级别改写 robot_command 与 obs.commands | StateController 之后、SetCommand 之前 |
| Watchdog | 监视 loop_rl 心跳、LowState 时间戳、/cmd_vel 时间戳 | SafetyMonitor 内部 |
| 现有 FSM | 作为 L2 的执行器,不承担分级 | 保持 fsm_robot/ |
整机状态与现有 FSM 状态的映射:
| 整机状态 | rl_sar FSM | 附加条件 |
|---|---|---|
| 自检 | 尚未 SetInitialState,或处于 Passive 且诊断未完成 | 禁止 Num0 起立 |
| 待机 | RLFSMStatePassive 或 GetUp 完成且未进 Locomotion | 故障级为 L0 / L1 |
| 行走 | RLFSMStateRLLocomotion | L0 全速;L1 时缩小 commands 与 torque_limits |
| 跌倒保护 | 强制 RLFSMStatePassive(高 kd) | 由姿态诊断触发,禁止 Num0 |
| 充电 | 扩展状态 RLFSMStateCharge,或复用 Passive 并锁死起立 | 检测充电桩对接信号 |
| 故障锁定 | Passive + 硬件 STO;FSM 忽略键盘/手柄 | 直到人工解锁 |
L1 降功率可直接复用现有限幅通道,不必改策略网络:
- 缩小 obs.commands(或在写入前乘以 power_scale)。
- 缩小 params 中的 torque_limits、rl_kp。
- 关闭 navigation_mode 的加速,或把 /cmd_vel 再限幅一次。
L2 停机应调用已有 RequestStateChange(“RLFSMStatePassive”),并把 TorqueProtect 中被注释的切状态逻辑正式交给 SafetyMonitor,而不是继续置位键盘 P。用键盘枚举传递安全事件会与操作员输入竞争,也难以表达 L3。
L3 急停锁定必须同时满足:软件不再更新业务指令;硬件回路切断力矩。仅靠 kd=8 的 Passive 不够,因为主控或 DDS 失效后该指令无法刷新。
6.5 硬件侧:软件失效后的最终屏障
软件监控处理可分级、可恢复的异常。硬件回路处理“软件已经不能被信任”的情况。与 rl_sar 实物部署直接相关的硬件要素如下。
| 硬件要素 | 作用 | 与软件的接口 |
|---|---|---|
| 电机驱动器过流 / 过温 / 过压保护 | 单关节局部安全 | 故障位读入 LowState,由监控升为 L2 / L3 |
| 编码器与 IMU | 姿态与关节诊断依据 | 已由 GetState 写入 RobotState |
| 指令 CRC | 防止损坏的 LowCmd 被执行 | SetCommand 已写 CRC;接收侧由驱动器校验 |
| 上电默认 PosStopF + 零增益 | 避免未初始化伺服冲击 | InitLowCmd |
| 急停按钮 / 无线急停 | 操作员 L3 | 独立触点,不经过策略进程 |
| STO(Safe Torque Off) | 主控死机时切断功率级 | 安全继电器或驱动器 STO 输入 |
| 抱闸 | 断电后防止关节失控下落 | L3 或掉电时自动啮合 |
| 电源接触器 | 切断母线 | 仅 L3 或热失控 |
实物 SetCommand 已经体现了“默认安全、再写有效关节”的硬件友好模式:先把全部通道置为零增益,再按 joint_mapping 填写有效指令,最后计算 CRC。
void RL_Real::SetCommand(const RobotCommand<float> *command)
{
unitree_go::msg::dds_::LowCmd_ dds_low_command;
dds_low_command.head()[0] = 0xFE;
dds_low_command.head()[1] = 0xEF;
dds_low_command.level_flag() = 0xFF;
dds_low_command.gpio() = 0;
for (int i = 0; i < 20; ++i)
{
dds_low_command.motor_cmd()[i].mode() = 0x01;
dds_low_command.motor_cmd()[i].q() = PosStopF;
dds_low_command.motor_cmd()[i].kp() = 0;
dds_low_command.motor_cmd()[i].dq() = VelStopF;
dds_low_command.motor_cmd()[i].kd() = 0;
dds_low_command.motor_cmd()[i].tau() = 0;
}
// ... 按 joint_mapping 填写有效指令后计算 CRC 并发送
这一模式应保留,并增加两条硬件约束:
- 指令超时断电。 驱动器若在约定周期(例如 20–50 ms)内收不到合法 LowCmd,自动进入无力矩,而不是保持最后一帧。这是对 loop_control 线程死亡的硬件补偿。
- 急停回路不经过 rl_real_go2。 按钮直接断开 STO 或接触器。软件只读取反馈并进入故障锁定,不能成为急停的唯一路径。
6.6 软硬件如何分工

分工可以概括为五条:
- 软件负责分级,硬件负责切断。 L1、L2 尽量留在软件,以保留可恢复性;L3 必须落到硬件。
- 软件负责记录,硬件负责即时性。 故障码、状态、解锁许可由监控模块发布;微秒级过流由驱动器完成。
- 软件看门狗监视业务,硬件看门狗监视软件。 SafetyMonitor 监视策略与通讯;驱动器监视 LowCmd 是否仍在刷新。
- 安全状态要能被硬件理解。 Passive 的“无力矩 + 阻尼”对应驱动器的电流环阻尼或无力矩模式;故障锁定对应 STO,而不是继续发送 kd=8。
- 仿真与实物使用同一套分级表。 Gazebo 路径用 URDF EffortLimit 代替驱动器保护,用软件标志代替 STO,便于在 rl_sim 中先验证状态机,再上实机。
6.7 推荐的诊断表(可直接落到 rl_sar)
| 诊断项 | 输入 | 阈值建议 | 级别 | 软件动作 | 硬件动作 |
|---|---|---|---|---|---|
| LowState 心跳丢失 | 最近一帧时间戳 | > 20 ms → L1;> 50 ms → L2 | L1 / L2 | 清零速度;进 Passive | 驱动器指令超时无力矩 |
| 推理看门狗 | loop_rl 心跳 | > 2 个 decimation 周期 → L1;> 10 个 → L2 | L1 / L2 | 丢弃陈旧动作 | 无 |
| /cmd_vel 超时 | 导航模式时间戳 | > 0.4 s | L1 | obs.commands = 0 | 无 |
| 力矩越限 | output_dof_tau 与 torque_limits | 连续越限 | L2 | TorqueProtect 真正切 Passive | 驱动器过流保护 |
| 姿态超限 | IMU 四元数 | 俯仰或横滚 > 75° | L2 | 跌倒保护(Passive + 禁止起立) | 无 |
| 观测 / 动作非有限值 | Forward 输出 | 出现 NaN/Inf | L2 | 丢弃动作,进 Passive | 无 |
| InitRL 失败 | 模型加载异常 | 一次失败 | L2 | 保持 Passive | 无 |
| 电机驱动器故障位 | LowState 错误码 | 严重故障 | L3 | 故障锁定 | STO / 抱闸 |
| 急停触点 | GPIO / 按钮 | 按下 | L3 | 忽略全部输入 | 切断功率级 |
| 安全监控失活 | 监控任务心跳 | 超时 | L3 | — | STO 默认吸合切断 |
阈值需按具体机型标定。上表与 Go2 的 dt、现有 AttitudeProtect(75°, 75°) 以及感知栈 cmd_timeout: 0.4 对齐,便于先在本仓库落地,再按实测调整。
6.8 控制周期中的安全插入伪代码
下列顺序保证:先诊断,再允许业务状态机运行,最后闸门改写即将下发的电机指令。
void RobotControl()
{
GetState(&robot_state);
safety.Update(robot_state, rl_heartbeat, cmd_vel_stamp, estop_hw);
// safety.level ∈ {Normal, Derate, Stop, EStopLock}
// safety.machine_state ∈ {SelfTest, Standby, Walk, FallProtect, Charge, FaultLock}
if (safety.level == FaultLevel::EStopLock) {
ApplyPassiveCommand(&robot_command); // 软件侧最后一帧阻尼
SetCommand(&robot_command);
AssertHardwareSTO(); // 硬件切断
return;
}
StateController(&robot_state, &robot_command); // 现有 FSM
safety.Gate(robot_command, control, obs.commands);
// L1: 缩小 commands 与力矩上限
// L2: 覆盖为 Passive / GetDown,并禁止 Num0/Num1
// 跌倒保护: 强制 Passive,ClearInput 中忽略起立键
SetCommand(&robot_command);
}
loop_rl 只向监控报告心跳与动作有限性,不再自行决定是否切 Passive,避免两个线程同时改 FSM。
| 步骤 | 环境 | 注入故障 | 通过标准 |
|---|---|---|---|
| 1 | rl_sim | 策略输出 NaN | 进入 Passive,Gazebo 中关节力矩为零 |
| 2 | rl_sim | 停止发布 /cmd_vel | 0.4 s 内速度指令为零,机体原地踏步或停止前进 |
| 3 | rl_sim | 将 IMU 俯仰置为 80° | 进入跌倒保护,Num0 无法起立 |
| 4 | rl_sim | 连续越限力矩 | 故障级升至 L2,不再跟踪策略 |
| 5 | 实物空载(架起) | 断开网口或停掉 loop_rl | 软件进停机;驱动器在超时后无力矩 |
| 6 | 实物空载 | 按下急停 | 不依赖进程,功率级切断;解锁前拒绝行走 |
| 7 | 实物着地 | L1 限速 | 手柄打满时速度不超过降功率上限 |
| 8 | 实物着地 | 正常行走中请求 L2 | 平稳进入阻尼或趴下,无大幅度抽搐 |
验证时须遵守仓库已有的安全声明:实机操作前采取充分防护;架起测试先于着地测试;急停按钮始终由专人持有。
7. 验证建议
功能安全不能只靠代码审查。建议按级别从仿真到实物递进。
| 步骤 | 环境 | 注入故障 | 通过标准 |
|---|---|---|---|
| 1 | rl_sim | 策略输出 NaN | 进入 Passive,Gazebo 中关节力矩为零 |
| 2 | rl_sim | 停止发布 /cmd_vel | 0.4 s 内速度指令为零,机体原地踏步或停止前进 |
| 3 | rl_sim | 将 IMU 俯仰置为 80° | 进入跌倒保护,Num0 无法起立 |
| 4 | rl_sim | 连续越限力矩 | 故障级升至 L2,不再跟踪策略 |
| 5 | 实物空载(架起) | 断开网口或停掉 loop_rl | 软件进停机;驱动器在超时后无力矩 |
| 6 | 实物空载 | 按下急停 | 不依赖进程,功率级切断;解锁前拒绝行走 |
| 7 | 实物着地 | L1 限速 | 手柄打满时速度不超过降功率上限 |
| 8 | 实物着地 | 正常行走中请求 L2 | 平稳进入阻尼或趴下,无大幅度抽搐 |
验证时须遵守仓库已有的安全声明:实机操作前采取充分防护;架起测试先于着地测试;急停按钮始终由专人持有。
8. 结语
功能安全要求机器人在硬件故障、软件缺陷、通讯失效和时序异常时不产生危险动作,并进入减速、停机、抱闸、急停或断电等安全状态。实现这一目标,不能把判断散落在导航、感知或策略内部,而需要独立的整机安全监控模块作为安全大脑。
故障分级给出能力边界:正常、降功率、停机、急停锁定。整机状态给出工作形态:自检、待机、行走、跌倒保护、充电、故障锁定。监控模块以诊断表连接二者,并用指令闸门保证所有运动入口都接受否决。
在 rl_sar 上,软件侧应把现有 FSM 的 Passive、力矩限幅、姿态保护和 CRC 收编为执行器,补齐独立监控、看门狗与分级恢复规则;硬件侧应以驱动器保护、指令超时无力矩、急停触点和 STO 作为软件失效后的最终屏障。两条链路同时存在,功能安全才是可执行的工程属性,而不是事后附加的告警日志。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)