Skip to content

Rewrite Inertia Estimation Script with Global Regression#110

Open
theelims wants to merge 1 commit intomjbots:mainfrom
theelims:main
Open

Rewrite Inertia Estimation Script with Global Regression#110
theelims wants to merge 1 commit intomjbots:mainfrom
theelims:main

Conversation

@theelims
Copy link
Copy Markdown

Rewrite inertia estimation using global regression

The original measure_inertia.py had several issues that inflated the variance of the result. This PR replaces the estimation strategy with a more statistically robust approach while keeping the same CLI interface and moteus communication pattern.

Problems with the original

Incorrect acceleration estimate. The two-point formula used end_velocity / delta_time, implicitly assuming the motor started from rest at the 25% mark. The correct formula is Δv / Δt. This bias varied with torque level and was a significant contributor to variance.

Friction ignored. The model τ = J·α treats all applied torque as going into acceleration. In reality τ = J·α + τ_friction. By ignoring friction, each per-trace J estimate is biased by τ_friction / α, and since that bias is larger at low torques (small α), the estimates are inconsistent across the sweep.

Per-trace median is statistically weak. Computing J independently for each trace and taking a median discards the relationship between traces and amplifies the effect of individual noisy estimates.

Fixed 25–75% window captures backlash. For motors with a planetary gearbox the initial samples are dominated by backlash and stiction, not clean acceleration. A fixed window start cannot account for how long backlash takes to clear, which varies with torque level.

Config not restored. servo.pid_dq.max_desired_rate was overridden for the measurement but never restored on exit.

Changes

Bidirectional sweep. Each torque magnitude is applied in both CW and CCW directions. Friction opposes motion, so it appears as a consistent offset in the global fit rather than corrupting J directly. Both directions contribute points to the regression, and the intercept of the fit gives a direct estimate of the friction torque.

Sliding best-R² window. Instead of a fixed 25–75% window or a velocity threshold, a window of 50% of the trace slides across the full recording. The position that maximises R² of a linear fit to v(t) is selected. Because the backlash region is inherently non-linear, the post-backlash clean acceleration phase wins the search automatically - no threshold tuning required.

Global OLS regression. All (α, τ) pairs from both directions and all torque levels are fed into a single τ = J·α + τ_friction least-squares fit. This uses all the data jointly, so no information is thrown away and outlier traces have proportionally less influence.

Bootstrap CI. 4000 bootstrap resamples of the (α, τ) pairs give a proper 95% confidence interval on J.

Starting torque scaled to motor. The sweep now starts at 1% of --torque-limit rather than a hardcoded 10 mN·m, making the script sensible for a wider range of motors out of the box.

Config restore. servo.pid_dq.max_desired_rate is restored on exit via conf load, which discards all in-RAM config changes since the last conf write. This works correctly on normal exit, cancellation, and exceptions.

Visualisation. A matplotlib summary is shown after the sweep: the left panel shows every v(t) trace with the selected window highlighted and the linear fit overlaid; the right panel shows the τ vs α scatter plot with the global fit line and 95% CI band, coloured consistently with the left panel.

image

measure_inertia: rewrite inertia estimation with global regression

- Bidirectional (CW + CCW) torque sweeps so friction cancels in regression
- Replace two-point accel estimate with sliding best-R² window (50% of
  trace) that automatically skips planetary gear backlash transients
- Single global OLS fit τ = J·α + τ_friction across all traces replaces
  per-trace median; intercept gives friction bias estimate
- Bootstrap 95% CI reported alongside J estimate
- Starting torque set to 1% of torque limit
- Restore servo.pid_dq.max_desired_rate via conf load after measurement
- Add matplotlib summary: per-trace v(t) with best window highlighted,
  global τ vs α scatter with fit line and CI band
@HenrikHorpedal1
Copy link
Copy Markdown

Thoughts on adding a note to the output indicating that when rotor_to_output_ratio ≠ 1, the reported inertia is the effective inertia seen from the output rather than the rotor?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants