Add UR10 example#691
Conversation
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
📝 WalkthroughWalkthroughAdds a UR10 robot example and updates README and tests. Re-exports compute_sphere_inertia in geometry. Refactors USD import to centralize joint parent/child resolution, warn on unresolved joints, and add a sphere-based inertia fallback when inertia is zero. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor USD as USD Loader
participant Importer as import_usd.parse_joint
participant Resolver as resolve_joint_parent_child
participant Graph as Articulation Graph
USD->>Importer: joint_desc, incoming_xform
Importer->>Resolver: resolve(joint_desc, body_index_map, get_transforms=True)
alt child unresolved & parent resolved
Resolver-->>Importer: swapped (parent_id, child_id, parent_tf, child_tf)
else both unresolved
Resolver-->>Importer: warn, return (-1, -1, None, None)
end
Importer->>Importer: apply incoming_xform to parent_tf
Importer->>Graph: add edge(parent_id, child_id)
sequenceDiagram
autonumber
actor User
participant Example as UR10 Example
participant Kernel as update_joint_target_trajectory_kernel
participant Solver
participant Viewer
User->>Example: run(num_envs)
Example->>Example: load USD, build model, init trajectories
loop per frame
Example->>Kernel: interpolate targets (time, dt)
Kernel-->>Example: joint_target per-env
Example->>Solver: apply targets and step
Example->>Viewer: render
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Out-of-scope changes
Possibly related PRs
Suggested reviewers
✨ 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (8)
newton/examples/robot/example_robot_ur10.py (4)
36-59: Add bounds checking for trajectory array access.The kernel accesses
joint_target_trajectory[step + 1, ...]without ensuring thatstep + 1is within bounds. While the modulo operation should prevent overflow, adding an explicit bounds check would improve robustness.@wp.kernel def update_joint_target_trajectory_kernel( joint_target_trajectory: wp.array3d(dtype=wp.float32), time: wp.array(dtype=wp.float32), dt: wp.float32, # output joint_target: wp.array2d(dtype=wp.float32), ): env_idx = wp.tid() t = time[env_idx] t = wp.mod(t + dt, float(joint_target_trajectory.shape[0] - 1)) step = int(t) + step = wp.min(step, joint_target_trajectory.shape[0] - 2) # Ensure step+1 is valid time[env_idx] = t num_dofs = joint_target.shape[1] for dof in range(num_dofs): # add env_idx here to make the sequence of dofs different for each env di = (dof + env_idx) % num_dofs joint_target[env_idx, dof] = wp.lerp( joint_target_trajectory[step, env_idx, di], joint_target_trajectory[step + 1, env_idx, di], wp.frac(t), )
114-119: Add validation for articulation count mismatch.The assertion provides a clear error message, but consider handling this case more gracefully or providing additional context about which articulations were found.
self.articulation_view = ArticulationView( self.model, "*ur10*", exclude_joint_types=[newton.JointType.FREE, newton.JointType.DISTANCE] ) -assert self.articulation_view.count == self.num_envs, ( - "Number of environments must match the number of articulations" -) +if self.articulation_view.count != self.num_envs: + raise ValueError( + f"Expected {self.num_envs} UR10 articulations but found {self.articulation_view.count}. " + f"This may indicate an issue with the USD import or replication." + )
131-135: Consider making the joint limit fallback configurable.The hardcoded fallback to
[-π, π]for joints without limits might not be appropriate for all joint types. Consider making this configurable or documenting the assumption.+ # Default limits for joints without explicit limits (assuming angular joints) + DEFAULT_ANGULAR_LIMITS = (-wp.pi, wp.pi) + for i in range(dof_count): # generate sinusoidal control signal for this dof lower = dof_lower[i] upper = dof_upper[i] if not np.isfinite(lower) or abs(lower) > 6.0: # no limits; assume the joint dof is angular - lower = -wp.pi - upper = wp.pi + lower, upper = DEFAULT_ANGULAR_LIMITS + if i == 0: # Log once to avoid spam + print(f"Using default angular limits {DEFAULT_ANGULAR_LIMITS} for joints without explicit limits")
143-143: Trajectory generation creates large arrays for wide joint ranges.The trajectory uses
int(limit_range * 50)points, which could create very large arrays for joints with wide ranges. Consider capping the maximum number of points or using a fixed trajectory length.- traj = np.sin(np.linspace(phase_shift, 2 * np.pi + phase_shift, int(limit_range * 50))) + # Cap trajectory points to avoid excessive memory usage + num_points = min(int(limit_range * 50), 500) + traj = np.sin(np.linspace(phase_shift, 2 * np.pi + phase_shift, num_points))newton/_src/utils/import_usd.py (4)
532-533: Consider using a more specific warning category.While the warnings are helpful, consider using a more specific warning category like
UserWarningor creating a custom warning class for USD import issues to allow users to filter these warnings if needed.- warnings.warn(f"Skipping joint {joint_desc.primPath}: both bodies unresolved", stacklevel=2) + warnings.warn(f"Skipping joint {joint_desc.primPath}: both bodies unresolved", UserWarning, stacklevel=2)- warnings.warn( - f"Body {body_path} has zero mass and zero inertia despite having the MassAPI USD schema applied.", - stacklevel=2, - ) + warnings.warn( + f"Body {body_path} has zero mass and zero inertia despite having the MassAPI USD schema applied.", + UserWarning, + stacklevel=2, + )Also applies to: 1246-1248
1224-1225: Consider making the default density configurable.The sphere approximation uses
default_shape_densityfor the inertia calculation. Consider allowing this to be overridden via a parameter or using the body's actual density if available frombody_density.- density = default_shape_density # kg/m³ + # Use body-specific density if available, otherwise fall back to default + density = body_density.get(body_path, default_shape_density) # kg/m³
538-538: Consider improving the verbose message for world connections.The message could be clearer about which body is being connected to the world frame.
- print(f"Joint {joint_desc.primPath} connects {parent_path} to world") + print(f"Joint {joint_desc.primPath}: connecting body '{parent_path}' to world frame (child unresolved)")
1241-1243: Consider adding units to the verbose output.The verbose message about inertia diagonal elements would be clearer with units.
- f"Applied default inertia matrix for body {body_path}: diagonal elements = [{I_default[0, 0]}, {I_default[1, 1]}, {I_default[2, 2]}]" + f"Applied default inertia matrix for body {body_path}: diagonal elements = [{I_default[0, 0]:.6f}, {I_default[1, 1]:.6f}, {I_default[2, 2]:.6f}] kg⋅m²"
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
docs/images/examples/example_robot_policy.jpgis excluded by!**/*.jpgdocs/images/examples/example_robot_ur10.jpgis excluded by!**/*.jpg
📒 Files selected for processing (6)
README.md(1 hunks)newton/_src/geometry/__init__.py(2 hunks)newton/_src/utils/import_usd.py(5 hunks)newton/examples/__init__.py(1 hunks)newton/examples/robot/example_robot_ur10.py(1 hunks)newton/tests/test_examples.py(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-08-27T19:05:44.697Z
Learnt from: Milad-Rakhsha-NV
PR: newton-physics/newton#535
File: newton/tests/test_examples.py:320-414
Timestamp: 2025-08-27T19:05:44.697Z
Learning: In newton/examples/__init__.py, the robot policy example is registered with the key "robot_policy" (not "robot.example_robot_policy"), so tests should reference it as name="robot_policy".
Applied to files:
newton/examples/__init__.pynewton/tests/test_examples.py
📚 Learning: 2025-08-27T23:32:48.670Z
Learnt from: shi-eric
PR: newton-physics/newton#660
File: pyproject.toml:54-59
Timestamp: 2025-08-27T23:32:48.670Z
Learning: In the newton project's pyproject.toml, self-referential extras (e.g., `examples = ["newton[sim]", "newton[importers]", ...]`) are normal and encouraged for dependency management, rather than inlining the dependencies.
Applied to files:
newton/examples/__init__.py
📚 Learning: 2025-08-12T17:51:37.474Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/geometry.py:16-22
Timestamp: 2025-08-12T17:51:37.474Z
Learning: In the Newton public API refactor, common geometry symbols like ParticleFlags and ShapeFlags are now exposed at the top level in newton/__init__.py rather than through newton.geometry. The newton/geometry.py module is intentionally focused only on broad-phase collision detection classes (BroadPhaseAllPairs, BroadPhaseExplicit, BroadPhaseSAP).
Applied to files:
newton/_src/geometry/__init__.py
📚 Learning: 2025-08-12T17:58:00.815Z
Learnt from: nvlukasz
PR: newton-physics/newton#519
File: newton/_src/solvers/featherstone/kernels.py:18-20
Timestamp: 2025-08-12T17:58:00.815Z
Learning: In newton/_src/core/__init__.py, the function transform_twist is properly re-exported from the spatial module via "from .spatial import (..., transform_twist, ...)" and included in __all__, making it available for import as "from ...core import transform_twist" from other modules.
Applied to files:
newton/_src/geometry/__init__.py
🧬 Code graph analysis (3)
newton/_src/geometry/__init__.py (1)
newton/_src/geometry/inertia.py (3)
compute_shape_inertia(426-522)compute_sphere_inertia(33-52)transform_inertia(388-423)
newton/examples/robot/example_robot_ur10.py (3)
newton/_src/utils/selection.py (2)
ArticulationView(125-799)set_attribute(576-591)newton/_src/sim/builder.py (6)
ModelBuilder(68-4465)add_usd(713-811)collapse_fixed_joints(2050-2347)add_shape_cylinder(2652-2692)replicate(621-643)add_ground_plane(2516-2536)newton/_src/solvers/mujoco/solver_mujoco.py (1)
SolverMuJoCo(1095-2566)
newton/_src/utils/import_usd.py (3)
newton/_src/geometry/types.py (1)
Mesh(113-297)newton/_src/geometry/flags.py (1)
ShapeFlags(30-42)newton/_src/geometry/inertia.py (1)
compute_sphere_inertia(33-52)
⏰ 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). (4)
- 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)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
🔇 Additional comments (11)
newton/examples/__init__.py (1)
203-203: LGTM!The UR10 example registration follows the established pattern and is correctly integrated into the example map.
newton/tests/test_examples.py (1)
328-335: Ignore renaming the UR10 test. The UR10 example’s name ("robot.example_robot_ur10") is consistent with the other robot examples in this file; only the policy entries should use the registered key"robot_policy".Likely an incorrect or invalid review comment.
README.md (1)
169-192: No missing images—files exist in docs/images/examples.Likely an incorrect or invalid review comment.
newton/examples/robot/example_robot_ur10.py (1)
93-95: Verify per-DOF control gains
UR10 joints vary in torque and inertia; adjustjoint_target_ke/kdfor each joint instead of using uniform values.newton/_src/geometry/__init__.py (1)
20-20: LGTM!The addition of
compute_sphere_inertiato the public API is correctly implemented and follows the existing pattern for exposing geometry utilities.Also applies to: 42-42
newton/_src/utils/import_usd.py (6)
21-21: LGTM! Appropriate import for handling warnings.The addition of the
warningsmodule is necessary for the new warning messages in the code.
31-31: LGTM! Good addition ofcompute_sphere_inertiaimport.The import is properly scoped and needed for the new inertia fallback functionality.
517-543: Well-structured joint parent/child resolver with proper error handling.The new
resolve_joint_parent_childhelper function effectively centralizes joint parent/child resolution logic. The function handles unresolved joints gracefully by swapping parent/child when needed and provides appropriate warnings.
544-551: LGTM! Clean refactoring ofparse_jointto use the new resolver.The refactoring to use
resolve_joint_parent_childwithget_transforms=Truesimplifies the code and maintains consistency.
905-906: LGTM! Consistent usage of resolver for joint edge construction.Using
resolve_joint_parent_childwithget_transforms=Falsefor topological sorting is efficient and maintains consistency.
1216-1249: Robust inertia fallback implementation with appropriate checks.The inertia fallback logic correctly:
- Only applies when inertia is zero and mass is non-zero
- Uses a reasonable sphere approximation based on mass and density
- Applies the parallel axis theorem when COM is offset
- Provides helpful verbose output
- Warns when both mass and inertia are zero
This addresses the UR10 import issue where bodies may have mass but lack explicit inertia data.
|
Just tried it in IsaacLab it works perfectly! No import problems, and it trains well and fast! |
AntoineRichard
left a comment
There was a problem hiding this comment.
LGTM, it works well in Sim, and it's fast!
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
newton/tests/test_import_usd.py (1)
116-119: Strengthen assertions: verify no FREE root and parent/child of the revolute joint.Good update to 2 joints. To harden this test against regressions:
- assert that no FREE joint exists
- assert the revolute joint connects CenterPivot → Arm
# Should have 2 joints: # 1. Fixed joint with only body0 specified (CenterPivot to world) # 2. Revolute joint between CenterPivot and Arm (normal joint with both bodies) - self.assertEqual(builder.joint_count, 2) + self.assertEqual(builder.joint_count, 2) + # Ensure no free root joint is present + self.assertNotIn(newton.JointType.FREE, builder.joint_type) + + # Validate revolute joint connectivity explicitly + arm_idx = builder.body_key.index("/Articulation/Arm") + self.assertEqual(builder.joint_parent[revolute_joint_idx], center_pivot_idx) + self.assertEqual(builder.joint_child[revolute_joint_idx], arm_idx)newton/tests/assets/revolute_articulation.usda (1)
52-61: Normalize or remove localRot1; add a comment explaining missing body1.The missing body1 is intentional, but localRot1=(0.6324555, 0, 0, 0) is not unit-length and can cause downstream normalization differences. Prefer identity and document intent.
def PhysicsFixedJoint "FixedJoint" { rel physics:body0 = </Articulation/CenterPivot> float physics:breakForce = inf float physics:breakTorque = inf point3f physics:localPos0 = (0, 0, 0) point3f physics:localPos1 = (0, 0, 0) quatf physics:localRot0 = (1, 0, 0, 0) - quatf physics:localRot1 = (0.6324555, 0, 0, 0) + # Intentionally omit physics:body1 to exercise importer fallback to world. + quatf physics:localRot1 = (1, 0, 0, 0) }
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
newton/tests/assets/revolute_articulation.usda(5 hunks)newton/tests/test_import_usd.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
newton/tests/test_import_usd.py (1)
newton/_src/sim/builder.py (1)
joint_count(525-529)
⏰ 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). (4)
- GitHub Check: Run GPU Unit Tests on AWS EC2 (Pull Request)
- GitHub Check: Run GPU Benchmarks (Pull Request)
- GitHub Check: run-newton-tests / newton-unittests (ubuntu-latest)
- GitHub Check: run-newton-tests / newton-unittests (windows-latest)
🔇 Additional comments (4)
newton/tests/assets/revolute_articulation.usda (4)
3-3: Render metadata cleanup is fine.Removing customLayerData payload is OK for a lightweight test asset.
12-14: Adding an explicit World Xform is a good clarity win.Keeps world semantics explicit without changing defaultPrim.
17-17: Dropping Isaac-specific APIs simplifies the test fixture.Leaner apiSchemas reduce importer variability and improve portability.
Also applies to: 29-29, 65-65, 91-91
99-101: Body swap and localPos swap look consistent; sanity-check pivot.Swapping body0/body1 and localPos0/localPos1 matches the new parent/child roles. Consider quickly verifying in the viewer that the hinge is at Arm’s -X end as intended.
Also applies to: 103-105
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
Signed-off-by: Eric Heiden <eric-heiden@outlook.com>
Description
Fixes a couple of USD parsing issues to be able to load the UR10 robot arm.
Adds a joint monkey example for the UR10 robot.
Closes #683.
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