scenarioCompareRwPanels

Third scenario in the dynamics-engine comparison series (see scenarioCompareOrbit for the introduction).

This scenario models a free-floating spacecraft: a central hub carrying three orthogonal reaction wheels (commanded with constant motor torques) and two symmetric solar arrays modeled as torsional spring-damper hinged rigid bodies, initially deflected. With gravity off, the comparison isolates the internal multi-body coupling: wheel reaction torques, panel flexing, and the hub’s rigid-body response.

Matching the two engines requires accounting for how each models the components:

  1. Reaction wheels. Basilisk’s back-substitution balanced C++ Module: reactionWheelStateEffector adds no mass or inertia to the system; it injects only the spin-axis reaction and gyroscopic terms. MuJoCo models each wheel as a real spinning rigid body. The two are made equivalent by folding each wheel’s inertia tensor into the BSM hub inertia, setting the BSM Js to the wheel axial inertia, and giving the MuJoCo wheel bodies negligible mass. A non-zero wheel mass would shift the system center of mass differently in the two formulations once the offset panels are attached.

  2. Hinged panels. The C++ Module: hingedRigidBodyStateEffector is a torsional spring(k)-damper(c) hinge with the panel center of mass a distance d from the hinge axis. The equivalent MuJoCo construction is a hinge joint with matching stiffness and damping, the child body’s center of mass offset by -d along its local x-axis (the effector’s sign convention), and a matching inertia tensor. The positive-x root frame is rotated by 180 degrees about z so both arrays extend outward and their hinge axes are mirrored.

The hub attitude is compared with the principal rotation angle of the relative direction cosine matrix, as in scenarioCompareTorque. The MuJoCo scene is run with highOrderAttitudeIntegration enabled so the hub quaternion is advanced at the integrator’s full order, matching BSM’s MRP attitude order.

The script is found in the folder basilisk/examples/dynamicsComparison and executed by using:

python3 scenarioCompareRwPanels.py

Illustration of Simulation Results

The hub angular velocities from the two engines lie on top of one another as the wheels spin up and the panels oscillate.

../../_images/scenarioCompareRwPanels_rate_x.svg ../../_images/scenarioCompareRwPanels_rate_y.svg ../../_images/scenarioCompareRwPanels_rate_z.svg

The panel hinge angles match between the two engines through the damped oscillation.

../../_images/scenarioCompareRwPanels_panelPositive.svg ../../_images/scenarioCompareRwPanels_panelNegative.svg

The cross-engine hub attitude difference remains near \(10^{-11}\) rad for this eleven-degree-of-freedom system. The small positive wheel mass required by MuJoCo sets this nominal floor; reducing that bookkeeping mass lowers the difference further.

../../_images/scenarioCompareRwPanels_attError.svg

Runtime cost

The optional local benchmark reports the wall-clock cost of propagating this system with each engine as the median of five measured trials after one discarded warm-up. Model setup is excluded. Both the absolute times and speedup are specific to the machine and build. Generate the optional local CSV with make -C docs comparison-runtime-tables; see scenarioCompareOrbit for the benchmark requirements and interpretation.

Next comparison: scenarioCompareFlexPanels increases the number of flexible degrees of freedom and measures runtime scaling.

scenarioCompareRwPanels.buildBSM(dt, tf, recordDt, record=True)[source]

Build the back-substitution hub-wheel-panel simulation without propagating it.

Parameters:
  • dt (float) – integrator time step [s]

  • tf (float) – final simulation time [s]

  • recordDt (float) – recorder sampling period [s]

  • record (bool, optional) – attach state, wheel, and panel recorders. Defaults to True.

Returns:

(simulation, outputs, handles).

Return type:

tuple

scenarioCompareRwPanels.buildMujoco(dt, tf, recordDt, record=True)[source]

Build the MuJoCo hub-wheel-panel simulation without propagating it.

Parameters:
  • dt (float) – integrator time step [s]

  • tf (float) – final simulation time [s]

  • recordDt (float) – recorder sampling period [s]

  • record (bool, optional) – attach state, wheel, and panel recorders. Defaults to True.

