Skip to content

Commit 32e4352

Browse files
yeezhouyiclaude
andcommitted
docs: promote v0.2.1 to stable release
WSL2 paired A/B validation confirms ~12% cycle time reduction (4/5 pairs), all 10 runs pass quality gate. Move Native Linux benchmark to v0.2.2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 4443012 commit 32e4352

3 files changed

Lines changed: 35 additions & 40 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,14 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## v0.2.1-rc1 (2026-05-31)
5+
## v0.2.1 (2026-05-31)
66

77
### Performance
88
- Cache condensed-QP weight matrices and Hessian.
99
- Rebuild cost matrices only on Q/R/S hot update (cost_matrix_dirty_).
1010
- Preallocate MPCController per-cycle work vectors.
1111
- Reduce controller-layer Eigen heap allocations from 17+ to ~3 per cycle.
1212
- Reuse OSQP wrapper conversion buffers (q, l, u, primal, dual, P).
13-
- **Benchmark results:** Paired A/B (5 alternating pairs) confirms
14-
cached Hessian cycle time reduction: 3.06 ms → 2.69 ms (−12%, 4/5
15-
pairs show improvement). All 10 runs passed the ≤10% failed-cycle
16-
quality gate. See README for dual-reporting with cross-session and
17-
paired data.
1813

1914
### Fixed
2015
- Q/R/S hot-update ordering: rebuild P before gradient computation to ensure
@@ -27,6 +22,12 @@ All notable changes to this project will be documented in this file.
2722
`dy_buffer_` replace per-cycle `std::vector` allocations in UpdateBounds,
2823
UpdateGradient, and SetPrimalDualWarmStart.
2924

25+
### Benchmark
26+
- WSL2 paired A/B validation (10 runs, 5 alternating pairs) confirms
27+
~12% cycle time reduction: v0.2.0 3.06 ms → v0.2.1 2.69 ms (4/5 pairs
28+
show improvement). All 10 runs passed the ≤10% failed-cycle quality gate.
29+
- Native Linux characterization deferred to v0.2.2.
30+
3031
## v0.2.0 (2026-05-30)
3132

3233
### Added

README.md

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -219,19 +219,15 @@ to ~3. Solve time and cycle time improvements are consistent with this change.
219219
The pre-run is a controller re-start warm-up cycle and is not included in
220220
any aggregate. Runs 03–05 exceeded the 10% failed-cycle quality gate.
221221

222-
##### Paired A/B Validation (v0.2.0 vs v0.2.1-rc1)
222+
##### Paired A/B Validation (v0.2.0 vs v0.2.1)
223223

224-
A 10-run alternating A/B benchmark was conducted in a single session to
225-
control for environmental variability (5 × v0.2.0, 5 × v0.2.1-rc1, 65 s
226-
each, alternating every 1–2 runs to cancel order bias).
224+
A 10-run alternating A/B benchmark was conducted in a single WSL2 session
225+
to control for environmental variability (5 × v0.2.0, 5 × v0.2.1, 65 s
226+
each, alternating every 1–2 runs to cancel order bias). **All 10 runs
227+
passed the quality gate (failed-cycle rate ≤ 10%)**.
227228

228-
**All 10 runs passed the quality gate (failed-cycle rate ≤ 10%)**
229-
a substantial improvement over the initial batch where 3/5 runs exceeded
230-
the threshold. This suggests the earlier anomalous runs were driven by
231-
WSL2 scheduling state rather than the controller code itself.
232-
233-
| Metric | v0.2.0 (A, 5 runs) | v0.2.1-rc1 (B, 5 runs) | Δ |
234-
|--------|-------------------:|----------------------:|---|
229+
| Metric | v0.2.0 (A, 5 runs) | v0.2.1 (B, 5 runs) | Δ |
230+
|--------|-------------------:|-------------------:|---|
235231
| Total cycles | 24,600 | 26,149 ||
236232
| **Optimal solve rate** | **97.6%** | **98.1%** | **+0.5 pp** |
237233
| **Mean solve time** | 2,880 µs | 2,590 µs | −10.1% |
@@ -241,16 +237,14 @@ WSL2 scheduling state rather than the controller code itself.
241237
| **Hold rate** | 2.40% | 1.85% | −0.54 pp |
242238

243239
**Pairs with B < A cycle time: 4/5** — the cached Hessian benefit is
244-
confirmed under controlled conditions. The improvement magnitude (~12%
245-
cycle time reduction) is a more reliable causal estimate than the
246-
cross-session comparison above.
240+
confirmed under controlled conditions.
247241

248-
> **Note on absolute timing:** Solve/cycle times in this controlled
249-
> paired benchmark (2.5–3.0 ms) are lower than the earlier cross-session
250-
> runs (3.9–7.4 ms). This is attributed to differences in WSL2 system
251-
> load, cache state, and Gazebo scheduling across benchmark sessions.
252-
> The paired comparison controls for these variables, making the Δ
253-
> column the relevant metric.
242+
> **Validation scope:** This benchmark was conducted under WSL2
243+
> (Ubuntu 24.04 on Windows) and should not be interpreted as a hard
244+
> real-time guarantee. The controlled paired design isolates the
245+
> relative improvement of v0.2.1 changes from environmental factors.
246+
> Native Linux characterization remains planned as a future work item
247+
> (see [ROADMAP](ROADMAP.md)).
254248
255249
#### Known Issues
256250

