Skip to content

Add gravity factory support for MuJoCo scenes#1490

Merged
schaubh merged 8 commits into
developfrom
feature/grav_factory_mujoco
Jul 22, 2026
Merged

Add gravity factory support for MuJoCo scenes#1490
schaubh merged 8 commits into
developfrom
feature/grav_factory_mujoco

Conversation

@schaubh

@schaubh schaubh commented Jul 20, 2026

Copy link
Copy Markdown
Contributor
  • Review: By commit
  • Merge strategy: Merge (no squash)

Description

This PR extends simIncludeGravBody.gravBodyFactory so the same gravity-body configuration can be attached to conventional Basilisk spacecraft dynamics or a MuJoCo MJScene.

MuJoCo users can now configure gravity with the standard factory workflow:

gravFactory = simIncludeGravBody.gravBodyFactory()
earth = gravFactory.createEarth()
earth.isCentralBody = True
gravFactory.addBodiesTo(scene)

For a MuJoCo scene, addBodiesTo() creates and retains an NBodyGravity model, adds the factory bodies as gravity sources, and registers every MuJoCo body as a gravity target at its center of mass. The gravity-body configuration is also exposed to Vizard. Duplicate attachment to a scene is rejected.

NBodyGravity now accepts shared GravBodyData descriptors. This preserves each body’s gravity model, central-body designation, and ephemeris input without duplicating configuration between conventional and MuJoCo dynamics. The existing manual NBodyGravity APIs remain available.

This PR also adds PlanetEphemeris.zeroBase. When set to a body propagated by the module, all output positions and velocities are translated relative to that body while retaining J2000-aligned axes. Leaving zeroBase empty preserves the existing heliocentric behavior. Body-name matching is case-insensitive, and invalid selections stop initialization with an error.

A new scenarioMJEarthMoonGravity tutorial demonstrates Earth and Moon gravity using either SPICE or PlanetEphemeris. It includes correct ephemeris scheduling, safe low-Earth-orbit initial conditions, Vizard binary-saving support, and illustrative plots.

Existing MuJoCo examples and appropriate MuJoCo-backed tests were migrated to the factory helper. Tests that intentionally exercise the low-level NBodyGravity configuration APIs remain explicit.

The commits are organized as follows:

  1. Add GravBodyData and MuJoCo-scene support to NBodyGravity and gravBodyFactory.
  2. Improve the gravity factory comments and user guidance.
  3. Add and document PlanetEphemeris.zeroBase.
  4. Add the Earth-Moon MuJoCo gravity tutorial.
  5. Migrate existing MuJoCo examples to the gravity factory.
  6. Migrate appropriate MuJoCo-backed unit tests.
  7. Add release-note snippets.

Verification

The following validation was performed:

  • Rebuilt the planetEphemeris C++ and SWIG target.
  • Ran all 18 PlanetEphemeris unit tests.
  • Ran all 14 MuJoCo example scenario tests.
  • Ran all 67 tests under src/simulation/mujocoDynamics.
  • Ran all 6 cannonball-drag tests.
  • Ran the updated custom-gravity-body scenario test.
  • Ran the Earth-Moon tutorial with both SPICE and PlanetEphemeris.
  • Verified that the spacecraft remains safely above the Earth’s atmosphere.
  • Verified both ephemeris configurations in Vizard.
  • Ran the applicable pre-commit hooks.
  • Ran Python compilation and diff whitespace checks.

No test baselines were re-generated or relaxed.

Documentation

The following documentation was added or updated:

  • Expanded the simIncludeGravBody module documentation and inline comments.
  • Documented PlanetEphemeris.zeroBase, including default behavior, usage, and limitations.
  • Added the required warning that zeroBase only works with bodies propagated by the same PlanetEphemeris instance.
  • Added scenarioMJEarthMoonGravity and linked it from the example index.
  • Documented the SPICE and analytical ephemeris configuration paths and their scheduling requirements.
  • Updated existing MuJoCo examples to use and describe the gravity-factory workflow.
  • Updated scenarioCustomGravBody to use an asteroid-centered ephemeris origin.
  • Added release-note snippets for the factory support, zeroBase, and tutorial.

