@@ -8,6 +8,7 @@ This repository contains a modified fork of LeRobot with OpenArm-specific enhanc
88
99- ** Bimanual OpenArm Support** : Control two OpenArm follower robots simultaneously
1010- ** Gamepad Teleoperation** : PlayStation/Xbox controller support for intuitive joint control
11+ - ** Leader Arm Teleoperation** : Bimanual leader arm control for high-quality demonstration collection
1112- ** Hardware Calibration Sync** : Proper integration with OpenArm's hardware calibration system
1213- ** Velocity & Torque Support** : Full action space including position, velocity, and torque
1314- ** Recording & Replay** : Compatible with LeRobot's dataset recording and policy training
@@ -88,48 +89,87 @@ If the arms move to awkward or asymmetric positions, proceed with recalibration.
8889** WARNING** : This will overwrite the existing calibration. Only do this if verification above failed.
8990
9091``` bash
91- # Calibrate right arm (can0)
92+ # Calibrate follower right arm (can0)
9293openarm-can-zero-position-calibration --canport can0 --arm-side right_arm
9394
94- # Calibrate left arm (can1)
95+ # Calibrate follower left arm (can1)
9596openarm-can-zero-position-calibration --canport can1 --arm-side left_arm
96- ```
9797
98- This tool:
99- 1 . Moves each joint to its mechanical stops
100- 2 . Calculates the center position
101- 3 . Sets that as zero in motor memory
102- 4 . Stores the calibration permanently
98+ # Calibrate leader right arm (can2)
99+ openarm-can-zero-position-calibration --canport can2 --arm-side right_arm
100+
101+ # Calibrate leader left arm (can3)
102+ openarm-can-zero-position-calibration --canport can3 --arm-side left_arm
103+ ```
103104
104105### Sync Calibration with LeRobot
105106
106- ** REQUIRED** : After verifying or recalibrating hardware, sync LeRobot's calibration files with the hardware zero positions :
107+ ** REQUIRED** : After verifying or recalibrating hardware, sync LeRobot's calibration files:
107108
108109``` bash
109110# Delete old LeRobot calibration files (if any)
110- rm -rf ~ /.cache/huggingface/lerobot/calibration/robots/bi_openarm_follower/
111+ rm -rf ~ /.cache/huggingface/lerobot/calibration/
112+
113+ # Calibrate follower arms
114+ lerobot-calibrate \
115+ --robot.type=openarm_follower \
116+ --robot.port=can0 \
117+ --robot.side=right \
118+ --robot.id=my_openarm_follower_right
119+
120+ lerobot-calibrate \
121+ --robot.type=openarm_follower \
122+ --robot.port=can1 \
123+ --robot.side=left \
124+ --robot.id=my_openarm_follower_left
125+
126+ # Calibrate leader arms
127+ lerobot-calibrate \
128+ --teleop.type=openarm_leader \
129+ --teleop.port=can2 \
130+ --teleop.id=my_openarm_leader_right
131+
132+ lerobot-calibrate \
133+ --teleop.type=openarm_leader \
134+ --teleop.port=can3 \
135+ --teleop.id=my_openarm_leader_left
136+ ```
111137
112- # Run calibration sync script
113- # This moves arms to hardware zero and creates LeRobot calibration files
114- python scripts/sync_calibration.py
138+ ### Verify CAN Interfaces
139+
140+ After plugging in USB-CAN adapters, verify they're configured:
141+
142+ ``` bash
143+ ip link show can0 can1 can2 can3
115144```
116145
117- ** What this does:**
118- 1 . Uses OpenArm C++ library to move arms to hardware-calibrated zero
119- 2 . Connects LeRobot and sets current position as LeRobot's zero
120- 3 . Saves calibration files to ` ~/.cache/huggingface/lerobot/calibration/ `
146+ All four interfaces should show as UP. If not, unplug and replug the USB-CAN adapters.
121147
148+ ** CAN port mapping:**
149+ - ` can0 ` — follower right arm
150+ - ` can1 ` — follower left arm
151+ - ` can2 ` — leader right arm
152+ - ` can3 ` — leader left arm
122153
123- ### Verify CAN Interfaces
154+ ### Camera Setup
124155
125- After plugging in USB-CAN adapters, verify they're configured :
156+ USB wrist cameras are identified by physical USB port using udev symlinks. After plugging in cameras :
126157
127158``` bash
128- # Check CAN interfaces
129- ip link show can0 can1
159+ # Verify symlinks are created
160+ ls -la /dev/video-wrist-*
161+ # Expected:
162+ # /dev/video-wrist-left -> videoX
163+ # /dev/video-wrist-right -> videoX
164+ ```
165+
166+ If symlinks are missing, check the udev rules file at ` /etc/udev/rules.d/99-openarm-cameras.rules ` .
130167
131- # Should show both as UP and RUNNING
132- # If not, unplug and replug USB-CAN adapters (auto-configures via udev)
168+ Get the RealSense chest camera serial number:
169+
170+ ``` bash
171+ source ~ /humanoids/lerobot_env/bin/activate
172+ python3 -c " import pyrealsense2 as rs; ctx = rs.context(); print([d.get_info(rs.camera_info.serial_number) for d in ctx.devices])"
133173```
134174
135175### Manual CAN Configuration (if needed)
@@ -187,6 +227,55 @@ lerobot-teleoperate \
187227- ** Triangle/Y** : Print current arm position
188228- ** Circle/B** : Exit teleoperation
189229
230+ ### Leader Arm Teleoperation
231+
232+ Leader arm teleoperation produces significantly smoother demonstrations than gamepad control and is recommended for high-quality data collection.
233+
234+ ** CAN port mapping for leader arm setup:**
235+ - ` can0/can1 ` — follower right/left arms
236+ - ` can2/can3 ` — leader right/left arms
237+
238+ ** Set camera formats before starting:**
239+ ``` bash
240+ v4l2-ctl --device=/dev/video-wrist-left --set-fmt-video=width=640,height=480,pixelformat=MJPG
241+ v4l2-ctl --device=/dev/video-wrist-right --set-fmt-video=width=640,height=480,pixelformat=MJPG
242+ ```
243+
244+ ** Teleoperate with cameras:**
245+ ``` bash
246+ lerobot-teleoperate \
247+ --robot.type=bi_openarm_follower \
248+ --robot.left_arm_config.port=can1 \
249+ --robot.left_arm_config.side=left \
250+ --robot.left_arm_config.cameras=" { \
251+ chest: {type: intelrealsense, serial_number_or_name: YOUR_SERIAL, width: 848, height: 480, fps: 30}, \
252+ wrist_left: {type: opencv, index_or_path: /dev/video-wrist-left, width: 640, height: 480, fps: 30, fourcc: MJPG} \
253+ }" \
254+ --robot.right_arm_config.port=can0 \
255+ --robot.right_arm_config.side=right \
256+ --robot.right_arm_config.cameras=" { \
257+ wrist_right: {type: opencv, index_or_path: /dev/video-wrist-right, width: 640, height: 480, fps: 30, fourcc: MJPG} \
258+ }" \
259+ --robot.id=my_bimanual_follower \
260+ --teleop.type=bi_openarm_leader \
261+ --teleop.left_arm_config.port=can3 \
262+ --teleop.right_arm_config.port=can2 \
263+ --teleop.id=my_bimanual_leader \
264+ --teleop.left_arm_config.position_kp=" [120,120,60,20,12,15,12,2]" \
265+ --teleop.left_arm_config.position_kd=" [2,2,1.0,0.5,0.1,0.1,0.1,0.02]" \
266+ --teleop.right_arm_config.position_kp=" [120,120,60,20,12,15,12,2]" \
267+ --teleop.right_arm_config.position_kd=" [2,2,1.0,0.5,0.1,0.1,0.1,0.02]" \
268+ --robot.left_arm_config.position_kp=" [240,240,120,40,24,31,25,5]" \
269+ --robot.left_arm_config.position_kd=" [5,5,1.5,0.3,0.3,0.3,0.3,0.05]" \
270+ --robot.right_arm_config.position_kp=" [240,240,120,40,24,31,25,5]" \
271+ --robot.right_arm_config.position_kd=" [5,5,1.5,0.3,0.3,0.3,0.3,0.05]" \
272+ --display_data=true
273+ ```
274+
275+ ** Tuning notes:**
276+ - ` teleop ` kp/kd values control leader arm stiffness — lower values make the leader easier to backdrive
277+ - ` robot ` kp/kd values control follower arm responsiveness
278+
190279### Common Issues
191280
192281** Controller not responding:**
@@ -201,6 +290,8 @@ lerobot-teleoperate \
201290
202291## Recording Demonstrations
203292
293+ ### Gamepad Recording
294+
204295``` bash
205296export HF_HUB_OFFLINE=1
206297
@@ -214,18 +305,62 @@ lerobot-record \
214305 --teleop.joint_velocity_scale=60.0 \
215306 --dataset.repo_id=local/my_task \
216307 --dataset.single_task=" Task description" \
217- --dataset.fps=60 \
308+ --dataset.fps=30 \
218309 --dataset.num_episodes=50 \
219310 --dataset.episode_time_s=30 \
220311 --dataset.reset_time_s=10 \
221312 --dataset.push_to_hub=false
222313```
223314
315+ ### Leader Arm Recording
316+
317+ ``` bash
318+ export HF_HUB_OFFLINE=1
319+
320+ v4l2-ctl --device=/dev/video-wrist-left --set-fmt-video=width=640,height=480,pixelformat=MJPG
321+ v4l2-ctl --device=/dev/video-wrist-right --set-fmt-video=width=640,height=480,pixelformat=MJPG
322+
323+ lerobot-record \
324+ --robot.type=bi_openarm_follower \
325+ --robot.left_arm_config.port=can1 \
326+ --robot.left_arm_config.side=left \
327+ --robot.left_arm_config.cameras=" { \
328+ chest: {type: intelrealsense, serial_number_or_name: YOUR_SERIAL, width: 848, height: 480, fps: 30, use_depth: true}, \
329+ wrist_left: {type: opencv, index_or_path: /dev/video-wrist-left, width: 640, height: 480, fps: 30, fourcc: MJPG} \
330+ }" \
331+ --robot.right_arm_config.port=can0 \
332+ --robot.right_arm_config.side=right \
333+ --robot.right_arm_config.cameras=" { \
334+ wrist_right: {type: opencv, index_or_path: /dev/video-wrist-right, width: 640, height: 480, fps: 30, fourcc: MJPG} \
335+ }" \
336+ --robot.id=my_bimanual_follower \
337+ --teleop.type=bi_openarm_leader \
338+ --teleop.left_arm_config.port=can3 \
339+ --teleop.right_arm_config.port=can2 \
340+ --teleop.id=my_bimanual_leader \
341+ --teleop.left_arm_config.position_kp=" [120,120,60,20,12,15,12,2]" \
342+ --teleop.left_arm_config.position_kd=" [2,2,1.0,0.5,0.1,0.1,0.1,0.02]" \
343+ --teleop.right_arm_config.position_kp=" [120,120,60,20,12,15,12,2]" \
344+ --teleop.right_arm_config.position_kd=" [2,2,1.0,0.5,0.1,0.1,0.1,0.02]" \
345+ --dataset.repo_id=local/my_task \
346+ --dataset.single_task=" Task description" \
347+ --dataset.fps=30 \
348+ --dataset.num_episodes=100 \
349+ --dataset.episode_time_s=40 \
350+ --dataset.reset_time_s=10 \
351+ --dataset.push_to_hub=false \
352+ --display_data=false
353+ ```
354+
355+ To resume adding episodes to an existing dataset add ` --resume=true ` to the command.
356+
224357** Recording Parameters:**
225- - ` --dataset.fps ` : Recording framerate (60 fps recommended for smooth playback)
226- - ` --dataset.num_episodes ` : Number of demonstrations
227- - ` --dataset.episode_time_s ` : Maximum episode duration
228- - ` --dataset.reset_time_s ` : Time to reset between episodes
358+ - ` --dataset.fps ` : Recording framerate (30 fps recommended for leader arm)
359+ - ` --dataset.num_episodes ` : Number of demonstrations to collect
360+ - ` --dataset.episode_time_s ` : Maximum episode duration in seconds
361+ - ` --dataset.reset_time_s ` : Time between episodes for scene reset
362+ - ` --dataset.push_to_hub ` : Set to false for local-only storage
363+ - ` --resume ` : Set to true to append episodes to an existing dataset
229364
230365** Dataset location:** ` ~/.cache/huggingface/lerobot/local/ `
231366
0 commit comments