
# 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或Galaxea A1Z）、千寻墨子（Moz1）、节卡（Jaka）、青龙（Azureloong）。
- **输入：** 包含ROS bag文件与可选配置文件（config.yaml和prompt.json）。
- **输出：** LeRobot V2.1或V3格式数据集目录。如果用户输出选的OBS路径，预置算法会判断是否有冲突目录，如果有冲突目录，则创建一个新目录并将结果放在新目录下。
#### 参数配置
平台内置星海图R1（Galaxea R1）、千寻墨子（Moz1）、节卡（Jaka）三种本体配置文件。系统配置加载遵循"数据集配置优先＞环境变量设置的内置配置＞默认配置"的优先级：当数据集目录下存在 config.yaml 时，优先使用该文件并忽略环境变量；若数据集中无配置文件，则尝试读取环境变量robot以加载对应的内置配置（此时无需上传 config.yaml）；若两者均未设置，系统将默认采用星海图R1配置进行处理。
表1参数说明 
| 参数名     | 是否必填 | 默认值  | 可选值                                           | 说明                                                                                                                 |
|:---|:---|:---|:---|:---|
| robot   | 否    | auto | galaxea、galaxea_a1z、jaka、moz1、azureloong、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单独，任务描述列表（可选）
```
![](https://support.huaweicloud.com/usermanual-cloudrobo/public_sys-resources/note_3.0-zh-cn.png)
平台轨迹生成数据通常采用上述traj_1, traj_2目录平铺模式，推荐用户按照该目录结构组织待转换ros数据。同时，也支持在一级目录下直接存放ros数据文件。
#### **config.yaml**配置文件
config.yaml描述bag内话题到LeRobot字段的映射、机械臂初始位姿以及所用处理器。配置顶层必须为dict，且需包含initial、topic_handlers、features、processor四个必需字段。
由于轨迹生成可根据配置生成不同参数的数据集，建议用户使用自定义配置文件完成转换。以下给出平台内置的6个本体的示例配置文件，当用户通过[自动生成轨迹](https://support.huaweicloud.com/usermanual-cloudrobo/cloudrobo_02_0067.html)使用不同参数生成数据集后（如视频尺寸、FPS参数设置不同时），可修改配置中的参数实现数据转换，用户需将该config.yaml放置在数据集的一级目录下。
- **节卡（jaka）**
  ```
  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
  ```
  
- **千寻（moz1）**
  ```
  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
  ```
  
- **星海图（galaxea r1）**
  ```
  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
  ```
  
  
- **星海图（galaxea a1z）**
  ```
  processor:
    a1z_o3de_processor.A1ZO3DEProcessor
  fps: 30
  repo_id: a1z_demo
  initial:
    arm: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    gripper: [100.0]
    vacuum: [0.0]
  topic_handlers:
    camera:
      /wrist_camera/camera_image_color: observation.images.wrist
      /external_camera/camera_image_color: observation.images.external
    arm_state:
      - /joint_states
    arm_action:
      - /arm_position_controller/commands
    gripper_state:
      - /gripper_width
  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.wrist:
      dtype: video
      shape:
        - 3
        - 480
        - 640
      names:
        - channel
        - height
        - width
    observation.images.external:
      dtype: video
      shape:
        - 3
        - 720
        - 1280
      names:
        - channel
        - height
        - width
  ```
  
- **青龙（azureloong）**
  ```
  processor:
    azureloong_o3de_processor.AzureLoongO3DEProcessor
  fps: 10
  repo_id: azureloong_demo
  initial:
    left_arm: [0.0174533, -0.977384,1.48353,2.35619, -1.39626, -1.13446,0.959931]
    right_arm: [0.0174533, -0.977384,-1.48353,2.35619, 1.39626, -1.13446,-0.959931]
    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:
      - /qinglong_controller/follow_joint_trajectory/_action/feedback
    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
  ```
  

- **字段说明：**
  表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** **子字段：**
  表3initial子字段说明 
  | **子字段**   | **类型** | **长度** | **说明**                          |
  |:---|:---|:---|:---|
  | left_arm  | list   | 6      | 左臂6关节初始角度（弧度），录制开始时左臂各关节的实际角度值。 |
  | right_arm | list   | 6      | 右臂6关节初始角度（弧度），录制开始时右臂各关节的实际角度值。 |
  | gripper   | list   | 1      | 夹爪初始值，录制开始时夹爪的开合程度。             |
     
  ![](https://support.huaweicloud.com/usermanual-cloudrobo/public_sys-resources/note_3.0-zh-cn.png)
  这些值用于填充时间同步过程中，各传感器通道数据尚未到达时的空隙帧。大多数情况下填零即可；若机器人录制开始时不在零位，建议填入实际起始角度，以保证数据集开头几帧的状态/动作数据准确。
  
- **topic_handlers** **子字段与消息类型：**
  
  | **topic_handlers**                                                                                  | **features**                   | **对应关系说明**                                                                                                                                                                                       |
  |:---|:---|:---|
  | camera 话题名含 ``` /camera_head_left/camera_image_color ```  | observation.images.front       | 头部相机图像。星海图r1的第三方视角是/camera_head_left/camera_image_color。星海图的a1z的第三方视角/external_camera/camera_image_color。节卡的第三方视角为/camera_external/camera_image_color。青龙的第三方视角为/camera_front/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维                                                                                                                                                             |
     
  ![](https://support.huaweicloud.com/usermanual-cloudrobo/public_sys-resources/caution_3.0-zh-cn.png)
  - features中必须配置与camera话题对应的图像字段：话题缺失，将会删除相关观测feature信息。
  
  - 其他机器人的camera第三方视角话题可能为/camera_external/camera_image_color或/head_camera/camera_image_color；节卡为单臂，gripper_action的对应的话题填一个，比如/gripper_position_controller/commands；以及有些本体单臂的手腕相机话题/wrist_camera/camera_image_color
  
  - 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"
}
```
![](https://support.huaweicloud.com/usermanual-cloudrobo/public_sys-resources/note_3.0-zh-cn.png)
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/
```