Reviewers should pay particular attention to the GravBodyData ownership and ephemeris connections in NBodyGravity, the automatic MuJoCo target registration in gravBodyFactory.addBodiesTo(), and the two-pass state translation in PlanetEphemeris.

Future work

No required follow-up is currently identified.

Cross-instance PlanetEphemeris.zeroBase support remains intentionally out of scope because separate module instances do not exchange propagated body states.

@schaubh
schaubh requested a review from juan-g-bonilla July 20, 2026 20:57
@schaubh schaubh self-assigned this Jul 20, 2026
@schaubh
schaubh requested a review from a team as a code owner July 20, 2026 20:57
@schaubh schaubh added documentation Improvements or additions to documentation enhancement New feature or request labels Jul 20, 2026
@schaubh schaubh added this to Basilisk Jul 20, 2026
schaubh added a commit that referenced this pull request Jul 20, 2026
Extend gravBodyFactory.addBodiesTo() to configure MJScene objects in
addition to conventional GravityEffector owners. For each MuJoCo scene,
create an NBodyGravity model, register every factory body as a gravity
source, and apply gravity independently at every MuJoCo body's center
of mass. Retain the model and Vizard gravity metadata on the scene and
reject duplicate gravity attachment.

Allow NBodyGravity sources to retain a shared GravBodyData descriptor.
Resolve the gravity model, central-body flag, and ephemeris input from
the descriptor so the same configuration can be shared by conventional
spacecraft and MuJoCo dynamics. Initialize descriptor-backed gravity
models during Reset and warn when an orientation-dependent model has no
ephemeris input.

Expose descriptor-backed sources to Python as
addGravitySourceFromBody(). Keep the existing manual
addGravitySource(..., isCentralBody=...) interface unchanged, including
support for its keyword argument.

This enables gravity models and SPICE connections created by
simIncludeGravBody to be reused directly by MuJoCo scenes without
duplicating their configuration.
schaubh added a commit that referenced this pull request Jul 20, 2026
schaubh added a commit that referenced this pull request Jul 20, 2026
Add an optional zeroBase setting to PlanetEphemeris so generated planet
states can be expressed relative to another body propagated by the same
module instance. Preserve the existing heliocentric behavior when
zeroBase is left empty.

Resolve the selected body during Reset using case-insensitive name
matching and report an initialization error when the requested body is
not configured in the module. Compute all heliocentric states before
subtracting the selected body's position and velocity, ensuring the
translation is independent of body ordering. Leave planet names,
timestamps, attitudes, attitude rates, and orientation flags unchanged.

Expand the PlanetEphemeris unit tests to verify:

- the default empty zeroBase value
- position and velocity translation at multiple simulation times
- zero position and velocity for the selected base body
- preservation of attitude and message metadata
- case-insensitive body-name matching
- rejection of bodies from outside the module instance

Document zeroBase configuration, default behavior, and the requirement
that the reference body be propagated by the same PlanetEphemeris
instance. Clarify that changing the output origin does not introduce
hierarchical or mutually coupled orbital propagation.

Update scenarioCustomGravBody to use Itokawa as the output origin,
placing the planet and spacecraft states in a common asteroid-centered
translational frame.
@schaubh
schaubh force-pushed the feature/grav_factory_mujoco branch from 2bbbd8c to b0a9b37 Compare July 20, 2026 21:01
schaubh added a commit that referenced this pull request Jul 20, 2026
Example uses both Spice and planetEphemeris message states.
schaubh added a commit that referenced this pull request Jul 20, 2026
schaubh added a commit that referenced this pull request Jul 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2bbbd8c1fb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/scenarioCustomGravBody.py Outdated
Comment thread src/simulation/mujocoDynamics/NBodyGravity/NBodyGravity.cpp
schaubh added a commit that referenced this pull request Jul 20, 2026
Add an optional zeroBase setting to PlanetEphemeris so generated planet
states can be expressed relative to another body propagated by the same
module instance. Preserve the existing heliocentric behavior when
zeroBase is left empty.

Resolve the selected body during Reset using case-insensitive name
matching and report an initialization error when the requested body is
not configured in the module. Compute all heliocentric states before
subtracting the selected body's position and velocity, ensuring the
translation is independent of body ordering. Leave planet names,
timestamps, attitudes, attitude rates, and orientation flags unchanged.

