a8cf4e012d
PiperOrigin-RevId: 869091889 Change-Id: Ib5ec2e451c7037cc92b4cb1a9c58d05f0049b298
97 lines
4.0 KiB
Markdown
97 lines
4.0 KiB
Markdown
# System Identification Toolbox
|
|
|
|
[](https://colab.research.google.com/github/google-deepmind/mujoco/blob/main/python/mujoco/sysid/sysid.ipynb)
|
|
|
|
Given a MuJoCo model and recorded sensor data, find parameters
|
|
that make simulation match reality. By default, the library uses
|
|
nonlinear least-squares with box constraints to minimize the difference
|
|
between measured and simulated (predicted) outputs. Residuals
|
|
can be modified by static or optimized parameters, such as
|
|
weights and time-delays.
|
|
|
|
The optimizer uses Gauss-Newton with finite-difference Jacobians. Each
|
|
parameter perturbation requires an independent simulation rollout. All
|
|
of them execute in a single batched call to `mujoco.rollout`, parallelized
|
|
across threads.
|
|
|
|
## Pipeline
|
|
|
|
**You provide:**
|
|
- One or more `ModelSequences` each bundling a single `MjSpec` with one or
|
|
more sequences of measured data. All will be optimized jointly.
|
|
- A `ParameterDict` defining differentiable `Parameter`s with bounds.
|
|
- Callbacks to apply `Parameter`s to an `MjSpec` (individually or jointly)
|
|
- (optional) Functions (`build_model`, `custom_rollout`, `modify_residual`)
|
|
that override the default residual function behavior.
|
|
|
|
**The framework:**
|
|
- Composes user code into a residual function (`build_residual_fn`).
|
|
- Optimizes parameters via batched parallel rollouts (`optimize`).
|
|
- Saves results and generates an HTML report (`save_results`, `default_report`).
|
|
|
|
## What Can You Identify?
|
|
|
|
You can optimize any parameter that differentiably modifies the final
|
|
residuals. Common use cases include:
|
|
|
|
**Physics parameters** settable on `MjSpec`. Most parameters in MjSpec
|
|
can be easily set directly by user-provided callbacks:
|
|
|
|
| Target | Approach |
|
|
|---|---|
|
|
| Contact sliding friction | `spec.pair("cp").friction[0] = p.value[0]` |
|
|
| Joint damping | `spec.joint("j1").damping = p.value[0]` |
|
|
|
|
Convenience functions are provided for common system identification
|
|
parameterizations that cannot be trivially applied to an MjSpec:
|
|
|
|
| Target | Approach |
|
|
|---|---|
|
|
| Body mass | `body_inertia_param(..., InertiaType.Mass)` |
|
|
| Body mass + center of mass | `body_inertia_param(..., InertiaType.MassIpos)` |
|
|
| Full inertia (10-D) | `body_inertia_param(..., InertiaType.Pseudo)` |
|
|
| Actuator P/D gains | `apply_pdgain(spec, "act1", p.value)` |
|
|
|
|
Full inertia uses the pseudo-inertia Cholesky parameterization
|
|
([Rucker & Wensing 2022](https://ieeexplore.ieee.org/document/9690029)),
|
|
guaranteeing physical consistency without singularities.
|
|
|
|
**Measurement parameters** such as sensor delays, gains, and biases are
|
|
properties of the measurement system, not the physics model. The library
|
|
provides utilities for applying these corrections to the residual after
|
|
rollout. They are functionally complete but their API is not yet final.
|
|
|
|
## Example
|
|
|
|
```python
|
|
import mujoco
|
|
from mujoco import sysid
|
|
|
|
# 1. Load model and define parameters.
|
|
spec = mujoco.MjSpec.from_file("robot.xml")
|
|
model = spec.compile()
|
|
|
|
def set_link1_mass(spec, p):
|
|
spec.body("link1").mass = p.value[0]
|
|
|
|
params = sysid.ParameterDict()
|
|
params.add(sysid.Parameter(
|
|
"link1_mass", nominal=2.0, min_value=0.5, max_value=5.0,
|
|
modifier=set_link1_mass))
|
|
|
|
# 2. Load and package measured data.
|
|
# arrays assumed to be in MuJoCo order, otherwise pass names argument
|
|
control = sysid.TimeSeries.from_control_names(times, ctrl_array, model)
|
|
measureddata = sysid.TimeSeries.from_names(times, measurement_array, model)
|
|
initial_state = sysid.create_initial_state(model, qpos_0, qvel_0)
|
|
ms = sysid.ModelSequences("robot", spec, "traj_1", initial_state, control, measureddata)
|
|
|
|
# 3. Build residual, optimize, save.
|
|
residual_fn = sysid.build_residual_fn(models_sequences=[ms])
|
|
opt_params, opt_result = sysid.optimize(initial_params=params, residual_fn=residual_fn)
|
|
sysid.save_results("results/", [ms], params, opt_params, opt_result, residual_fn)
|
|
```
|
|
|
|
`default_report` generates an interactive HTML report with videos, measurement comparisons,
|
|
parameter tables, and confidence intervals.
|