Train and deploy your first policy
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ DEFINE │ │ RECORD │ │ CONVERT │ │ TRAIN │ │ DEPLOY │
│ Contract │────▶│ Demos │────▶│ Dataset │────▶│ Policy │────▶│ on Robot │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
We run the full pipeline once on a two-joint arm with one camera. Substitute your own topics and joint names as you type. You need a ROS 2 robot you can teleoperate, a camera stream, and a GPU for training.
1. Define a contract
# my_contract.yaml
robot_type: my_robot
robot_interface: ros2
fps: 30
observations:
observation.state:
channel: {topic: /joint_states, type: sensor_msgs/msg/JointState}
align: {strategy: hold, timeline: header}
select: [position.j1, position.j2]
observation.images.cam:
channel: {topic: /camera/image_raw/compressed,
type: sensor_msgs/msg/CompressedImage}
align: {strategy: hold, timeline: header}
apply: [resize: [480, 640]]
actions:
action:
channel: {topic: /cmd, type: sensor_msgs/msg/JointState}
align: {strategy: hold, timeline: header}
select: [position.j1, position.j2]
If your driver does not stamp its messages, write timeline: receive instead of
timeline: header everywhere. Check with
ros2 topic echo /joint_states --field header.stamp --once: a sec of 0 means
unstamped.
2. Record demonstrations
# Terminal 1: Start the recorder
ros2 launch rosetta episode_recorder_launch.py contract_path:=my_contract.yaml
# Terminal 2: Keyboard controller (r=start, s=save, d=discard, t=set prompt, q=quit)
ros2 run rosetta episode_keyboard_node
Teleoperate the robot through a short task, save, and repeat. Ten episodes is enough to close the loop, and the policy will be clumsy. Each bag is one episode.
3. Convert bags to a dataset
rosetta_port \
--raw-dir ./datasets/bags \
--contract my_contract.yaml \
--repo-id my-org/my-dataset \
--root ./datasets/lerobot
ls datasets/lerobot/my-org/my-dataset/meta/ shows info.json, tasks.parquet,
and rosetta_contract.yaml. That last one is the contract from step 1, now
travelling inside the dataset.
4. Train
lerobot-train \
--dataset.repo_id=my-org/my-dataset \
--policy.type=act \
--output_dir=outputs/train/my_policy
Training is stock LeRobot, and this is the long step.
5. Deploy
# Terminal 1: Start the policy runner
ros2 launch rosetta policy_runner_launch.py \
contract_path:=my_contract.yaml \
pretrained_name_or_path:=outputs/train/my_policy/checkpoints/last/pretrained_model
# Terminal 2: Run the policy
ros2 action send_goal /run_policy \
rosetta_interfaces/action/RunPolicy "{prompt: 'pick up the red block'}"
Use the same prompt you recorded with. Ctrl-C stops execution. The robot now moves by itself, through the contract we wrote in step 1.