Expand the PlanetEphemeris unit tests to verify:

- the default empty zeroBase value
- position and velocity translation at multiple simulation times
- zero position and velocity for the selected base body
- preservation of attitude and message metadata
- case-insensitive body-name matching
- rejection of bodies from outside the module instance

Document zeroBase configuration, default behavior, and the requirement
that the reference body be propagated by the same PlanetEphemeris
instance. Clarify that changing the output origin does not introduce
hierarchical or mutually coupled orbital propagation.

Update scenarioCustomGravBody to use Itokawa as the output origin,
placing the planet and spacecraft states in a common asteroid-centered
translational frame.
schaubh added a commit that referenced this pull request Jul 20, 2026
Example uses both Spice and planetEphemeris message states.
schaubh added a commit that referenced this pull request Jul 20, 2026
@schaubh
schaubh force-pushed the feature/grav_factory_mujoco branch from b0a9b37 to f209d89 Compare July 20, 2026 23:59
schaubh added a commit that referenced this pull request Jul 20, 2026
schaubh added a commit that referenced this pull request Jul 20, 2026
Treat an all-zero J20002Pfix matrix from a linked gravity-source
ephemeris message as an identity transformation.

Position-only ephemeris messages leave J20002Pfix at its default zero
value. Applying that matrix previously collapsed transformed target
positions to zero, which could produce a singular gravity calculation
and NaN forces. The new fallback matches the existing GravityEffector
behavior and interprets an unspecified source attitude as inertially
aligned.

Add a MuJoCo regression test using a factory-created central gravity
body connected to a position-only ephemeris message. Verify that the
computed force remains finite and agrees with the analytical
point-mass gravity result.

Verification:
- NBodyGravity unit tests: 11 passed
- MuJoCo dynamics tests: 68 passed
- pre-commit checks passed
- git diff --check passed

@juan-g-bonilla juan-g-bonilla left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused mostly on the NBodyGravity changes and usage. Left two nitpick-y comments and suggested a fix for what I think gets you stale recorded data. Otherwise the scenarios look much nicer with the factory!

Comment thread src/simulation/mujocoDynamics/NBodyGravity/NBodyGravity.cpp Outdated
Comment thread src/utilities/simIncludeGravBody.py Outdated
Comment thread examples/mujoco/scenarioMJEarthMoonGravity.py Outdated
schaubh added 7 commits July 21, 2026 19:23
Extend gravBodyFactory.addBodiesTo() to configure MJScene objects in
addition to conventional GravityEffector owners. For each MuJoCo scene,
create an NBodyGravity model, register every factory body as a gravity
source, and apply gravity independently at every MuJoCo body's center
of mass. Retain the model and Vizard gravity metadata on the scene and
reject duplicate gravity attachment.

Allow NBodyGravity sources to retain a shared GravBodyData descriptor.
Resolve the gravity model, central-body flag, and ephemeris input from
the descriptor so the same configuration can be shared by conventional
spacecraft and MuJoCo dynamics. Initialize descriptor-backed gravity
models during Reset and warn when an orientation-dependent model has no
ephemeris input.

Expose descriptor-backed sources to Python as
addGravitySourceFromBody(). Keep the existing manual
addGravitySource(..., isCentralBody=...) interface unchanged, including
support for its keyword argument.

This enables gravity models and SPICE connections created by
simIncludeGravBody to be reused directly by MuJoCo scenes without
duplicating their configuration.
Add an optional zeroBase setting to PlanetEphemeris so generated planet
states can be expressed relative to another body propagated by the same
module instance. Preserve the existing heliocentric behavior when
zeroBase is left empty.

Resolve the selected body during Reset using case-insensitive name
matching and report an initialization error when the requested body is
not configured in the module. Compute all heliocentric states before
subtracting the selected body's position and velocity, ensuring the
translation is independent of body ordering. Leave planet names,
timestamps, attitudes, attitude rates, and orientation flags unchanged.

Expand the PlanetEphemeris unit tests to verify:

- the default empty zeroBase value
- position and velocity translation at multiple simulation times
- zero position and velocity for the selected base body
- preservation of attitude and message metadata
- case-insensitive body-name matching
- rejection of bodies from outside the module instance

