Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
- Fix `ModelBuilder.add_usd()` marking a `guide`-purpose collider visible when it has a bound render material. Such a collider is not viewport geometry, and the extra `VISIBLE` flag left it drawn by the viewer's visual toggle instead of its collision toggle. `force_show_colliders` still reveals it.
- Fix USD capsule, cylinder, and cone visual and site scaling to follow the authored primitive axis.
- Fix MJCF contact pairs ignoring properties inherited from pair default classes.
- Fix `ArticulationView.is_fixed_base` for roots with zero effective degrees of freedom, including fully locked D6 joints. (#3727)
- Fix USD plane visual width and length to scale along the axes defined by the `UsdGeomPlane` schema, and orient X- and Y-axis plane visuals along the authored axis.
- Validate `ArticulationView` mask shapes and devices before launching selection kernels. (#3448)
- Exclude active particles with non-finite positions from rebuildable `SolverImplicitMPM` sparse-grid packing.
Expand Down
3 changes: 2 additions & 1 deletion newton/_src/utils/selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,8 +754,9 @@ def __init__(
raise ValueError("Articulations are not identical")

self.root_joint_type = root_joint_types[0][0]
root_joint_dof_count = int(model_joint_qd_start[arti_joint_begin + 1] - model_joint_qd_start[arti_joint_begin])
# fixed base means that all linear and angular degrees of freedom are locked at the root
self.is_fixed_base = self.root_joint_type == JointType.FIXED
self.is_fixed_base = root_joint_dof_count == 0
Comment thread
jcarius-nv marked this conversation as resolved.
# floating base means that all linear and angular degrees of freedom are unlocked at the root
# (though there might be constraints like distance)
self.is_floating_base = self.root_joint_type in (JointType.FREE, JointType.DISTANCE)
Expand Down
27 changes: 27 additions & 0 deletions newton/tests/test_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,33 @@ def test_fixed_joint_only_articulation(self):
self.assertEqual(view.get_dof_velocities(state).shape, (1, 1, 0))
self.assertEqual(view.get_dof_forces(control).shape, (1, 1, 0))

def test_root_base_classification_uses_dof_count(self):
"""Classify zero-DOF roots as fixed while preserving floating roots."""
cases = (
("fixed", True, False),
("locked_d6", True, False),
("free", False, True),
)

for root_kind, expected_fixed, expected_floating in cases:
with self.subTest(root_kind=root_kind):
builder = newton.ModelBuilder()
root = builder.add_link(label="root")

if root_kind == "fixed":
root_joint = builder.add_joint_fixed(parent=-1, child=root)
elif root_kind == "locked_d6":
root_joint = builder.add_joint_d6(parent=-1, child=root)
else:
root_joint = builder.add_joint_free(parent=-1, child=root)

builder.add_articulation([root_joint], label=root_kind)
model = builder.finalize(device="cpu")
view = ArticulationView(model, root_kind)

self.assertEqual(view.is_fixed_base, expected_fixed)
self.assertEqual(view.is_floating_base, expected_floating)

def test_labels_preserve_full_paths(self):
"""Two-finger gripper whose distal bodies, finger joints, and tip
shapes each share a colliding leaf name. ``*_names`` attributes
Expand Down
Loading