Biomechanics Quick Start
This guide is for biomechanists who want to use MyoSuite to run forward simulations, extract kinematic and kinetic data, perform inverse dynamics, and interface with tools like OpenSim.
No machine learning background is required.
Key Concepts
MyoSuite simulates musculoskeletal models in MuJoCo. A few terms you will encounter:
MjData — the simulation state at the current time step (positions, velocities, forces).
qpos — generalised joint positions (angles in radians for rotational joints).
qvel — generalised joint velocities (rad/s).
actuator_force — net force/torque generated by each muscle actuator (N or N·m).
Frame skip — number of physics sub-steps per control call (default 10 × 2 ms = 20 ms control period). Change the control step per env with
EnvConfig(env_id, ctrl_dt=...)(see Machine Learning Quick Start).
Installation
pip install -U myosuite
# or with uv:
uv sync -p 3.10
See Installation for a from-source install and Python version support.
Running a Forward Simulation
from myosuite import make_env
import numpy as np
env = make_env('myoElbowPose1D6MRandom-v0')
obs, info = env.reset(seed=0)
# Access the underlying MuJoCo model and data
model = env.unwrapped.model # mujoco.MjModel
data = env.unwrapped.data # mujoco.MjData
print("Number of joints: ", model.njnt)
print("Number of muscles: ", model.nu)
print("Joint names: ", [model.joint(i).name for i in range(model.njnt)])
obs, info = env.reset()
for _ in range(100):
env.step(env.action_space.sample()) # random muscle excitations
env.close()
Note
env.unwrapped is the underlying MyoSuite env, which holds model, data and the state of the
muscle conditions. On an env straight from make_env these attributes also work without .unwrapped,
but not behind other wrappers (for example Stable-Baselines3’s Monitor or gymnasium’s
RecordEpisodeStatistics). Use env.unwrapped in code that may be wrapped.
Extracting Kinematics
from myosuite import make_env
import numpy as np
env = make_env('myoElbowPose1D6MRandom-v0')
obs, info = env.reset(seed=0)
records = []
for _ in range(500):
obs, reward, terminated, truncated, info = env.step(env.action_space.sample())
d = env.unwrapped.data
records.append({
"time": d.time,
"qpos": d.qpos.copy(), # joint angles (rad)
"qvel": d.qvel.copy(), # joint velocities (rad/s)
"xpos": d.xpos.copy(), # body Cartesian positions (m)
})
if terminated or truncated:
obs, info = env.reset()
# Summarise range of motion
qpos_array = np.array([r["qpos"] for r in records])
rom = np.ptp(qpos_array, axis=0) # peak-to-peak per joint
model = env.unwrapped.model
for i, r in enumerate(rom):
print(f" {model.joint(i).name:30s} ROM = {np.degrees(r):.1f} deg")
env.close()
Extracting Muscle Forces
data.actuator_force is the force of each actuator in N. MuJoCo reports a muscle’s tension with a
negative sign, so the peak force of a muscle is the most negative value. The resulting joint torques
are in data.qfrc_actuator:
from myosuite import make_env
import numpy as np
env = make_env('myoElbowPose1D6MRandom-v0')
obs, info = env.reset(seed=0)
force_records = []
for _ in range(500):
obs, reward, terminated, truncated, info = env.step(env.action_space.sample())
force_records.append(env.unwrapped.data.actuator_force.copy())
if terminated or truncated:
obs, info = env.reset()
forces = np.array(force_records)
model = env.unwrapped.model
print("Peak muscle forces (N):")
for i in range(model.nu):
print(f" {model.actuator(i).name:30s} {-forces[:, i].min():.1f}")
env.close()
Inverse Dynamics
MyoSuite includes a tutorial for computing joint torques from motion data.
See tutorials/3.3_Inverse_Dynamics.ipynb for a step-by-step walkthrough.
The key MuJoCo function is mujoco.mj_inverse(model, data), which fills
data.qfrc_inverse with the generalised forces required to produce the
observed acceleration:
import mujoco
import numpy as np
# After setting data.qpos, data.qvel, data.qacc:
mujoco.mj_inverse(model, data)
joint_torques = data.qfrc_inverse.copy() # N·m per generalised coordinate
Inverse Kinematics
See tutorials/3.2_Inverse_Kinematics.ipynb for an IK solver built on top of
MINK:
pip install -e ".[examples]" # install mink
python tutorials/files/3.2/inverse_kinematics.py
Replaying OpenSim Motion Files
MyoSuite can play back *.mot files exported from OpenSim.
See tutorials/3.5_Playback_Mot_File.ipynb for the full workflow.
The high-level steps are:
Load the motion file (column headers map to joint names).
Iterate over frames, setting
data.qposto the corresponding angles.Call
mujoco.mj_forward(model, data)to update all derived quantities.Extract whatever quantities you need (muscle forces, contact forces, etc.).
Body Centre of Mass and Ground Reaction Forces
Continuing with the model and data of the forward simulation above:
import mujoco
import numpy as np
mujoco.mj_forward(model, data)
# Subtree centre of mass for the whole body (world frame)
com = data.subtree_com[0].copy() # shape (3,)
# Contact forces (all contacts)
for i in range(data.ncon):
contact = data.contact[i]
force_torque = np.zeros(6)
mujoco.mj_contactForce(model, data, i, force_torque)
print(f"Contact {i}: force = {force_torque[:3]} N")
Available Musculoskeletal Models
Model |
DoF |
Muscles |
Example environment |
|---|---|---|---|
myoFinger |
4 |
5–6 |
|
myoElbow |
1 |
6 |
|
myoHand |
23 |
39 |
|
myoArm (hand-free) |
18 |
50 |
|
myoArm (full) |
27 |
63 |
|
myoLeg (14 joints plus the 6-DoF free root) |
20 |
80 |
|
myoTorso |
18 |
216 |
|
For the full environment listing — task variants, pathological conditions, and challenge IDs — see Environment Reference.
To inspect any model interactively:
python -m myosuite.utils.examine_sim -s $(python -c "import myo_sim; print(myo_sim.get_path('legacy/elbow/myoelbow_1dof6muscles.xml'))")
Pathological Conditions
Variant environments model common clinical conditions:
from myosuite import make_env
# Sarcopenia: 50 % reduction in peak muscle force
env = make_env('myoSarcElbowPose1D6MFixed-v0')
# Cumulative fatigue: activation history reduces muscle output
env = make_env('myoFatiElbowPose1D6MFixed-v0')
Each variant is the base env registered with the matching wrapper, so the same conditions (and motor
noise) can be applied to any other env, with your own parameters, through EnvConfig(env_id, features=...);
see Neuroscience Quick Start for examples and docs/wiki/cross-backend-contract.md for which envs
take which features.
Next Steps
tutorials/3.1_Analyse_Movements.ipynb— movement analysis with plottingtutorials/3.3_Inverse_Dynamics.ipynb— joint torque computationtutorials/3.4_Computed_Muscle_Control.ipynb— feedforward muscle control (CMC)Neuroscience Quick Start — sensory feedback and reflex controllers
Sports Medicine & Rehabilitation Quick Start — rehabilitation and clinical condition modelling