Initial support for Mujoco equality constraints#460
Conversation
📝 WalkthroughWalkthroughThis update introduces support for equality constraints in the Newton simulation framework. It adds new public constants for constraint types, extends the model builder and model data structures to store equality constraints, implements parsing and export of these constraints to and from MuJoCo/MJCF, and provides comprehensive tests and XML assets to validate the new functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ModelBuilder
participant Model
participant MuJoCoSolver
participant MJCFParser
User->>ModelBuilder: add_equality_constraint_*(...)
ModelBuilder->>ModelBuilder: Store constraint attributes in lists
User->>ModelBuilder: finalize()
ModelBuilder->>Model: Assign equality constraint arrays and count
User->>MuJoCoSolver: convert_to_mjc(model)
MuJoCoSolver->>MuJoCoSolver: Extract equality constraint arrays
MuJoCoSolver->>MuJoCoSolver: Add constraints to MuJoCo model
User->>MJCFParser: parse_mjcf(..., skip_equality_constraints=False)
MJCFParser->>ModelBuilder: add_equality_constraint_* for each parsed constraint
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ 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. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
8cfc8c0 to
7301c35
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (3)
newton/solvers/mujoco/solver_mujoco.py (2)
1622-1631: Remove or document unused equality constraint variablesSeveral variables are extracted but immediately commented out. This creates unnecessary overhead and makes the code harder to maintain. Either remove these lines entirely or add a TODO comment explaining their future purpose.
eq_constraint_body1 = model.equality_constraint_body1.numpy() eq_constraint_body2 = model.equality_constraint_body2.numpy() eq_constraint_anchor1 = model.equality_constraint_anchor1.numpy() -# eq_constraint_anchor2 = model.equality_constraint_anchor2.numpy() -# eq_constraint_distance = model.equality_constraint_distance.numpy() eq_constraint_joint1 = model.equality_constraint_joint1.numpy() eq_constraint_joint2 = model.equality_constraint_joint2.numpy() eq_constraint_polycoef = model.equality_constraint_polycoef.numpy() -# eq_constraint_enabled = model.equality_constraint_enabled.numpy() +# TODO: Add support for anchor2, distance, and enabled properties when implementing +# weld, distance, and other constraint types
2020-2039: Consider environment filtering and enabled flag for constraintsThe equality constraints should respect the environment filtering logic used elsewhere in the code when
separate_envs_to_worldsis True. Also, theequality_constraint_enabledproperty exists but is commented out - consider using it to allow disabling constraints.Would you like me to implement the environment filtering logic for equality constraints to ensure they're only added for the selected environment?
newton/sim/builder.py (1)
3530-3556: Consider polycoef array structure and approve the rest.The equality constraint finalization is well-implemented and follows the established patterns. However, there's a potential issue with the
polycoefattribute:m.equality_constraint_polycoef = wp.array(self.equality_constraint_polycoef, dtype=wp.float32)Since
polycoefis a list of lists (each constraint can have multiple polynomial coefficients), flattening it into a single Warp array might lose the structure. Consider either:
- Using a 2D array if all constraints have the same number of coefficients
- Storing it as a list of Warp arrays
- Adding metadata to track coefficient counts per constraint
The rest of the implementation correctly converts the equality constraint data to appropriate Warp array types and follows the established patterns for model finalization.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between e37f0d9 and 7301c3511b3ad67b557894f5aa443e11f0d513c6.
📒 Files selected for processing (4)
newton/sim/builder.py(5 hunks)newton/sim/model.py(2 hunks)newton/solvers/mujoco/solver_mujoco.py(2 hunks)newton/utils/import_mjcf.py(4 hunks)
🧠 Learnings (3)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
newton/sim/model.py (1)
Learnt from: dylanturpin
PR: #450
File: newton/sim/ik.py:1286-1296
Timestamp: 2025-07-21T19:11:04.055Z
Learning: In Newton's IK system, the JointLimitObjective class intentionally only handles joints where DOF count equals coordinate count (1-1 mapping). This is appropriate because joint limits are typically only meaningful for simple joint types like revolute and prismatic joints, not complex joints like ball or free joints where DOF count != coordinate count.
newton/solvers/mujoco/solver_mujoco.py (1)
Learnt from: Kenny-Vilella
PR: #398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
newton/sim/model.py (1)
Learnt from: dylanturpin
PR: #450
File: newton/sim/ik.py:1286-1296
Timestamp: 2025-07-21T19:11:04.055Z
Learning: In Newton's IK system, the JointLimitObjective class intentionally only handles joints where DOF count equals coordinate count (1-1 mapping). This is appropriate because joint limits are typically only meaningful for simple joint types like revolute and prismatic joints, not complex joints like ball or free joints where DOF count != coordinate count.
newton/solvers/mujoco/solver_mujoco.py (1)
Learnt from: Kenny-Vilella
PR: #398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
⏰ 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 (3)
newton/sim/model.py (1)
275-323: LGTM! Clean addition of equality constraint attributes.The new equality constraint attributes follow the established naming conventions and are properly documented with their expected shapes and types. The initialization as empty lists is appropriate for these dynamic collections.
newton/sim/builder.py (2)
421-432: LGTM! Well-structured equality constraint attributes.The new equality constraint attributes follow the established naming pattern and data structure conventions in the codebase. The attribute types are appropriate for their intended use (strings for type/key, integers for indices, Vec3 for anchors, etc.).
688-698: LGTM! Proper integration with builder combination.The equality constraint attributes are correctly added to the
more_builder_attrslist, ensuring that when builders are combined usingadd_builder(), the equality constraint data is properly copied. This follows the established pattern for handling other model attributes.
dd0148e to
7ef9a3e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
newton/tests/test_equality_constraints.py (2)
25-36: Consider improving test organization and method naming.The test setup is functionally correct, but could be improved:
Move timing parameters to setUp(): The simulation timing parameters should be initialized in a
setUp()method rather than within the test method for better test organization.Test method name could be more descriptive: The method name
test_connect_constraintsuggests it's testing connect constraints specifically, but the test actually verifies general equality constraint parsing.Consider this refactor:
class TestEqualityConstraints(unittest.TestCase): + def setUp(self): + self.sim_time = 0.0 + self.frame_dt = 1 / 60 + self.sim_dt = self.frame_dt / 10 + - def test_connect_constraint(self): + def test_equality_constraints_parsing(self): - self.sim_time = 0.0 - self.frame_dt = 1 / 60 - self.sim_dt = self.frame_dt / 10 -
62-69: Consider enhancing test coverage with additional assertions.The current assertion only verifies that equality constraints exist but doesn't validate their correctness. For a more comprehensive test, consider adding assertions to verify:
- Specific constraint types (connect, joint, etc.)
- Constraint properties and parameters
- Expected number of constraints for the 4_bar.xml model
Example additional assertions:
self.assertGreater( self.solver.mj_model.eq_type.shape[0], 0 ) # check if number of equality constraints in mjModel > 0 + + # Verify specific constraint properties + eq_types = self.solver.mj_model.eq_type + self.assertIn(mujoco.mjtEq.mjEQ_CONNECT, eq_types) # Verify connect constraint exists + self.assertEqual(len([t for t in eq_types if t == mujoco.mjtEq.mjEQ_CONNECT]), 1) # Expected countThe main execution block with kernel cache clearing is appropriate.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 7301c3511b3ad67b557894f5aa443e11f0d513c6 and 7ef9a3eb54e80de41017f28c53ac2ec5e88de2ba.
📒 Files selected for processing (2)
newton/tests/assets/4_bar.xml(1 hunks)newton/tests/test_equality_constraints.py(1 hunks)
🧠 Learnings (1)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
✅ Files skipped from review due to trivial changes (1)
- newton/tests/assets/4_bar.xml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
⏰ 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_equality_constraints.py (2)
1-22: LGTM! Clean imports and proper licensing.The copyright header and imports are well-structured and include only the necessary dependencies for the test.
39-48: MuJoCoSolver use_mujoco flag is now fully supportedThe
use_mujoco=Trueoption is correctly handled innewton/solvers/mujoco/solver_mujoco.py(it setsself.use_mujocoand exercises the pure MuJoCo backend instep) and is exercised by multiple tests (e.g.test_equality_constraints.py,test_rigid_contact.py,test_up_axis.py, etc.). No further action needed.
|
Thanks for this - 1 question (probably mostly for @eric-heiden..) Architecturally, did we make a formal decision that a loop joint is treated differently in the newton model? You could argue that for non tree-based solvers, these joints are just joints.. And the featherstone/MuJoCo case is actually the special case. In fact, this is also how USD handles things, that everything is just joints and then you specify the articulation on top of it, as well as the loop joints that are then excluded from the tree and added as constraints. I feel like this needs a conversation with Disney for Kamino, at least. @nvtw @gdaviet probably have comments here as well. |
7ef9a3e to
b598927
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (5)
newton/tests/test_equality_constraints.py (1)
42-51: Verify thatuse_mujoco=Trueis now supported.According to previous learnings, the
use_mujocooption was unsupported and caused crashes. Please verify that this has been properly implemented and no longer causes issues.#!/bin/bash # Description: Check if use_mujoco is still marked as unsupported in the codebase # Search for any warnings or unsupported messages related to use_mujoco rg -A 5 "use_mujoco.*unsupported|unsupported.*use_mujoco" # Check the MuJoCoSolver implementation for use_mujoco handling ast-grep --pattern 'class MuJoCoSolver { $$$ }' # Look for any crash-related comments or warnings about use_mujoco rg -A 5 "use_mujoco.*crash|crash.*use_mujoco"newton/utils/import_mjcf.py (2)
768-773: Apply consistent body name sanitization.The connect constraint replaces hyphens with underscores in body names, but other constraint types should do the same for consistency.
817-817: Add verbose check for debug print statement.The weld constraint debug message should be wrapped with verbose check for consistency.
newton/sim/model.py (1)
277-296: Initialize Warp arrays withNone.According to past review comments, Model attributes that are Warp arrays should be initialized with
None.- self.equality_constraint_body1 = None - self.equality_constraint_body2 = None - self.equality_constraint_anchor = None - self.equality_constraint_torquescale = None - self.equality_constraint_relpose = None - self.equality_constraint_joint1 = None - self.equality_constraint_joint2 = None - self.equality_constraint_polycoef = None - self.equality_constraint_enabled = None + self.equality_constraint_body1 = None + self.equality_constraint_body2 = None + self.equality_constraint_anchor = None + self.equality_constraint_torquescale = None + self.equality_constraint_relpose = None + self.equality_constraint_joint1 = None + self.equality_constraint_joint2 = None + self.equality_constraint_polycoef = None + self.equality_constraint_enabled = NoneNote: The attributes are already initialized to
None, so the code is correct as-is.newton/solvers/mujoco/solver_mujoco.py (1)
2054-2080: Add error handling and validation for equality constraintsThe implementation still lacks proper error handling for invalid indices and unsupported constraint types as previously identified.
🧹 Nitpick comments (1)
newton/sim/model.py (1)
275-297: Consider adding equality constraints to attribute_frequency mapping.The new equality constraint attributes should be classified in the
attribute_frequencydictionary to maintain consistency with other model attributes.Add the following after line 385:
# attributes per equality constraint self.attribute_frequency["equality_constraint_type"] = "equality_constraint" self.attribute_frequency["equality_constraint_body1"] = "equality_constraint" self.attribute_frequency["equality_constraint_body2"] = "equality_constraint" self.attribute_frequency["equality_constraint_anchor"] = "equality_constraint" self.attribute_frequency["equality_constraint_torquescale"] = "equality_constraint" self.attribute_frequency["equality_constraint_relpose"] = "equality_constraint" self.attribute_frequency["equality_constraint_joint1"] = "equality_constraint" self.attribute_frequency["equality_constraint_joint2"] = "equality_constraint" self.attribute_frequency["equality_constraint_polycoef"] = "equality_constraint" self.attribute_frequency["equality_constraint_enabled"] = "equality_constraint"
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 7ef9a3eb54e80de41017f28c53ac2ec5e88de2ba and b598927e759d3e31b2fc3836dcf1ea3fb37b09f1.
📒 Files selected for processing (6)
newton/sim/builder.py(5 hunks)newton/sim/model.py(2 hunks)newton/solvers/mujoco/solver_mujoco.py(2 hunks)newton/tests/assets/constraints.xml(1 hunks)newton/tests/test_equality_constraints.py(1 hunks)newton/utils/import_mjcf.py(4 hunks)
✅ Files skipped from review due to trivial changes (1)
- newton/tests/assets/constraints.xml
🚧 Files skipped from review as they are similar to previous changes (1)
- newton/sim/builder.py
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
newton/sim/model.py (1)
Learnt from: dylanturpin
PR: #450
File: newton/sim/ik.py:1286-1296
Timestamp: 2025-07-21T19:11:04.077Z
Learning: In Newton's IK system, the JointLimitObjective class intentionally only handles joints where DOF count equals coordinate count (1-1 mapping). This is appropriate because joint limits are typically only meaningful for simple joint types like revolute and prismatic joints, not complex joints like ball or free joints where DOF count != coordinate count.
newton/tests/test_equality_constraints.py (1)
Learnt from: Kenny-Vilella
PR: #398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
newton/solvers/mujoco/solver_mujoco.py (1)
Learnt from: Kenny-Vilella
PR: #398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
🧬 Code Graph Analysis (1)
newton/utils/import_mjcf.py (1)
newton/sim/builder.py (1)
add_equality_constraint(1289-1339)
⏰ 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)
b598927 to
5ee4700
Compare
We definitely need to discuss more how this should be handled architecturally in Newton. We rely on kinematic trees a lot in Newton at the moment so just having loops represented by joints will break kinematics, etc. It may be beneficial to make the definition of which "joint" (or let's call it equality constraint) to be used to close the loop explicitly defined by the user instead of providing some cyclic joint graph to every algorithm (FK/IK, or the MuJoCoSolver converter) in Newton which then has to decide which joint to treat for loop closure, etc. @mmacklin for viz. |
|
Indeed if you look at the model from a solver-centric point of view, the loop joint/equality constraint should just be a different thing in a different array vs the joints that are part of the kinematic tree. I think that would also work well for a purely maximal coordinate solver as for these the model would only contain equality constraints. It does get difficult at the point where you want to switch solvers with the same model, which I think is a requirement for us. At that point I think there is no way around having everything in the same array/bucket and then have some additional information that you setup at model init time that tells the solver how to use those constraints. |
960d776 to
a5b60fa
Compare
a5b60fa to
4f8b03b
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
newton/utils/import_mjcf.py (4)
814-815: Add verbose check for consistency.The debug print statement should be wrapped with a verbose check for consistency with the rest of the codebase.
- if verbose: - print(f"Weld constraint: {body1_name} to {body2_name}") + if verbose: + print(f"Weld constraint: {body1_name} to {body2_name}")Wait, this is already correctly wrapped. Let me check if there are other missing verbose checks in the function.
775-802: Fix undefined variable and improve consistency.Multiple issues in the connect constraint parsing:
- Line 787 uses undefined variable
anchorinstead ofanchor_vec- Body name sanitization should be consistent with other constraint types
Apply this fix:
if body1_name and anchor: if verbose: - print(f"Connect constraint: {body1_name} to {body2_name} at anchor {anchor}") + print(f"Connect constraint: {body1_name} to {body2_name} at anchor {anchor_vec}")Also, consider moving the
anchor_veccalculation before the verbose print for better code organization.
803-832: Fix incorrect attribute reference and apply consistent naming.Critical issue: Lines 805-806 incorrectly reference
connect.attribinstead ofweld.attribwhen parsing weld constraints.Apply this fix:
- body1_name = connect.attrib.get("body1", "").replace("-", "_") if connect.attrib.get("body1") else None + body1_name = weld.attrib.get("body1", "").replace("-", "_") if weld.attrib.get("body1") else None body2_name = ( - connect.attrib.get("body2", "worldbody").replace("-", "_") if connect.attrib.get("body2") else None + weld.attrib.get("body2", "worldbody").replace("-", "_") if weld.attrib.get("body2") else None )
833-851: Fix undefined variable in joint constraint parsing.The variable
commonis used but not defined in the joint constraint parsing section.Add the missing line:
for joint in equality.findall("joint"): + common = parse_common_attributes(joint) joint1_name = joint.attrib.get("joint1")
🧹 Nitpick comments (1)
newton/utils/import_mjcf.py (1)
612-613: Remove leftover debug code.This debug print statement appears to be leftover development code and should be removed.
- if body_name == "thigh_right": - print(geoms)
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 5ee4700adbe2fa69608c63e562ccbdfb08006270 and 4f8b03b91e781e11bcbef718812289abdad94c60.
📒 Files selected for processing (9)
newton/__init__.py(2 hunks)newton/sim/__init__.py(1 hunks)newton/sim/builder.py(5 hunks)newton/sim/model.py(2 hunks)newton/sim/types.py(1 hunks)newton/solvers/mujoco/solver_mujoco.py(2 hunks)newton/tests/assets/constraints.xml(1 hunks)newton/tests/test_equality_constraints.py(1 hunks)newton/utils/import_mjcf.py(4 hunks)
✅ Files skipped from review due to trivial changes (3)
- newton/sim/init.py
- newton/init.py
- newton/sim/types.py
🚧 Files skipped from review as they are similar to previous changes (4)
- newton/tests/test_equality_constraints.py
- newton/tests/assets/constraints.xml
- newton/sim/model.py
- newton/solvers/mujoco/solver_mujoco.py
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
⏰ 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 (6)
newton/utils/import_mjcf.py (2)
57-57: LGTM! Parameter addition is well-implemented.The
parse_equalityparameter is properly added with a sensible default value and clear documentation.Also applies to: 86-86
883-888: LGTM! Equality constraint integration is well-placed.The integration of equality constraint parsing is correctly implemented:
- Proper conditional check using the
parse_equalityparameter- Well-positioned in the parsing flow after bodies but before collision setup
- Clear section separation with comments
newton/sim/builder.py (4)
447-458: LGTM! Clean initialization of equality constraint data structures.The initialization of equality constraint lists follows the established pattern in the ModelBuilder class and covers all necessary attributes for representing Mujoco-style equality constraints. The naming convention is consistent with other constraint types in the codebase.
1313-1363: Good implementation with proper error handling.The method correctly addresses the previous review concern about name-to-index resolution by adding proper validation (
name in self.key_list) before calling.index(). The implementation handles all constraint types with appropriate default values and follows the established pattern of otheradd_*methods in the class.The method signature is comprehensive and the documentation clearly explains each parameter's purpose.
714-724: Correct integration with ModelBuilder composition.The equality constraint attributes are properly added to the
more_builder_attrslist, ensuring that constraint data is correctly copied when combining ModelBuilder instances. This maintains consistency with how other constraint types are handled during builder composition.
3749-3775: Proper finalization of equality constraint data.The constraint data is correctly converted from Python lists to appropriate Warp arrays during model finalization. The data types are well-chosen for GPU computation, and the constraint count is properly set on the model. This follows the established pattern for other constraint types in the finalization process.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
newton/solvers/mujoco/solver_mujoco.py (2)
1656-1665: Add validation for equality constraint attributes before accessing them.The code directly accesses multiple equality constraint attributes without checking if they exist on the model object. This could cause runtime exceptions if any attributes are missing or not properly initialized.
+ # Validate equality constraint attributes exist + constraint_attrs = [ + 'equality_constraint_type', 'equality_constraint_body1', 'equality_constraint_body2', + 'equality_constraint_anchor', 'equality_constraint_torquescale', + 'equality_constraint_relpose', 'equality_constraint_joint1', + 'equality_constraint_joint2', 'equality_constraint_polycoef', + 'equality_constraint_enabled' + ] + for attr in constraint_attrs: + if not hasattr(model, attr): + raise AttributeError(f"Model missing required equality constraint attribute: {attr}") + eq_constraint_type = model.equality_constraint_type.numpy() eq_constraint_body1 = model.equality_constraint_body1.numpy() eq_constraint_body2 = model.equality_constraint_body2.numpy()
2055-2081: Add comprehensive error handling and validation for equality constraints.The constraint conversion logic lacks proper error handling and validation:
- Direct dictionary access could raise
KeyErrorif indices are invalid- No bounds checking for body/joint indices before accessing model arrays
- No explicit handling for unsupported constraint types
- No validation of constraint data before use
for i, typ in enumerate(eq_constraint_type): if typ == newton.EQ_CONNECT: + # Validate body indices + body1_idx = eq_constraint_body1[i] + body2_idx = eq_constraint_body2[i] + if body1_idx >= len(model.body_key) or body2_idx >= len(model.body_key): + print(f"Warning: Invalid body indices in connect constraint {i}") + continue + eq = spec.add_equality(objtype=mujoco.mjtObj.mjOBJ_BODY) eq.type = mujoco.mjtEq.mjEQ_CONNECT eq.active = eq_constraint_enabled[i] eq.name1 = model.body_key[eq_constraint_body1[i]] eq.name2 = model.body_key[eq_constraint_body2[i]] eq.data[0:3] = eq_constraint_anchor[i] elif typ == newton.EQ_JOINT: + # Validate joint indices + joint1_idx = eq_constraint_joint1[i] + joint2_idx = eq_constraint_joint2[i] + if joint1_idx >= len(model.joint_key) or joint2_idx >= len(model.joint_key): + print(f"Warning: Invalid joint indices in joint constraint {i}") + continue + eq = spec.add_equality(objtype=mujoco.mjtObj.mjOBJ_JOINT) eq.type = mujoco.mjtEq.mjEQ_JOINT eq.active = eq_constraint_enabled[i] eq.name1 = model.joint_key[eq_constraint_joint1[i]] eq.name2 = model.joint_key[eq_constraint_joint2[i]] eq.data[0:5] = eq_constraint_polycoef[i] elif typ == newton.EQ_WELD: + # Validate body indices + body1_idx = eq_constraint_body1[i] + body2_idx = eq_constraint_body2[i] + if body1_idx >= len(model.body_key) or body2_idx >= len(model.body_key): + print(f"Warning: Invalid body indices in weld constraint {i}") + continue + eq = spec.add_equality(objtype=mujoco.mjtObj.mjOBJ_BODY) eq.type = mujoco.mjtEq.mjEQ_WELD eq.active = eq_constraint_enabled[i] eq.name1 = model.body_key[eq_constraint_body1[i]] eq.name2 = model.body_key[eq_constraint_body2[i]] eq.data[0:3] = eq_constraint_anchor[i] eq.data[3:10] = eq_constraint_relpose[i] eq.data[10] = eq_constraint_torquescale[i] + + else: + print(f"Warning: Unknown or unsupported equality constraint type '{typ}' at index {i}")
🧹 Nitpick comments (1)
newton/utils/import_mjcf.py (1)
612-613: Remove leftover debug code.This debug print statement appears to be leftover development code that should be removed before merging.
- if body_name == "thigh_right": - print(geoms)
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 5ee4700adbe2fa69608c63e562ccbdfb08006270 and 4f8b03b91e781e11bcbef718812289abdad94c60.
📒 Files selected for processing (9)
newton/__init__.py(2 hunks)newton/sim/__init__.py(1 hunks)newton/sim/builder.py(5 hunks)newton/sim/model.py(2 hunks)newton/sim/types.py(1 hunks)newton/solvers/mujoco/solver_mujoco.py(2 hunks)newton/tests/assets/constraints.xml(1 hunks)newton/tests/test_equality_constraints.py(1 hunks)newton/utils/import_mjcf.py(4 hunks)
✅ Files skipped from review due to trivial changes (3)
- newton/init.py
- newton/sim/init.py
- newton/sim/types.py
🚧 Files skipped from review as they are similar to previous changes (4)
- newton/tests/assets/constraints.xml
- newton/tests/test_equality_constraints.py
- newton/sim/model.py
- newton/sim/builder.py
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
newton/solvers/mujoco/solver_mujoco.py (2)
Learnt from: Kenny-Vilella
PR: #398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
Learnt from: adenzler-nvidia
PR: #479
File: newton/solvers/mujoco/solver_mujoco.py:2147-2149
Timestamp: 2025-07-28T15:04:54.360Z
Learning: In the Newton MuJoCo solver implementation, the ls_parallel option may not be available in the pure MuJoCo mjOption structure, despite being documented in newer MuJoCo versions. The user adenzler-nvidia confirmed that mj_model does not have this attribute in their implementation, so ls_parallel should only be set on mjw_model.opt.
🧬 Code Graph Analysis (1)
newton/utils/import_mjcf.py (1)
newton/sim/builder.py (1)
add_equality_constraint(1313-1363)
⏰ 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 Benchmarks (Pull Request)
🔇 Additional comments (3)
newton/utils/import_mjcf.py (3)
57-57: LGTM: Well-designed parameter addition.The new
parse_equalityparameter with a default value ofFalseprovides a clean way to optionally enable equality constraint parsing without affecting existing functionality.Also applies to: 86-86
766-853: Good implementation with past issues addressed.The
parse_equality_constraintsfunction correctly addresses most of the issues from previous reviews:✅ Fixed attribute references (using
weld.attribinstead ofconnect.attrib)
✅ Added verbose checks for all debug print statements
✅ Properly definedanchor_vecbefore use
✅ Consistent body name sanitization withreplace("-", "_")
✅ Proper extraction and usage of common attributesThe function handles the three supported constraint types (connect, weld, joint) appropriately and includes helpful warnings for unsupported site-based constraints.
883-888: LGTM: Proper conditional invocation.The equality constraints parsing is correctly invoked only when both the
<equality>element exists in the XML and theparse_equalityparameter is enabled. The placement in the parsing flow is appropriate.
|
Chiming in on the architecture discussion, is it ok that we introduce these new variables in the Newton model dedicated to a Mujoco-only feature? If it feels too Mujoco centric I could change the implementation to add an In the USD side, I spoke with Renato Gasoto about the Mjcf to Usd converter and it seems all loop-closing joints are marked with a |
|
Ideally we would have a way to figure out what is an equality constraint at the time we initialize the solver. Then we can store those specific variables on the solver itself. That requires us not to lose that information coming from the input file and making it through the modelBuilder and finalize. I think that's doable here by just introducing another model field that keeps track of whether a joint has this excludeFromArticulation flag set. I don't know how that will influence everything else though as you now suddenly have joints with dofs in the middle of articulations, so I think this requires a few changes in other places as well that rely on certain orderings. I do think it's more general and will be a good fit for all the maximal coordinate solvers to have all the joints in the same place in the model. We could put the requirement that the joints of the same tree must be consecutive, if that helps. |
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
4f8b03b to
7520245
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
newton/utils/import_mjcf.py (1)
612-613: Remove leftover debug code.This debug print statement appears to be leftover development code that should be removed before merging.
- if body_name == "thigh_right": - print(geoms)
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 4f8b03b91e781e11bcbef718812289abdad94c60 and 7520245.
📒 Files selected for processing (9)
newton/__init__.py(2 hunks)newton/sim/__init__.py(2 hunks)newton/sim/builder.py(6 hunks)newton/sim/joints.py(1 hunks)newton/sim/model.py(2 hunks)newton/solvers/mujoco/solver_mujoco.py(2 hunks)newton/tests/assets/constraints.xml(1 hunks)newton/tests/test_equality_constraints.py(1 hunks)newton/utils/import_mjcf.py(4 hunks)
✅ Files skipped from review due to trivial changes (2)
- newton/sim/joints.py
- newton/tests/assets/constraints.xml
🚧 Files skipped from review as they are similar to previous changes (5)
- newton/init.py
- newton/sim/init.py
- newton/sim/model.py
- newton/solvers/mujoco/solver_mujoco.py
- newton/sim/builder.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: the use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crash...
Learnt from: Kenny-Vilella
PR: newton-physics/newton#398
File: newton/examples/example_mujoco.py:352-352
Timestamp: 2025-07-14T03:57:29.670Z
Learning: The use_mujoco option in newton/examples/example_mujoco.py is currently unsupported and causes crashes. The code automatically disables this option with a warning message when users attempt to enable it. This is intentionally kept as a placeholder for future implementation.
Applied to files:
newton/tests/test_equality_constraints.py
🧬 Code Graph Analysis (1)
newton/utils/import_mjcf.py (1)
newton/sim/builder.py (3)
add_equality_constraint_connect(1363-1392)add_equality_constraint_weld(1425-1460)add_equality_constraint_joint(1394-1423)
⏰ 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)
🔇 Additional comments (7)
newton/utils/import_mjcf.py (3)
57-57: LGTM! Parameter naming and default value are well chosen.The
skip_equality_constraintsparameter with defaultFalsecorrectly implements the suggestion from previous reviews to parse constraints by default unless explicitly disabled.
766-869: LGTM! Implementation addresses previous review feedback effectively.The
parse_equality_constraintsfunction correctly implements:
- Consistent body name sanitization with
replace("-", "_")across all constraint types- Proper verbose checks around debug print statements
- Correct attribute references (
weld.attribvsconnect.attrib)- Proper variable definitions (
commonandanchor_vec)- Complete parameter extraction and builder integration
The function handles connect, weld, and joint constraints appropriately and includes proper warnings for unsupported site-based constraints.
899-905: LGTM! Clean integration of equality constraint parsing.The integration follows the established pattern in the codebase with proper conditional checks and clear section organization. The logic correctly respects both the presence of equality elements and the user's preference via
skip_equality_constraints.newton/tests/test_equality_constraints.py (4)
25-40: LGTM! Comprehensive test setup.The test properly configures simulation parameters and uses the new
skip_equality_constraints=Falseparameter to enable constraint parsing. The use of a dedicated test asset file and relevant parsing options demonstrates good test design.
54-65: LGTM! Active simulation addresses previous feedback.The implementation now includes a proper simulation loop instead of commented-out code, which directly addresses the previous review feedback. The nested loop structure and state management follow Newton patterns correctly.
66-82: Excellent test assertions that address previous feedback comprehensively.The test now includes runtime validation that directly addresses previous concerns:
- Verifies constraints were parsed and exist in the MuJoCo model
- Validates constraint violations remain within acceptable thresholds (< 0.01)
- Checks constraint forces are reasonable (< 1000.0)
- Includes proper error messages with actual values for debugging
This is a significant improvement that tests both parsing correctness and runtime constraint behavior.
43-52: Ignoreuse_mujoco=Truewarning.The
MuJoCoSolverimplementation insolver_mujoco.pyfully supportsuse_mujoco=True—there are no built-in checks that disable it or emit warnings in the solver itself (the only explicit disablement is in the example script, not in the solver). It’s safe to run equality‐constraint tests withuse_mujoco=True.Likely an incorrect or invalid review comment.
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Signed-off-by: Gabriel Noya <mega.kaloca@gmail.com>
Description
Adds support for Mujoco equality constraints. (<equality> tag in MJCF files).
There are currently 5 types of equality constraints in Mujoco: connect, weld, joint, tendon, and flex.
Currently connect, weld, and joint are implemented. The overall structure for other types is already present, but full implementation would depend on Newton supporting the tendon and flex types themselves.
Equality constraints primarily serve as a way to remediate closed kinematic loops and are present in many assets in the Mujoco menagerie. (Issue #331)
Newton Migration Guide
Please ensure the migration guide for warp.sim users is up-to-date with the changes made in this MR.
docs/migration.rstis up-to dateBefore your PR is "Ready for review"
newton/tests/test_examples.py)pre-commit run -aSummary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation