Fix cylinder vs plane collisions#831
Conversation
📝 WalkthroughWalkthroughCylinder-plane contact now returns an explicit validity flag and callers gate processing on it; cylinder is excluded from effective-radius calculation in geo data. A test inserts a cylinder (free joint) and updates expected positions; solver njmax increased. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Broadphase
participant Narrowphase as cylinder_plane_collision
participant Pipeline as handle_contact_pairs
Broadphase->>Narrowphase: Request contact info (cylinder, plane)
Note right of Narrowphase #DDEBF7: compute (pA, pB, normal, distance, valid)
Narrowphase-->>Broadphase: Return contact tuple
Broadphase->>Pipeline: Dispatch contact tuple
alt valid == true
Pipeline->>Pipeline: Continue full contact processing
else valid == false
Note right of Pipeline #FDE9E9: Skip / early return for this contact
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
newton/_src/geometry/kernels.py (2)
1442-1455: Avoid magic threshold; use finiteness check for invalid contacts.Comparing to 1.0e5 is brittle and unit-dependent. The primitive returns +inf for invalid contacts; prefer a finiteness check.
Apply this diff:
- # Check if this contact point is valid (primitive function returns wp.inf for invalid contacts) - valid = distance < 1.0e5 # Use a reasonable threshold instead of exact wp.inf comparison + # Check if this contact point is valid (primitive returns +inf for invalid contacts) + valid = wp.isfinite(distance)If wp.isfinite is unavailable here, fall back to an explicit comparison:
valid = distance < wp.inf
2163-2170: Early-return before doing work when contact is invalid.Micro-optimization and clearer flow: check valid before flipping the normal.
Apply this diff:
- # Flip the normal since we flipped the arguments - normal = -neg_normal - if not valid: - return + if not valid: + return + # Flip the normal since we flipped the arguments + normal = -neg_normal
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
newton/_src/geometry/kernels.py(4 hunks)newton/tests/test_rigid_contact.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
newton/tests/test_rigid_contact.py (1)
newton/_src/sim/builder.py (4)
add_body(1179-1241)add_joint_free(1609-1660)add_shape_cylinder(2636-2676)add_shape_mesh(2721-2754)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
🔇 Additional comments (4)
newton/_src/geometry/kernels.py (2)
1340-1340: Good call excluding cylinder from radius_eff.Leaving CYLINDER out of radius_eff avoids double-counting its radius since cylinder-plane distance is computed surface-to-surface in the primitive.
1413-1415: All callers unpack the 5-tuple
The sole call at newton/_src/geometry/kernels.py:2163 now unpacks (p_b_world, p_a_world, neg_normal, distance, valid).newton/tests/test_rigid_contact.py (2)
140-148: Adds cylinder case; expectations look correct.Axis aligned with world Z, so center settles at half_height. Good coverage addition.
149-157: Mesh body shift and expectations updated appropriately.Sequence and z-targets consistent with shape half-extents and scale.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
newton/tests/test_rigid_contact.py (1)
140-147: Add a rotated cylinder case to also validate radius-based offsetTo catch regressions when the cylinder axis is horizontal (rest height should equal radius), add a second cylinder rotated from Z to Y (similar to the capsule). Example:
expected_end_positions.append(wp.vec3(5.0, y_pos, 0.3 * scale)) + # Rotated cylinder (axis along Y): rest height equals radius + b = builder.add_body(xform=wp.transform(wp.vec3(6.0, y_pos, 1.0), wp.quat_identity())) + builder.add_joint_free(b) + xform_cyl = wp.transform(wp.vec3(), quat_between_axes(newton.Axis.Z, newton.Axis.Y)) + builder.add_shape_cylinder( + body=b, + xform=xform_cyl, + radius=0.1 * scale, + half_height=0.3 * scale, + ) + expected_end_positions.append(wp.vec3(6.0, y_pos, 0.1 * scale))
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
newton/_src/geometry/kernels.py(4 hunks)newton/tests/test_rigid_contact.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
newton/tests/test_rigid_contact.py (1)
newton/_src/sim/builder.py (4)
add_body(1179-1241)add_joint_free(1609-1660)add_shape_cylinder(2636-2676)add_shape_mesh(2721-2754)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
🔇 Additional comments (2)
newton/tests/test_rigid_contact.py (2)
140-147: Good addition: cylinder-on-plane case verifies correct half-height contact offsetAdding the vertical cylinder and expecting z = half_height exercises the previously incorrect offset. Looks correct and aligned with the fix for #826.
149-156: Mesh reposition and expectations updated — looks consistentMoving the mesh to x=7.0 and keeping the expected z at the mesh half-extent (0.3*scale) is consistent with the vertex setup and scaling.
|
@nvtw Can you fix |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
newton/tests/test_rigid_contact.py (4)
140-147: Cylinder addition looks correct; consider also testing rotated orientation.Upright cylinder’s expected z=half_height is correct. To fully cover the cylinder–plane bug, add a rotated cylinder (axis along X or Y) and expect z=radius for that case. This catches orientation-related regressions.
149-156: Mesh shift and expectations updated — add a quick length check.The move to x=7.0 and expected z=0.3·scale are consistent. Add a guard to ensure the number of expected positions matches the number of dynamic bodies to catch future divergences early.
Apply this minimal check near Line 183:
body_q = state_0.body_q.numpy() - expected_end_positions = np.array(expected_end_positions) + expected_end_positions = np.array(expected_end_positions) + assert expected_end_positions.shape[0] == model.body_count
44-47: Remove redundant builder setup.
builderis created and configured at Lines 44–47 but immediately replaced at Lines 99–104; the first instance (andadd_ground_plane()there) is unused.Apply:
- builder = newton.ModelBuilder() - builder.default_shape_cfg.ke = 1e4 - builder.default_shape_cfg.kd = 500.0 - builder.add_ground_plane()Also applies to: 99-104
194-194: Drop explicitnjmax=150or document rationale. MuJoCo defaultsnjmaxtonefcwhen unspecified (and uses the larger of the default or provided value); remove the override for model-agnostic stability or add a brief note explaining why 150 is required here.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
newton/tests/test_rigid_contact.py(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-19T12:27:30.629Z
Learnt from: preist-nvidia
PR: newton-physics/newton#579
File: newton/examples/example_mujoco.py:350-354
Timestamp: 2025-08-19T12:27:30.629Z
Learning: In Newton examples, Example.use_mujoco is a high-level attribute that controls whether to use MuJoCo solver vs other solvers (like XPBD), while SolverMuJoCo.use_mujoco_cpu controls the backend within MuJoCo (CPU vs Warp). These are separate concepts serving different purposes - the PR rename only applies to the solver parameter, not the Example class attributes.
Applied to files:
newton/tests/test_rigid_contact.py
🧬 Code graph analysis (1)
newton/tests/test_rigid_contact.py (2)
newton/_src/sim/builder.py (4)
add_body(1179-1241)add_joint_free(1609-1660)add_shape_cylinder(2636-2676)add_shape_mesh(2721-2754)newton/_src/solvers/mujoco/solver_mujoco.py (1)
SolverMuJoCo(1136-2844)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
|
Had to increase njmax for mujoco because the test scene now has more objects and generated more contacts. This first looked like a CI hiccup but it's fixed now. |
Co-authored-by: Eric Heiden <eheiden@nvidia.com>
Co-authored-by: Eric Heiden <eheiden@nvidia.com>
Description
Fixes #826
Newton Migration Guide
Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this PR.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit
Bug Fixes
Tests