@@ -259,9 +253,6 @@ cross-session comparison above.
259253
- **Sporadic `PRIMAL_INFEASIBLE` bursts with sentinel slack values (P2 — RESOLVED via warm-start hardening)**: On rare cycles (0–14% per run) OSQP returned status −3 (`PRIMAL_INFEASIBLE`) with slack variables at a sentinel value of 2,143,289,344 (0x7fc00000, a quiet NaN in IEEE 754 single-precision). Once triggered, the bad ADMM state could cascade via warm start, causing contiguous failure blocks. **Root cause identified:** The receding-horizon warm-start shift treated the partitioned decision vector z = [U, ε] as a monolithic block, interleaving U and slack components during the shift. This corrupted the slack initial guess, driving OSQP into an invalid ADMM state that propagated across cycles. **Fix:** Partitioned the warm-start shift into independent U-block and ε-block shifts, with `allFinite()` guards and error-checked reset on solver failure. Post-fix benchmarks confirm **zero sentinel occurrences across 22,179 cycles** (6 runs). See [osqp_solver.cpp:143-171](src/osqp_solver.cpp#L143-L171) for the fix.
260254
- **Deadline misses**: In clean runs the cached condensed Hessian reduced mean cycle time from 7.41 ms (v0.2.0) to 4.00 ms in the original benchmark, and from 3.06 ms to 2.69 ms (−12%) in the paired A/B validation. The Hessian cache eliminates ~512K FLOPs/cycle of redundant matrix-matrix products, reducing per-cycle Eigen heap allocations from 17+ to ~3. Remaining contributors include WSL2 virtualization overhead, Gazebo scheduling, and solver polishing cost.
261255

262-
> Comparison charts will be generated after Native Linux benchmark
263-
> validation (see benchmark status note above).
264-
265256
## Dynamic Parameter Tuning
266257

267258
Weights can be updated at runtime without restarting the controller.

ROADMAP.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,22 @@
1414
- Post-fix benchmarks: 97.7% optimal solve rate, 1.13 rad position RMS, 16.3% deadline miss
1515
- All three priority issues resolved (P0: position bounds, P1: soft constraints, P2: warm-start corruption)
1616

17+
### v0.2.1 — Real-Time Optimization and Portability Hardening
18+
- Cached condensed-QP weight matrices and Hessian (Q_bar, R_bar, S_bar, P_sparse)
19+
- Preallocated per-cycle work vectors (x_ref_stacked_, x_free_, rate_offset_, q_vec_, l_, u_)
20+
- OSQP wrapper c_float portability (element-wise static_cast)
21+
- Reused conversion buffers (q_buffer_, l_buffer_, u_buffer_, px_buffer_, dy_buffer_, p_buffer_)
22+
- WSL2 paired A/B validation (5 alternating pairs): 4/5 pairs confirm ~12% cycle time reduction
23+
- [x] All features implemented and validated via paired A/B benchmark
24+
1725
## Planned
1826

19-
### v0.2.1-rc1 — Portability & Real-Time Optimization
20-
- [x] Cache condensed-QP weight matrices and Hessian (Q_bar, R_bar, S_bar, P_sparse)
21-
- [x] Preallocate MPCController per-cycle work vectors (x_ref_stacked_, x_free_, rate_offset_, q_vec_, l_, u_)
22-
- [x] Fix hot-update ordering (rebuild P before gradient on Q/R/S change)
23-
- [x] Reuse OSQP wrapper conversion buffers (q_buffer_, l_buffer_, u_buffer_, px_buffer_, dy_buffer_, p_buffer_)
24-
- [x] Add `c_float` portability (element-wise conversion instead of Eigen::Map)
25-
- [x] WSL2 A/B benchmark: clean-run aggregate 3,876 µs solve time, 98.4% optimal rate
26-
- [x] WSL2 paired A/B validation (5 alternating pairs, v0.2.0 vs v0.2.1): 4/5 pairs confirm ~12% cycle time reduction
27-
- [ ] Native Linux benchmark (5+ runs, Ubuntu 24.04)
28-
- [ ] Publish v0.2.1 stable (after experimental validation complete)
29-
- [ ] ControllerUpdateStats integration (deferred to v0.3.0)
27+
### v0.2.2 — Runtime Characterization
28+
- [ ] Native Ubuntu 24.04 benchmark (5+ runs)
29+
- [ ] P95 / P99 latency reporting
30+
- [ ] ControllerUpdateStats integration
31+
- [ ] Additional solver parameter tuning
32+
- [ ] Regenerate comparison charts with consolidated data
3033

3134
### v0.3.0 — Additional Robot Examples
3235
- Diff-drive base MPC example

0 commit comments

Comments
 (0)