ROS2转LeRobot数据集
Rosbag转LeRobot算子用于将ROS bag文件(.bag / .db3)转换为LeRobot标准数据集格式,支持输出LeRobot V2.1与LeRobot V3两种格式。平台支持节卡、千寻、星海图三个类型的本体数据,可直接使用数据生产中生成的轨迹数据集作为输入。
- 核心能力:
- 数据提取:从ROS bag中提取图像、关节状态、控制命令等多路话题数据。
- 时间同步:对多路相机图像与机械臂状态/动作执行时间对齐与帧同步。
- 格式重组:按LeRobot标准目录结构(data/、meta/、videos/ 或 images/)重组数据。
- 任务描述注入:支持通过prompt.json为各episode注入多样化任务指令,或通过统一description 描述任务。
- 批量处理:支持一次提交多个bag目录并行转换,单个失败不影响其他。
- 当前支持机型: 星海图R1(Galaxea R1)、千寻墨子(Moz1)、节卡(Jaka)。
- 输入: 包含ROS bag文件与可选配置文件(config.yaml和prompt.json)。
- 输出: LeRobot V2.1或V3格式数据集目录。
参数配置
平台内置星海图R1(Galaxea R1)、千寻墨子(Moz1)、节卡(Jaka)三种本体配置文件。系统配置加载遵循“数据集配置优先>环境变量设置的内置配置>默认配置“的优先级:当数据集目录下存在 config.yaml 时,优先使用该文件并忽略环境变量;若数据集中无配置文件,则尝试读取环境变量robot以加载对应的内置配置(此时无需上传 config.yaml);若两者均未设置,系统将默认采用星海图R1配置进行处理。
| 参数名 | 是否必填 | 默认值 | 可选值 | 说明 |
|---|---|---|---|---|
| robot | 否 | auto | galaxea、jaka、moz1、auto | 指定机器人型号,使用平台内置支持的三种本体类型之一,在数据集目录中未配置config.yaml文件时使用。填写无效值时自动回退为galaxea。默认选择auto,即回退到config.yaml配置,或进一步回退到galaxea。 |
| flat | 否 | true | true/false | 结果输出是否平铺。若选择true,则不会创建repo_id文件夹,输出数据集直接展示data、meta、videos目录;若设置为false,则按照repo_id来设置。 |
| repo_id | 否 | auto | 任意字符串类型 | 在创建数据处理任务时,用户可添加或修改该环境变量。含义为转换完成的数据集repo_id,未设置时默认按照config.yaml中的repo_id字段获取;默认设置为auto,即读取config.yaml中的值。 |
输入说明
输入数据支持ros2 db3格式数据,db3文件同级可配置转换映射配置文件config.yaml或任务描述文件task.txt。
输入目录结构
每个待转换的bag目录需包含ROS bag文件与配置文件:
<bag_dir>/ # 输入目录 ├── traj_1/ # 轨迹1目录(目录下通常为 *.db3 metadata.yaml) ├── traj_2/ # 轨迹2目录(目录下通常为 *.db3 metadata.yaml) ├── task.txt # 针对所有bag的统一描述(数据生成数据资产默认自带) ├── config.yaml # 放置在数据集一级目录下,数据集与话题映射配置(可选) └── prompt.json # 对每个bag单独,任务描述列表(可选)
平台轨迹生成数据通常采用上述traj_1, traj_2目录平铺模式,推荐用户按照该目录结构组织待转换ros数据。同时,也支持在一级目录下直接存放ros数据文件。
config.yaml配置文件
config.yaml描述bag内话题到LeRobot字段的映射、机械臂初始位姿以及所用处理器。配置顶层必须为dict,且需包含initial、topic_handlers、features、processor四个必需字段。
由于轨迹生成可根据配置生成不同参数的数据集,建议用户使用自定义配置文件完成转换。以下给出平台内置的3个本体的示例配置文件,当用户通过自动生成轨迹使用不同参数生成数据集后(如视频尺寸、FPS参数设置不同时),可修改配置中的参数实现数据转换,用户需将该config.yaml放置在数据集的一级目录下。
processor:
jaka_o3de_processor.JAKAO3DEProcessor # 配置类,jaka本体,请勿修改
fps: 5 # 根据实际视频帧率修改
repo_id: jaka_minicobo_pickplace # 根据输出数据集需要修改
initial:
arm: [1.5, 0.12, 1.06, -2.23, -0.09, -0.9076]
gripper: [100]
vacuum: [0.0]
topic_handlers:
camera:
/camera_external/camera_image_color: observation.images.external
/camera_wrist/camera_image_color: observation.images.wrist
arm_state:
- /joint_states
arm_action:
- /arm_position_controller/commands
gripper_state:
- /gripper_width
gripper_action:
- /gripper_position_controller/commands
features:
observation.state:
dtype: float64
shape:
- 7
names:
axes:
- arm_1
- arm_2
- arm_3
- arm_4
- arm_5
- arm_6
- gripper
action:
dtype: float64
shape:
- 7
names:
axes:
- arm_exp_1
- arm_exp_2
- arm_exp_3
- arm_exp_4
- arm_exp_5
- arm_exp_6
- gripper_exp
observation.images.external: # 根据实际视频的尺寸进行修改
dtype: video
shape:
- 3
- 480
- 640
names:
- channel
- height
- width
observation.images.wrist:
dtype: video
shape:
- 3
- 480
- 640
names:
- channel
- height
- width processor:
moz1_o3de_processor.MOZ1O3DEProcessor # 配置类,moz1本体,请勿修改
fps: 10 # 根据实际视频帧率修改
repo_id: moz1_minicobo_pickplace # 根据输出数据集需要修改
initial:
left_arm: [-0.1571, -0.8727, -0.3491, -1.5708, -0.6109, 0.1396, -0.1222]
right_arm: [0.1571, -0.8727, 0.3491, 1.5708, 0.6109, 0.1396, 0.1222]
torso: [0.0, 0.0, 0.0, 0.0]
gripper: [100]
vacuum: [0.0]
topic_handlers:
camera:
/camera_front/camera_image_color: observation.images.front
/camera_right/camera_image_color: observation.images.wrist_right
/camera_left/camera_image_color: observation.images.wrist_left
arm_state:
- /joint_states
arm_action:
- /left_arm_position_controller/commands
- /right_arm_position_controller/commands
gripper_state:
- /left_gripper_width
- /right_gripper_width
gripper_action:
- /left_gripper_position_controller/commands
- /right_gripper_position_controller/commands
features:
observation.state:
dtype: float64
shape:
- 16
names:
axes:
- left_arm_1
- left_arm_2
- left_arm_3
- left_arm_4
- left_arm_5
- left_arm_6
- left_arm_7
- left_gripper
- right_arm_1
- right_arm_2
- right_arm_3
- right_arm_4
- right_arm_5
- right_arm_6
- right_arm_7
- right_gripper
action:
dtype: float64
shape:
- 16
names:
axes:
- left_arm_exp_1
- left_arm_exp_2
- left_arm_exp_3
- left_arm_exp_4
- left_arm_exp_5
- left_arm_exp_6
- left_arm_exp_7
- left_gripper_exp
- right_arm_exp_1
- right_arm_exp_2
- right_arm_exp_3
- right_arm_exp_4
- right_arm_exp_5
- right_arm_exp_6
- right_arm_exp_7
- right_gripper_exp
observation.images.front: # 根据实际视频的尺寸进行修改
dtype: video
shape:
- 3
- 480
- 640
names:
- channel
- height
- width
observation.images.wrist_left:
dtype: video
shape:
- 3
- 480
- 640
names:
- channel
- height
- width
observation.images.wrist_right:
dtype: video
shape:
- 3
- 480
- 640
names:
- channel
- height
- width processor:
galaxea_o3de_processor.GalaxeaO3DEProcessor # 配置类,galaxea本体,请勿修改
fps: 10 # 根据实际视频帧率修改
repo_id: pick_red_test # 根据输出数据集需要修改
initial:
left_arm: [0.0, 2.0,-0.873, -1.57, -1.117, 1.57]
right_arm: [0.0, 2.0,-0.873, 1.57, 1.117, -1.57]
gripper: [80]
topic_handlers:
camera:
/camera_right/camera_image_color: observation.images.wrist_right
/camera_left/camera_image_color: observation.images.wrist_left
/camera_head_left/camera_image_color: observation.images.front
arm_state:
- /joint_states
arm_action:
- /left_arm_position_controller/commands
- /right_arm_position_controller/commands
gripper_action:
- /left_gripper_position_controller/commands
- /right_gripper_position_controller/commands
features:
observation.state:
dtype: float64
shape:
- 14
names:
- left_arm_1
- left_arm_2
- left_arm_3
- left_arm_4
- left_arm_5
- left_arm_6
- left_gripper
- right_arm_1
- right_arm_2
- right_arm_3
- right_arm_4
- right_arm_5
- right_arm_6
- right_gripper
action:
dtype: float64
shape:
- 14
names:
- left_arm_exp_1
- left_arm_exp_2
- left_arm_exp_3
- left_arm_exp_4
- left_arm_exp_5
- left_arm_exp_6
- left_gripper_exp
- right_arm_exp_1
- right_arm_exp_2
- right_arm_exp_3
- right_arm_exp_4
- right_arm_exp_5
- right_arm_exp_6
- right_gripper_exp
observation.images.front:
dtype: video
shape:
- 3
- 360
- 640
names:
- channel
- height
- width
observation.images.wrist_left:
dtype: video
shape:
- 3
- 360
- 640
names:
- channel
- height
- width
observation.images.wrist_right:
dtype: video
shape:
- 3
- 360
- 640
names:
- channel
- height
- width - 字段说明:
表2 字段说明 字段
类型
必填
说明
initial
dict
是
机械臂初始位姿,用于填充录制开头各传感器通道数据尚未到达时的空隙帧。通常填机器人零位姿态即可;若机器人实际起始位姿非零位,建议填入真实初始角度以保证开头几帧数据准确,见下表。
topic_handlers
dict
是
ROS 话题到处理器类型的映射,见下表。
features
dict
是
LeRobot 特征字段定义,键为特征路径(如observation.state),值为特征配置(含dtype、shape、names)。包括相机特征(observation.images.*)、状态特征(observation.state)和动作特征(action),见下表。
processor
string
是
处理器类路径,当前仅支持galaxea_o3de_processor.GalaxeaO3DEProcessor(星海图R1专用)。
repo_id
string
否
数据集标识符,作为输出子目录名。
fps
int
否
采集帧率,默认10。
description
string
否
统一任务描述文本。
- initial子字段:
子字段
类型
长度
说明
left_arm
list
6
左臂6关节初始角度(弧度),录制开始时左臂各关节的实际角度值。
right_arm
list
6
右臂6关节初始角度(弧度),录制开始时右臂各关节的实际角度值。
gripper
list
1
夹爪初始值,录制开始时夹爪的开合程度。
这些值用于填充时间同步过程中,各传感器通道数据尚未到达时的空隙帧。大多数情况下填零即可;若机器人录制开始时不在零位,建议填入实际起始角度,以保证数据集开头几帧的状态/动作数据准确。
- topic_handlers子字段与消息类型:
topic_handlers
features
对应关系说明
camera 话题名含
/camera_head_left/camera_image_color
observation.images.front
头部相机图像。星海图的第三方视角是/camera_head_left/camera_image_color。节卡的第三方视角为/camera_external/camera_image_color
camera 话题名含
/camera_left/camera_image_color
observation.images.wrist_left
左腕部相机图像
camera 话题名含
/camera_right/camera_image_color
observation.images.wrist_right
右腕部相机图像
arm_state
observation.state
状态:左臂6关节 + 左夹爪1 + 右臂6关节 + 右夹爪1 = 14维(夹爪状态数据包含在 arm_state 话题中)
arm_action + gripper_action
action
动作:左臂6关节 + 左夹爪1 + 右臂6关节 + 右夹爪1 = 14维
- features中必须配置与camera话题对应的图像字段:话题缺失,将会删除相关观测feature信息。
- 其他机器人的camera第三方视角话题可能为/camera_external/camera_image_color;以及节卡为单臂,gripper_action的对应的话题填一个,比如/gripper_position_controller/commands
- observation.state 和action 的shape 取决于机器人配置。星海图R1为14维(左臂6关节+左夹爪1+右臂6关节+右夹爪1)。
task.txt任务描述文件(数据生产后若添加了描述信息会包含该文件)
task.txt为单一字符串,设置后所有episode统一使用该任务描述
The robot uses its right arm to grasp a black-and-white pen from the table and places it into a small black cylindrical container.
此外,平台保留历史prompt.json任务描述文件兼容性,当目录下无task.txt时会检查是否有该文件存在,若存在该文件,任务描述文件可参照该文件,支持多个轨迹使用不同的任务描述(可选)
格式为JSON字典,键为对应轨迹数据文件(db3)在数据集目录中的相对路径,值为该条轨迹的任务描述。
{
"traj_1/traj_1_0.db3":"pick up the red box",
"traj_2/traj_2_0.db3":"place the plug into the socket",
"traj_3/traj_3_0.db3":"grab the gray cylinder"
}
task.txt为单一字符串,设置后所有episode统一使用该任务描述。prompt.json为多轨迹独立任务描述,用户可自由配置。
输出说明
flat=true 模式: ``` <output_dir>/ ├── data/ │ └── chunk-000/ │ ├── episode_000000.parquet │ └── ... ├── meta/ │ ├── info.json │ ├── tasks.jsonl │ ├── episodes.jsonl │ └── episodes_stats.jsonl ├── images/ │ ├── observation.images.front/ │ └── ... └── videos/
如果flat为false且提供repo_id,则转换结果输出到<repo_id>/目录下,格式由目标类型决定(V2.1或 V3),repo_id可通过repo_id环境变量进行设置,若未设置按照config配置文件中获取repo_id。
LeRobot V2.1输出结构
<repo_id>/ ├── data/ │ └── chunk-000/ │ ├── episode_000000.parquet # 轨迹数据 │ ├── episode_000001.parquet │ └── ... ├── meta/ │ ├── info.json # 数据集基本信息(版本、帧率等) │ ├── tasks.jsonl # 任务定义(jsonl 格式) │ ├── episodes.jsonl # Episode 元信息 │ └── episodes_stats.jsonl # Episode 统计信息 ├── images/ # 图像数据(图片序列,可选) │ ├── observation.images.front/ │ ├── observation.images.wrist_left/ │ └── observation.images.wrist_right/ └── videos/ # 视频数据(V2.1 必需字段)
LeRobot V3输出结构
<repo_id>/
├── data/
│ └── chunk-000/
│ ├── file_000000.parquet
│ ├── file_000001.parquet
│ └── ...
├── meta/
│ ├── info.json # 数据集基本信息(版本、帧率、特征等)
│ ├── stats.json # 数据统计信息
│ ├── tasks.parquet # 任务定义
│ └── episodes/ # Episode 元信息
└── videos/ # 视频数据
├── observation.images.front/
├── observation.images.wrist_left/
└── observation.images.wrist_right/