Skip to content

fix(teleop): stop sim joints 2 and 3 pinning in the 3D viewer - #86

Open
cn0303 wants to merge 2 commits into
huggingface:mainfrom
cn0303:fix/teleop-urdf-joint-mapping
Open

fix(teleop): stop sim joints 2 and 3 pinning in the 3D viewer#86
cn0303 wants to merge 2 commits into
huggingface:mainfrom
cn0303:fix/teleop-urdf-joint-mapping

Conversation

@cn0303

@cn0303 cn0303 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

During teleop the 3D URDF viewer's shoulder_lift (Pitch) and elbow_flex
(Elbow) joints pinned at their limits and stopped tracking the real arm. The
other four joints tracked fine.

The cause was a _SO101_URDF_CORRECTIONS table that ran only those two joints
through a motor_at_urdf_zero offset of about 110 degrees before converting to
radians. That offset pushed the value past the URDF's symmetric limit of about
100 degrees, where urdf-loader's setJointValue clamps it, so the joint
pinned. A live trace confirmed it: shoulder_lift -101 -> Pitch -211 (clamped to
-100), elbow_flex +97 -> Elbow +186 (clamped to +90).

The fix

SO101FollowerConfig (and the leader) default use_degrees=True, so
observation["<motor>.pos"] is already the joint angle in degrees about the
calibration center, which is the same zero the URDF is authored around. The four
joints that always tracked prove it: they map degrees to radians directly with no
offset. So the fix deletes _SO101_URDF_CORRECTIONS (and the now-unused
_STS3215_MAX_RES) and maps every joint the same way:

angle_degrees = observation[motor_key]
joint_positions[urdf_joint_name] = angle_degrees * math.pi / 180.0

The gripper is unchanged (its 0 to 100 range already lands inside the Jaw limit).
The throttled [joint-debug] log is kept as a live verification aid.

Testing

ruff check and ruff format green. Backend imports cleanly. pytest: 198 passed;
the only 3 failures are pre-existing on main and unrelated to teleop (Windows
dataset_repair timestamp and two jobs pid/checkpoint tests), confirmed by running
them against a clean main.

Hardware-verified on Windows 11 (SO-101 leader plus follower, lerobot 0.6.0):
moving the leader through its range, Pitch and Elbow track the real arm in the 3D
viewer and no longer pin, matching the other four joints, with no sign flip.

cn0303 added 2 commits July 25, 2026 23:21
shoulder_lift (Pitch) and elbow_flex (Elbow) pinned at the URDF limits in the
3D sim and stopped tracking the real arm. The _SO101_URDF_CORRECTIONS table
subtracted a ~110° "URDF zero" offset from just these two joints, which shoved
their value past the joint's ±100° URDF limit, so urdf-loader clamped them
(live trace: shoulder_lift +/-101° -> Pitch -211°, clamped to -100°).

lerobot drives the SO-101 with use_degrees=True by default, so each
observation["<motor>.pos"] is already the joint angle in degrees about the
calibration center — the same zero the URDF is authored around. The four
joints that always tracked correctly prove the point: they map degrees
straight to radians with no offset. shoulder_lift and elbow_flex need the same
treatment, not a special correction. Drop the table so every joint maps
identically.
Add a unit test that feeds a fake observation and asserts every joint maps
straight to radians (deg * pi/180). It supplies a calibration that would have
triggered the removed shoulder_lift/elbow_flex correction, so it fails against
the old offset table and passes now that all joints map identically.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant