Conversation
MultibodyJoint::set_free_pos copied the root's translation into coords.x/y and its rotation into joint_rot, but not into the angular coordinate coords.z. On the next integrate, a joint with one free angular DoF rebuilds joint_rot from that coordinate, so a dynamic root lost its initial rotation on the first step while keeping its position, and the whole articulation came out rotated about the root. 3D is unaffected: with three free angular DoFs, integrate composes onto joint_rot instead of rebuilding it from the coordinates. Adds a regression test for both dimensions. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
Bug
In 2D, a multibody whose root is a dynamic rigid-body loses the root's rotation on the first step. Its position is kept, so the whole articulation ends up rotated about the root.
MultibodyJoint::set_free_pos(used when a dynamic root takes the body's pose) copies the translation intocoords.x/coords.yand the rotation intojoint_rot, but not into the angular coordinatecoords.z. On the nextintegrate, a joint with one free angular DoF rebuildsjoint_rotfrom that coordinate:so the root's rotation becomes
0 + angvel * dt.3D is unaffected: with three free angular DoFs,
integratecomposes ontojoint_rotrather than rebuilding it from the coordinates.Fix
One line in the
dim2branch ofset_free_pos:self.coords.z = pos.rotation.angle();Test
multibody_dynamic_root_keeps_its_initial_rotation(inphysics_pipeline/test.rs, both dimensions): a dynamic root at 0.7 rad with one revolute multibody joint to a child, one step, and the root's rotation must be unchanged. Before the fix in 2D it changes by exactly 0.7 rad. In 3D it passes with or without the change, which confirms the 3D case.cargo test -p rapier2d(217) andcargo test -p rapier3d(444) pass, andcargo fmt -- --checkis clean. I did not run the fullrun-ci-checks.sh(parallel/SIMD feature builds, release-mode determinism tests, examples), and I did not run the testbed examples. Clippy onrapier2d/rapier3dreports two warnings, both in files this PR doesn't touch.How I found it
I was evaluating multibody joints for a 2D articulated robot: a 5-capsule chain converted from impulse joints came out rotated at the first step by exactly its root's initial angle (0.245 rad with the root at one end of the chain, 1.57 rad with the root in the middle). I traced it to this. Until it's fixed, on released versions the workaround is
multibody.link_mut(0).unwrap().joint.apply_displacement(&[0.0, 0.0, root_angle])after inserting the joints.AI disclosure
I used Claude Code (Anthropic) to help investigate this, and to write the fix and the test. I reviewed the diff, and ran the tests myself against a checkout of current
master(846c463). I did not see an AI policy in CONTRIBUTING.md, so please tell me if you'd like this handled differently.🤖 Generated with Claude Code