Document zeroBase configuration, default behavior, and the requirement
that the reference body be propagated by the same PlanetEphemeris
instance. Clarify that changing the output origin does not introduce
hierarchical or mutually coupled orbital propagation.

Update scenarioCustomGravBody to use Itokawa as the output origin,
placing the planet and spacecraft states in a common asteroid-centered
translational frame.
Example uses both Spice and planetEphemeris message states.
Treat an all-zero J20002Pfix matrix from a linked gravity-source
ephemeris message as an identity transformation.

Position-only ephemeris messages leave J20002Pfix at its default zero
value. Applying that matrix previously collapsed transformed target
positions to zero, which could produce a singular gravity calculation
and NaN forces. The new fallback matches the existing GravityEffector
behavior and interprets an unspecified source attitude as inertially
aligned.

Add a MuJoCo regression test using a factory-created central gravity
body connected to a position-only ephemeris message. Verify that the
computed force remains finite and agrees with the analytical
point-mass gravity result.

Verification:
- NBodyGravity unit tests: 11 passed
- MuJoCo dynamics tests: 68 passed
- pre-commit checks passed
- git diff --check passed
@schaubh
schaubh force-pushed the feature/grav_factory_mujoco branch from f209d89 to c0fd86a Compare July 22, 2026 01:23
@schaubh
schaubh merged commit 8eb951c into develop Jul 22, 2026
7 checks passed
schaubh added a commit that referenced this pull request Jul 22, 2026
Extend gravBodyFactory.addBodiesTo() to configure MJScene objects in
addition to conventional GravityEffector owners. For each MuJoCo scene,
create an NBodyGravity model, register every factory body as a gravity
source, and apply gravity independently at every MuJoCo body's center
of mass. Retain the model and Vizard gravity metadata on the scene and
reject duplicate gravity attachment.

Allow NBodyGravity sources to retain a shared GravBodyData descriptor.
Resolve the gravity model, central-body flag, and ephemeris input from
the descriptor so the same configuration can be shared by conventional
spacecraft and MuJoCo dynamics. Initialize descriptor-backed gravity
models during Reset and warn when an orientation-dependent model has no
ephemeris input.

Expose descriptor-backed sources to Python as
addGravitySourceFromBody(). Keep the existing manual
addGravitySource(..., isCentralBody=...) interface unchanged, including
support for its keyword argument.

This enables gravity models and SPICE connections created by
simIncludeGravBody to be reused directly by MuJoCo scenes without
duplicating their configuration.
schaubh added a commit that referenced this pull request Jul 22, 2026
schaubh added a commit that referenced this pull request Jul 22, 2026
Add an optional zeroBase setting to PlanetEphemeris so generated planet
states can be expressed relative to another body propagated by the same
module instance. Preserve the existing heliocentric behavior when
zeroBase is left empty.

Resolve the selected body during Reset using case-insensitive name
matching and report an initialization error when the requested body is
not configured in the module. Compute all heliocentric states before
subtracting the selected body's position and velocity, ensuring the
translation is independent of body ordering. Leave planet names,
timestamps, attitudes, attitude rates, and orientation flags unchanged.

Expand the PlanetEphemeris unit tests to verify:

- the default empty zeroBase value
- position and velocity translation at multiple simulation times
- zero position and velocity for the selected base body
- preservation of attitude and message metadata
- case-insensitive body-name matching
- rejection of bodies from outside the module instance

Document zeroBase configuration, default behavior, and the requirement
that the reference body be propagated by the same PlanetEphemeris
instance. Clarify that changing the output origin does not introduce
hierarchical or mutually coupled orbital propagation.

Update scenarioCustomGravBody to use Itokawa as the output origin,
placing the planet and spacecraft states in a common asteroid-centered
translational frame.
schaubh added a commit that referenced this pull request Jul 22, 2026
Example uses both Spice and planetEphemeris message states.
@schaubh
schaubh deleted the feature/grav_factory_mujoco branch July 22, 2026 02:31
schaubh added a commit that referenced this pull request Jul 22, 2026
schaubh added a commit that referenced this pull request Jul 22, 2026
@github-project-automation github-project-automation Bot moved this to ✅ Done in Basilisk Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

2 participants