fix(wbt): correct velocities, body poses and clip boundaries in default-pose transitions - #202
Open
tkevinbest wants to merge 1 commit into
Open
tkevinbest wants to merge 1 commit into
tkevinbest wants to merge 1 commit into
Conversation
tkevinbest
marked this pull request as draft
September 11, 2026 19:53
tkevinbest
marked this pull request as ready for review
September 11, 2026 22:11
tkevinbest
marked this pull request as draft
September 14, 2026 16:43
tkevinbest
force-pushed
the
fix/wbt-transition-velocities-and-fk
branch
from
September 14, 2026 19:29
3327bde to
e7edeec
Compare
…lt-pose transitions The lead-in/lead-out segment the WBT command term can splice between the robot's default pose and a motion clip stored velocities that were not the derivative of its own positions, and body poses that were not forward-kinematics-consistent with its own joint angles. With motion_dir it also registered each transition as a separate motion, so step() resampled a new clip at exactly the handoff frame. Joint angles and the root position now come from a cubic Hermite that yields position and its exact derivative from one polynomial, with both endpoints at rest so the joint path is monotone between the two poses. Root rotation runs the same cubic in rotation-vector space. Body poses are per-frame forward kinematics of those joint angles, batched across environments and clips; body velocities are differenced from them, referenced to each body's centre of mass to match what a motion file stores. Every clip gets its own transition, spliced into that clip's own frame interval. Also fixes two scatter-map defects on the same path: motion body slots the robot does not have were zero-filled, yielding zero quaternions, and an aliased foot contact point overwrote its ankle link, which is a tracked body. Both flags remain off by default and no shipped config sets them.
tkevinbest
force-pushed
the
fix/wbt-transition-velocities-and-fk
branch
from
September 14, 2026 19:55
e7edeec to
4440570
Compare
Contributor
Author
Contributor
Author
|
Also a simple video showing the results. No appending/prepending is on the far left, the pre-PR behavior is in the middle, and the post PR behavior is on the right. There's minimal visual difference between middle and right, but the velocity references fed to the policy are now correctly differentiated. wbt_transition_boxlift_3pane.mp4 |
tkevinbest
marked this pull request as ready for review
September 14, 2026 19:57
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

MotionCommandcan splice a synthetic lead-in and lead-out between the robot's default pose and a retargeted clip, so a whole-body-tracking policy has something trackable at the clip boundary instead of a step change. It is gated byenable_default_pose_prepend/enable_default_pose_append, both default off, and no shipped config turns either on. That is also why the path had zero test coverage and seven defects.What was wrong:
motion_dir, the transition was registered as its own motion interval.step()resamples a new clip the instanttime_stepsreaches a motion's end index, so the robot played the lead-in and was teleported to a random clip exactly at the handoff. Only the first and last clip of the concatenation got a transition at all.body_pos_wat the link origin andbody_lin_vel_wat the CoM). Up to 16 cm of offset on this robot.Joint angles and root position now come from a cubic Hermite segment that returns position and its analytic derivative from one polynomial, so the stored velocity is the derivative of the stored position by construction. Root rotation runs the same cubic in rotation-vector space, with the endpoint derivative mapped through the inverse left Jacobian of SO(3). Body poses are per-frame forward kinematics of the interpolated joint angles, batched across environments and clips rather than looped frame by frame. Body velocities are finite-differenced from those poses and referenced to each body's CoM. Every clip gets its own lead-in and lead-out, spliced into that clip's own frame interval, so
time_stepswalks from the transition straight into the clip's frames without a reset. The math lives in a new pure-math module,utils/transition_trajectory.py, with no env or simulator imports. FK stays IsaacSim-only, as before, and there are no new config knobs.Both endpoints are at rest, which makes the cubic a smoothstep and the joint path monotone between the two poses. That is a deliberate trade. Matching the clip's actual arrival velocity would make the seam velocity-continuous, but it forces the path out past the target and back whenever the net displacement is small.
Verification: about 1500 of the 2400 added lines are tests.
utils/tests/test_transition_trajectory.pycovers the math (36 tests, no sim);test_wbt_transition_fields.py,test_wbt_transition_splice.pyandtest_wbt_motion_scatter.pycover the emitted fields, the splice and the body scatter underno_sim; and an IsaacSim harness asserts the root pose round-trips through FK, that distinct joint configurations give distinct body poses, and that the batched result matches looping one frame at a time. Batched-vs-per-frame agreement is 2.9e-06, which is what rules out the stale-cache failure mode, and link lengths hold to 2.4e-07 m while the root travels 64 cm. Full runs:no_sim603 passed, IsaacSim 63 passed, pre-commit and mypy clean. On a 19 s 29-DoF clip (959 frames at 50 fps) the emitted joint angles arrive monotonically at the clip's first frame with no detour, against a stored velocity that is the derivative of the plotted position. A 300-iteration training run on this path completed with no NaNs.Known limitations: feet can slide during the transition, and the default-pose root height still comes from the nominal spawn height rather than from FK, which is entangled with foot anchoring.