# Configuration Parameter Reference

[Configuration System](https://thanhndv212.github.io/figaroh-plus/concepts/configuration/index.md) explains the two config *formats* (unified vs. legacy) and how they're parsed. This page is the field-by-field glossary for what each parameter in the `calibration:` and `identification:` sections actually *means* — units, which pipeline step consumes it, and its unified-format equivalent where one exists.

Field names below match the **legacy flat format**, since that's what you see verbatim in an existing config file (the legacy format was removed in 1.0; these are the keys `config_migration` reads). The **Unified path** column gives the equivalent key under `tasks.calibration.*` / `tasks.identification.*` in the unified format — `unified_to_legacy_config` and `unified_to_legacy_identif_config` (both in `figaroh/src/figaroh/*/config.py`) convert one to the other, so the two formats agree on meaning even though the layout differs.

## `calibration:` section

| Field                 | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | Unified path                                                                                                                                                                            |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `calib_level`         | Kinematic-error model: `joint_offset` (one offset per joint, about or along its own axis) or `full_params` (six placement errors per joint, translation and rotation vector in the joint frame)                                                                                                                                                                                                                                                                         | `parameters.calibration_level`                                                                                                                                                          |
| `estimation`          | Which parameters to estimate and how: `method` (`structural` default, `excitation`, `map`, `map_cv`, `cv_subset`), `priors`, `noise_std`, cross-validation settings. See [Calibration estimation methods](https://thanhndv212.github.io/figaroh-plus/concepts/calibration_estimation/index.md)                                                                                                                                                                          | `parameters.estimation`                                                                                                                                                                 |
| `non_geom`            | Also identify joint elasticity (gravity-torque-driven compliance, one term per active joint) on top of the geometric model                                                                                                                                                                                                                                                                                                                                              | `parameters.include_non_geometric`                                                                                                                                                      |
| `base_frame`          | URDF frame name at the **start** of the kinematic chain                                                                                                                                                                                                                                                                                                                                                                                                                 | `kinematics.base_frame`                                                                                                                                                                 |
| `tool_frame`          | URDF frame name at the **end** of the chain (usually the gripper/tool mount)                                                                                                                                                                                                                                                                                                                                                                                            | `kinematics.tool_frame`                                                                                                                                                                 |
| `base_to_ref_frame`   | *(optional, eye-hand/camera mode only)* A frame reachable from `base_frame` via a **known** transform (e.g. a camera housing anchor)                                                                                                                                                                                                                                                                                                                                    | `eye_hand.camera_frame` (requires `eye_hand.enabled: true`)                                                                                                                             |
| `ref_frame`           | *(optional, eye-hand/camera mode only)* The frame the chain restarts from after the known `base_to_ref_frame` segment; the *unknown* camera/anchor pose being estimated sits between `ref_frame` and the true world frame                                                                                                                                                                                                                                               | `eye_hand.reference_frame` (requires `eye_hand.enabled: true`)                                                                                                                          |
| `markers[].ref_joint` | Joint the external marker is rigidly mounted near; its offset from `tool_frame` is what gets estimated (`pEEx/y/z`, `phiEEx/y/z`; `pEEx_k` ... for marker `k`). Several markers are points on the same `tool_frame`, see [Several points on the tool](#several-points-on-the-tool)                                                                                                                                                                                      | `measurements.markers[].reference_joint` — written by convention, but **not currently read back** by `_extract_marker_info` (only `measurable_dof`, from the first marker, is consumed) |
| `markers[].measure`   | 6-DOF boolean mask `[x, y, z, roll, pitch, yaw]` — which axes the external sensor (mocap/vision/contact) actually reports for that marker. Every marker uses the first marker's mask                                                                                                                                                                                                                                                                                    | `measurements.markers[].measurable_dof`                                                                                                                                                 |
| `free_flyer`          | `True` if the robot's base itself is unconstrained/floating in the model (mobile-base robots with an unknown per-sample base pose)                                                                                                                                                                                                                                                                                                                                      | `kinematics.free_flying_base`                                                                                                                                                           |
| `base_pose`           | Initial guess `[x, y, z, roll, pitch, yaw]` (m, rad) for the `base_frame` → world (or anchor → camera, in eye-hand mode) transform being estimated                                                                                                                                                                                                                                                                                                                      | `measurements.poses.base_pose`                                                                                                                                                          |
| `tip_pose`            | Initial guess `[x, y, z, roll, pitch, yaw]` (m, rad) for the `tool_frame` → marker transform being estimated                                                                                                                                                                                                                                                                                                                                                            | `measurements.poses.tool_pose`                                                                                                                                                          |
| `coeff_regularize`    | **Removed in 1.0 (#120, #185), default 0.** One L2 weight that robot cost functions applied to every joint parameter, penalising metres and radians alike. Core never applied it; a non-zero value is now a `ConfigurationError` (the migration tool writes 0 and warns). Use `estimation.method: map` instead (priors of physical size per parameter group, [estimation methods](https://thanhndv212.github.io/figaroh-plus/concepts/calibration_estimation/index.md)) | `parameters.regularization_coefficient`                                                                                                                                                 |
| `outlier_eps`         | Position error (**meters**, norm of the measured x/y/z residuals of a sample, worst marker) above which a sample is excluded and the rest refitted, for up to `max_iterations` fits. Rotational components do not take part; with no measured position component nothing is excluded. Excluded samples and their errors are in the evaluation (`excluded_samples`, `excluded_sample_errors`) and the report                                                             | `parameters.outlier_threshold`                                                                                                                                                          |
| `random_seed`         | Seed for the random configurations that select the identifiable parameter set (default 0). The selection, hence the result, does not depend on any global random state; the seed is recorded in the run provenance                                                                                                                                                                                                                                                      | `parameters.random_seed`                                                                                                                                                                |
| `data_file`           | Path to the CSV of recorded `(joint configuration, measured marker pose)` samples                                                                                                                                                                                                                                                                                                                                                                                       | `data.source_file`                                                                                                                                                                      |
| `sample_configs_file` | Optional: path cross-referencing which planned/optimal configuration each `data_file` row corresponds to. Traceability only — not required for the fit itself                                                                                                                                                                                                                                                                                                           | `data.sample_configurations_file`                                                                                                                                                       |
| `nb_sample`           | Number of samples expected from `data_file`                                                                                                                                                                                                                                                                                                                                                                                                                             | `data.number_of_samples`                                                                                                                                                                |

Why the camera pose is a free parameter, not a small offset

Everything else in `full_params`/`joint_offset` calibration treats the URDF as *approximately* right — each joint gets a small correction around its known nominal placement. An add-on eye-in-hand/eye-to-hand camera is different: its housing-to-robot mounting pose usually isn't known precisely from CAD/assembly at all, so it can't be treated as a small perturbation. `base_to_ref_frame`/`ref_frame` handle this by inserting the camera as a genuine 6-DOF unknown *in the middle of the chain* (`base_pose` is a real initial guess, not a near-zero one) rather than folding it into the same small-offset parameters as every other joint.

That's also what makes eye-hand calibration a specialized, harder case: this unknown camera-pose block is estimated *simultaneously*, from the same measurements, as the per-joint offsets of every joint the camera observes through — "camera is off by X" and "joint N is off by Y" can produce very similar marker-pose residuals, which can leave the problem under-determined or poorly conditioned. Priors (`estimation.method: map`) and deliberately exciting poses that vary joint loading/configuration widely (`sample_configs_file`, D-optimal design a la `tiago_pro/generate_optimal_configs.py`) are the two practical levers against this. A plain single-anchor unknown base frame — `base_frame` set to `universe`/`base_footprint` with no `base_to_ref_frame`, as in TiagoPro's `tiago_pro_calibration_config.yaml` (`known_baseframe=False` in `run_calibration.py`) — doesn't have this coupling, because nothing downstream of that single anchor is *itself* another unknown sensor mount; it's one 6-DOF unknown at the root, not one inserted mid-chain and re-estimated jointly with everything past it.

### Several points on the tool

Each entry of `measurements.markers` is one measured point (or pose) on the same `tool_frame`, for example the points of one mocap rigid body. The CSV has columns `x1, y1, z1, x2, ...` per marker, and each marker `k` gets its own offset `pEEx_k, pEEy_k, pEEz_k` (and `phiEE*_k` when orientation is measured); the base frame and the joint parameters are shared. Residual rows are ordered marker, then component, then sample.

What several points do and do not give (figaroh-plus#119):

- **The same identifiable joint parameters as one point.** Free point offsets absorb any rotation of the tool frame itself, so a joint offset about the tool axis stays unidentifiable. On a TIAGo arm, four points keep exactly the joint parameters one point keeps.
- **Smaller standard errors**, about `1/sqrt(n_points)` when the points' noise is independent. Points of one rigid body are not fully independent, so expect less.
- **Not necessarily better prediction.** On the TIAGo mocap reference, a four-point fit did not predict held-out postures better than marker 1 alone (`full_params`: 3.39 against 2.80 mm on marker 1); the extra points' rows bring their own errors (reflections, rigid-body tracking, unmodelled wrist effects) into every parameter.
- **One bad point affects the whole sample.** Outlier exclusion (`outlier_eps`) uses each sample's worst point, so a misreflected point removes that sample. A missing (occluded) point, i.e. an empty cell, is refused by the loader with its CSV rows; exclude them with `del_list`.

Decide per robot and dataset: compare held-out errors per point (the validation report lists them) with a one-point fit before adopting more points.

Eye-hand / camera calibration now has a unified-format equivalent

`base_to_ref_frame`/`ref_frame` map to `tasks.calibration.eye_hand.{camera_frame,reference_frame}` (with `eye_hand.enabled: true`) — the unified schema template (`templates/base_robot_config.yaml`) already reserved this section; `unified_to_legacy_config` just didn't read it. Fixed, so eye-hand configs like `examples/tiago/config/tiago_config_hey5.yaml` are no longer stuck in the legacy format — see [Migrating from legacy to unified format](#migrating-from-legacy-to-unified-format) below. (`free_flyer`/`kinematics.free_flying_base` had a similar wrong-key bug — the converter read `parameters.free_flyer`, a key the template never defines — fixed the same way.)

## `identification:` section

### `robot_params`

| Field                                                   | Meaning                                                                                                                                                                       | Unified path                                                                                                                                                               |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `q_lim_def`, `dq_lim_def`, `ddq_lim_def`, `tau_lim_def` | Joint position/velocity/acceleration/torque limit margins                                                                                                                     | `joints.joint_limits.{position,velocity,acceleration,torque}` — **parsed but not currently consumed anywhere in the identification pipeline** (kept for schema/future use) |
| `fv`                                                    | Viscous friction coefficient per joint (N·m·s/rad)                                                                                                                            | `mechanics.friction_coefficients.viscous` — used only if `has_friction`                                                                                                    |
| `fs`                                                    | Coulomb/static friction coefficient per joint (N·m)                                                                                                                           | `mechanics.friction_coefficients.static` — used only if `has_friction`                                                                                                     |
| `Ia`                                                    | Reflected actuator (motor + gearbox) inertia per joint (kg·m²)                                                                                                                | `mechanics.actuator_inertias` — used only if `has_actuator_inertia`                                                                                                        |
| `offset`                                                | Constant joint torque offset per joint (N·m) — electrical/sensor bias term                                                                                                    | `mechanics.joint_offsets` — used only if `has_joint_offset`                                                                                                                |
| `Iam6`, `fvm6`, `fsm6`                                  | Same three quantities as `Ia`/`fv`/`fs`, but for the shared "6th motor" of a differential-coupled wrist (two motors jointly drive the last two wrist axes, e.g. Staubli TX40) | `coupling.{Iam6,fvm6,fsm6}` — used only if `has_coupled_wrist`                                                                                                             |
| `reduction_ratio`                                       | Per-joint gear reduction ratio (motor turns per joint turn); sign encodes actuation direction                                                                                 | `mechanics.reduction_ratios`                                                                                                                                               |
| `ratio_essential`                                       | Threshold (%) for the "essential parameters" selection technique (Pham et al., 1995)                                                                                          | `mechanics.ratio_essential` — **documented intent only; not currently wired into any solver in this codebase**                                                             |

### `problem_params`

| Field                     | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                      | Unified path                                     |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `is_external_wrench`      | Include a measured force/torque sensor wrench as a regressor input                                                                                                                                                                                                                                                                                                                                                                           | `problem.include_external_forces`                |
| `is_joint_torques`        | Regress against joint torque signals (standard inverse-dynamics identification; almost always `True`)                                                                                                                                                                                                                                                                                                                                        | `problem.use_joint_torques`                      |
| `force_torque`            | Which F/T channels to use (e.g. `['Fx','Fy','Fz']` or `['All']`) — only applied if `is_external_wrench` is `True`                                                                                                                                                                                                                                                                                                                            | `problem.force_torque_sensors`                   |
| `external_wrench_offsets` | Also identify a constant bias offset on the F/T sensor reading                                                                                                                                                                                                                                                                                                                                                                               | `problem.external_wrench_offsets`                |
| `has_friction`            | Include the `fv`/`fs` columns in the regressor                                                                                                                                                                                                                                                                                                                                                                                               | `problem.model_components.friction`              |
| `has_actuator_inertia`    | Include the `Ia` column in the regressor                                                                                                                                                                                                                                                                                                                                                                                                     | `problem.model_components.actuator_inertia`      |
| `has_joint_offset`        | Include the `offset` column in the regressor                                                                                                                                                                                                                                                                                                                                                                                                 | `problem.model_components.joint_offset`          |
| `is_static_regressor`     | Include the friction + offset ("static") regressor block                                                                                                                                                                                                                                                                                                                                                                                     | *(no unified equivalent found — always derived)* |
| `is_inertia_regressor`    | Include the rigid-body inertial-parameter regressor block                                                                                                                                                                                                                                                                                                                                                                                    | *(no unified equivalent found — always derived)* |
| `has_coupled_wrist`       | Last two wrist joints share differential actuation → adds the `Iam6`/`fvm6`/`fsm6` terms and a coupling transform to the regressor                                                                                                                                                                                                                                                                                                           | `coupling.has_coupled_wrist`                     |
| `embedded_forces`         | Express the external wrench in a body-embedded (tool) frame rather than a fixed/world frame                                                                                                                                                                                                                                                                                                                                                  | *(no unified equivalent found)*                  |
| `qr_relative_tolerance`   | *(optional)* QR rank threshold as a fraction of the largest pivot. Columns whose pivot falls below it are treated as unidentifiable instead of fitting noise. Unset: only the absolute `1e-6` threshold applies. `1e-4` is a reasonable start when the log warns about an ill-conditioned base regressor                                                                                                                                     | `problem.qr_relative_tolerance`                  |
| `active_joints`           | *(optional)* Restrict identification to this explicit subset of joint names, instead of every active joint in the chain                                                                                                                                                                                                                                                                                                                      | `joints.active_joints`                           |
| `torque_fit_joints`       | *(optional)* Active joints whose measured effort enters the fit and the fit/validation statistics. The other active joints keep their kinematics in the regressor (their motion still loads the fitted joints), but their effort is neither fitted nor scored; validation lists them under `not_fitted_joints`. Use it for joints whose effort signal is not trusted (unknown force constant, heavy quantisation). Unset: every active joint | `problem.torque_fit_joints`                      |

### `processing_params`

| Field                           | Meaning                                                                                                                                                                                                                                                                                                 | Unified path                                                                                                         |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `cut_off_frequency_butterworth` | Low-pass Butterworth filter cutoff frequency (Hz) applied to position/velocity/acceleration/torque signals before regression                                                                                                                                                                            | `signal_processing.cutoff_frequency`                                                                                 |
| `ts`                            | Sample period (**seconds**) of the recorded data                                                                                                                                                                                                                                                        | `signal_processing.sampling_frequency` *(unified format specifies the rate directly, in Hz, rather than the period)* |
| `filter_config.filter_params`   | Arguments of the median + Butterworth filter (`f_sample`, `f_butter`, `nbutter`, `med_fil`). In the unified format, `f_sample`, `f_butter` and `nbutter` default to `sampling_frequency`, `cutoff_frequency` and `filter_order` (4); an explicit `signal_processing.filter_params` entry overrides them | `signal_processing.filter_params`                                                                                    |

`ts` → `nb_samples` is a rate, not a count

Despite the name, the legacy parser computes `identif_config["nb_samples"] = int(1 / ts)` — i.e. an implied samples-per-second rate, not the number of rows in your data file. Don't be misled by the field name; it isn't used as a row count anywhere downstream.

### `tls_params` (optional — known-payload identification)

| Field               | Meaning                                                                                                                                          |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `mass_load`         | Known mass (kg) of a test payload attached during a supplementary run, used to refine the identified inertial parameters via total-least-squares |
| `which_body_loaded` | Index of the link/body in the regressor that carries that payload                                                                                |
| `sync_joint_motion` | **Parsed by nothing** — not even read into `identif_config` by the legacy parser. Effectively decorative today.                                  |

### `trajectory_params` (optional — used by `optimal_trajectory.py`, not `identification.py`)

| Field                           | Meaning                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `n_wps`                         | Number of waypoints in the generated exciting trajectory                                                                                                                                                                                                                                                                                                                                             |
| `freq`                          | Trajectory sample frequency (Hz)                                                                                                                                                                                                                                                                                                                                                                     |
| `t_s`                           | Time window between waypoints (s)                                                                                                                                                                                                                                                                                                                                                                    |
| `soft_lim`                      | Joint-limit safety margin/discount applied during trajectory search                                                                                                                                                                                                                                                                                                                                  |
| `max_attempts`                  | Maximum attempts to find a feasible trajectory before giving up                                                                                                                                                                                                                                                                                                                                      |
| `max_iterations`                | IPOPT iteration cap per trajectory segment (default 200; unified config: `problem.max_iterations`)                                                                                                                                                                                                                                                                                                   |
| `segment_attempts`              | Solves per trajectory segment: a failed segment is retried from a new random initial guess (default 1 = no retry; unified config: `problem.segment_attempts`)                                                                                                                                                                                                                                        |
| `collision_margin`              | Minimum clearance (m) between collision pairs (default 0.01). Pairs: the geometry model's, or, when it has none, every two geometries on non-adjacent bodies (the world and the first moving body count as adjacent); `srdf` removes pairs (#143). Initial guesses and every solved segment must keep this clearance along the whole spline, checked at `collision_check_frequency` (default 200 Hz) |
| `collision_checks_per_interval` | Check points per waypoint interval in the collision constraint, ending at the waypoint (default 1 = waypoints only)                                                                                                                                                                                                                                                                                  |
| `collision_screen`              | Optional (m): exact distances only for pairs within it, the others count as the screen; faster with many mesh pairs (UR10 example: 0.02). Default none = all distances exact                                                                                                                                                                                                                         |

## Migrating from legacy to unified format

The legacy flat format was removed in 1.0 (it warned since 0.4.6). Loading a legacy config, whether via `BaseCalibration`/`BaseIdentification.load_param` or `figaroh.utils.config_parser.get_param_from_yaml`, raises a `ConfigurationError` that names the command below. The migration tool itself still reads legacy files.

`figaroh.utils.config_migration` converts a legacy config to unified format automatically, using the exact field mapping in the tables above:

```
python -m figaroh.utils.config_migration \
    --input examples/tiago/config/tiago_config_hey5.yaml \
    --output examples/tiago/config/tiago_config_hey5_unified.yaml \
    --urdf urdf/tiago_48_hey5.urdf   # optional: runs a round-trip self-check
```

- `--template {base,manipulator,humanoid}` (default `base`) picks which template the output `extends:` — `base` (extending `base_robot_config.yaml` directly) is the safest default since it doesn't risk silently inheriting a specialized template's default the legacy file didn't actually have.
- Passing `--urdf` runs the output back through the real `unified_to_legacy_config`/`unified_to_legacy_identif_config` and diffs it against the original legacy values — the same self-check mechanism that caught the `free_flyer`/`eye_hand` bugs above. A migration that reports `MISMATCHES` should not be trusted without investigating why.
- Fields with no unified-format consumer today (`is_static_regressor`, `is_inertia_regressor`, `sync_joint_motion`, the unused joint-limit fields — see the tables above) are preserved under the output's `custom:` section rather than silently dropped, even though nothing reads them back yet.
- The tool only converts the file; it doesn't rewrite the example script that loads it, or verify the migrated config still produces the same calibration/identification *results* on real data — treat that as a required follow-up before switching an example over, the same way the `calc_updated_fkm` merge was validated against real TIAGo/TIAGo Pro/TALOS/UR10 data before landing.

## Next steps

- [Configuration System](https://thanhndv212.github.io/figaroh-plus/concepts/configuration/index.md) — format structure and template inheritance.
- [Calibration Walkthrough](https://thanhndv212.github.io/figaroh-plus/tutorials/calibration_walkthrough/index.md) and [Identification Walkthrough](https://thanhndv212.github.io/figaroh-plus/tutorials/identification_walkthrough/index.md) — these fields in context, end to end.
