部署反馈闭环
相关源文件
生成此 wiki 页面时使用了以下文件作为上下文:
本文档说明 IB-Robot 中的部署反馈闭环机制。该机制通过记录已部署机器人产生的在线评估数据,并将其回流到训练流水线,支持持续改进和领域适配。
概览
部署反馈闭环补齐了数据生命周期的最后一环,让已部署机器人可以记录真实执行数据,用于后续训练迭代。它支持:
领域适配:让模型适应初始训练中未覆盖的新环境或新任务。
失败分析:结合 operator prompts 记录失败案例,用于针对性再训练。
持续学习:通过聚合部署 episodes,逐步提升模型表现。
反馈闭环复用现有数据流水线,并使用初始数据采集同一套 contract-aware 处理工具(episode_recorder、bag_to_lerobot),以减少 training/serving skew src/dataset_tools/dataset_tools/bag_to_lerobot.py:8-11。
来源: src/dataset_tools/dataset_tools/bag_to_lerobot.py:1-20, src/robot_config/robot_config/launch_builders/recording.py:1-9
反馈闭环架构
下图展示部署反馈如何接入整体数据生命周期,并将自然语言 prompts 连接到被记录的代码实体。
数据生命周期图
graph TB
subgraph NaturalLanguageSpace["Natural Language Space"]
PROMPT["Operator Task Prompt<br/>'pick up the red block'"]
end
subgraph DeploymentPhase["Deployment Phase"]
INF["inference_service<br/>(Policy Node)"]
ROBOT["Physical Robot<br/>(so101_hardware)"]
INF -->|"actions"| ROBOT
end
subgraph CodeEntitySpace["Code Entity Space (Feedback Loop)"]
CLI["record_cli.py<br/>(Action Client)"]
SERVER["EpisodeRecorderServer<br/>(Action Server)"]
WRITER["rosbag2_py.SequentialWriter<br/>(Writer)"]
CLI -->|"RecordEpisode.Goal(prompt)"| SERVER
SERVER -->|"serialize_message"| WRITER
ROBOT -->|"Topic Observations"| SERVER
WRITER -->|"metadata.yaml + .mcap"| BAG["ROS2 Bag"]
end
subgraph DatasetAdaptation["Dataset Adaptation"]
BAG -->|"bag_to_lerobot.py"| CONVERT["Dataset Conversion"]
CONVERT -->|"append"| DS["LeRobot v3 Dataset"]
end
PROMPT -.->|"input to"| CLI
DS -.->|"retrain"| INF
关键工作流:
机器人运行已部署策略,例如 ACT 或 Diffusion model src/dataset_tools/dataset_tools/bag_to_lerobot.py:8-10。
操作员通过
record_cli触发录制,并为当前 episode 提供语义 prompt src/dataset_tools/dataset_tools/episode_recorder.py:53-55。EpisodeRecorderServer基于robot_config.yaml中的contractsection 捕获 ROS2 消息 src/dataset_tools/dataset_tools/episode_recorder.py:138-143。录制得到的 bag 通过
bag_to_lerobot.py转换为 LeRobot v3 格式。该脚本使用共享decode_value逻辑和 contract specs,确保训练和推理对齐 src/dataset_tools/dataset_tools/bag_to_lerobot.py:14-19。
来源: src/dataset_tools/dataset_tools/episode_recorder.py:8-32, src/dataset_tools/dataset_tools/bag_to_lerobot.py:8-19, src/robot_config/robot_config/launch_builders/recording.py:138-143
录制模式
系统支持由 robot_config launch 系统生成的两种录制模式 src/robot_config/robot_config/launch_builders/recording.py:38-42:
Mode |
Implementation |
Use Case |
|---|---|---|
Continuous |
|
无语义触发的完整会话日志,保存到 |
Episodic |
|
选择性捕获特定任务,通过 |
启动录制
通过 record:=true launch 参数启用录制。除非显式指定,否则模式默认为 continuous src/robot_config/robot_config/launch_builders/recording.py:65-72。
# Episodic recording for feedback
ros2 launch robot_config robot.launch.py record:=true record_mode:=episodic
# Continuous recording
ros2 launch robot_config robot.launch.py record:=true record_mode:=continuous
来源: src/robot_config/robot_config/launch_builders/recording.py:38-76, src/robot_config/robot_config/launch_builders/recording.py:79-117, src/robot_config/robot_config/launch_builders/recording.py:120-144
Episode Recorder 实现
Action Server 接口
EpisodeRecorderServer 使用 RecordEpisode action 接口管理录制生命周期 src/dataset_tools/dataset_tools/episode_recorder.py:14-17。它使用 rosbag2_py.SequentialWriter 将序列化后的 CDR bytes 写入磁盘 src/dataset_tools/dataset_tools/episode_recorder.py:173-188。
graph LR
subgraph record_cli["record_cli.py"]
SEND["send_goal(prompt)"]
end
subgraph episode_recorder["episode_recorder.py"]
GOAL["handle_goal()"]
EXEC["execute_callback()"]
WRITE["_on_message_received()"]
WRITER_STATE["WriterState"]
TIMER["Timer (Feedback/Timeout)"]
end
SEND -->|"RecordEpisode.Goal"| GOAL
GOAL --> EXEC
EXEC --> TIMER
WRITE -->|"serialize_message"| WRITER_STATE
WRITER_STATE -->|"rosbag2_py.SequentialWriter"| DISK[(".mcap Storage")]
关键组件
单一事实源:基于机器人配置的
contractsection 创建订阅,确保只记录相关 topics src/dataset_tools/dataset_tools/episode_recorder.py:21-22。Caching:recorder 使用内部缓存(默认 100MB)平滑写入突发,通过
max_cache_size配置 src/dataset_tools/dataset_tools/episode_recorder.py:107-107。元数据管理:episode 完成后,server 尝试用 operator prompt 和
lerobot_conversion_fingerprint修补metadata.yaml,供下游处理使用 src/dataset_tools/dataset_tools/episode_recorder.py:29-31。
来源: src/dataset_tools/dataset_tools/episode_recorder.py:8-32, src/dataset_tools/dataset_tools/episode_recorder.py:173-190, src/robot_config/robot_config/launch_builders/recording.py:138-151
数据转换与重采样
处理反馈数据时,需要将原始 bags 转换为适合训练的格式。bag_to_lerobot.py 脚本严格遵循机器人 contract 完成这一过程 src/dataset_tools/dataset_tools/bag_to_lerobot.py:14-15。
转换流水线
加载 Contract:使用
robot_config.contract_utils中的load_contract作为单一事实源 src/dataset_tools/dataset_tools/bag_to_lerobot.py:24-25。扫描并解码:扫描 bag,并使用共享
tensormsgconverters 解码 contract topics src/dataset_tools/dataset_tools/bag_to_lerobot.py:15-16。重采样:使用
resample逻辑,将多个数据流(相机、关节)对齐到 contract 的rate_hzsrc/dataset_tools/dataset_tools/bag_to_lerobot.py:17-18。归一化:根据
robot_config应用关节转换表和夹爪归一化 src/dataset_tools/dataset_tools/bag_to_lerobot.py:106-113。
CLI 用法示例
python3 bag_to_lerobot.py \
--bag /path/to/bag_dir \
--robot-config /path/to/robot_config.yaml \
--out /path/to/lerobot_dataset_root
来源: src/dataset_tools/dataset_tools/bag_to_lerobot.py:6-19, src/dataset_tools/dataset_tools/bag_to_lerobot.py:27-41, src/dataset_tools/dataset_tools/bag_to_lerobot.py:94-114
验证与错误处理
为保证反馈闭环完整性,系统实现了多层验证:
架构验证:
validate_control_mode_config在启动系统前检查模型、观测和外设引用是否存在 src/robot_config/robot_config/contract_builder.py:12-24。外设一致性:
validate_contract_peripheral_consistency确保 contract 引用的相机或传感器确实定义在机器人硬件外设中 src/robot_config/robot_config/generators/contract.py:173-185。Writer 可靠性:
EpisodeRecorderServer将 writer 失败视为当前 episode 的致命错误,记录 traceback 并干净结束 action,避免产生部分或损坏数据 src/dataset_tools/dataset_tools/episode_recorder.py:63-65。
来源: src/robot_config/robot_config/contract_builder.py:12-24, src/robot_config/robot_config/generators/contract.py:173-195, src/dataset_tools/dataset_tools/episode_recorder.py:63-68