Returns:

(simulation, outputs, handles).

Return type:

tuple

scenarioCompareRwPanels.hubInertiaBSM()[source]

BSM hub inertia: bare hub plus the three folded-in wheel tensors.

Returns:

3x3 hub inertia tensor [kg*m^2].

Return type:

numpy.ndarray

scenarioCompareRwPanels.mujocoModel()[source]

Return the MJCF model: hub, three reaction wheels, two hinged panels.

scenarioCompareRwPanels.panelRootDcm(hingeX)[source]

Return the root-frame DCM that makes both panels extend away from the hub.

scenarioCompareRwPanels.plotResults(timeAxis, omegaBSM, omegaMujoco, panelBSM, panelMujoco, attError)[source]

Build the scenario figures.

Parameters:
  • timeAxis (numpy.ndarray) – sample times [s]

  • omegaBSM (numpy.ndarray) – BSM hub-rate history [rad/s]

  • omegaMujoco (numpy.ndarray) – MuJoCo hub-rate history [rad/s] (or None)

  • panelBSM (numpy.ndarray) – BSM panel-angle history [rad]

  • panelMujoco (numpy.ndarray) – MuJoCo panel-angle history [rad] (or None)

  • attError (numpy.ndarray) – cross-engine attitude error [rad] (or None)

Returns:

mapping from figure name to matplotlib figure.

Return type:

dict

scenarioCompareRwPanels.relativePrincipalAngle(sigmaBSM, sigmaMujoco)[source]

Per-sample principal rotation angle between two MRP attitude histories.

Parameters:
  • sigmaBSM (numpy.ndarray) – BSM MRP history, shape (N, 3)

  • sigmaMujoco (numpy.ndarray) – MuJoCo MRP history, shape (N, 3)

Returns:

principal angle per sample [rad].

Return type:

numpy.ndarray

scenarioCompareRwPanels.run(showPlots=False, saveJson=False, saveTiming=False, resultsDir=None)[source]

Main function, see scenario description.

Parameters:
  • showPlots (bool, optional) – if True, plot and show the simulation results. Defaults to False.

  • saveJson (bool, optional) – if True, write the comparison metrics to results/scenarioCompareRwPanels.json. Defaults to False.

  • saveTiming (bool, optional) – if True, measure the BSM-vs-MJScene wall-clock cost of this scenario and write results/scenarioCompareRwPanels_runtime.csv. Defaults to False.

  • resultsDir (str, optional) – explicit artifact directory. Defaults to the scenario results folder.

Returns:

mapping from figure name to matplotlib figure.

Return type:

dict

scenarioCompareRwPanels.runBSM(dt, tf, recordDt)[source]

Propagate the hub-wheel-panel system with the back-substitution C++ Module: spacecraft.

scenarioCompareRwPanels.runMujoco(dt, tf, recordDt)[source]

Propagate the same hub-wheel-panel system with the MJScene.

scenarioCompareRwPanels.writeJsonSummary(timeAxis, omegaBSM, omegaMujoco, wheelBSM, wheelMujoco, panelBSM, panelMujoco, attError, targetResults)[source]

Write a JSON summary of the comparison metrics to the results folder.

Parameters:
  • timeAxis (numpy.ndarray) – sample times [s]

  • omegaBSM (numpy.ndarray) – BSM hub-rate history [rad/s]

  • omegaMujoco (numpy.ndarray) – MuJoCo hub-rate history [rad/s] (or None)

  • wheelBSM (numpy.ndarray) – BSM wheel-speed history [rad/s]

  • wheelMujoco (numpy.ndarray) – MuJoCo wheel-speed history [rad/s] (or None)

  • panelBSM (numpy.ndarray) – BSM panel-angle history [rad]

  • panelMujoco (numpy.ndarray) – MuJoCo panel-angle history [rad] (or None)

  • attError (numpy.ndarray) – cross-engine attitude error [rad] (or None)

  • targetResults (str) – directory for the JSON artifact