The per-layer error CSVs produced by Step 2 accumulate in the state directory over the course of a print job. Step 4 aggregates them into a single interactive visualization that confirms the proportional controller's performance: error should diminish as layers progress.
What it produces
3D Pancake Stackup
An interactive Plotly scene showing every layer's robot path and error surface at their physical Z heights — a literal "pancake stack" of the build. Each layer has two traces:
| Trace | Visual | Data |
|---|---|---|
| Robot path | Cool→warm gradient by layer progression | X, Y, Z from CSV |
| Error surface | Red-Yellow-Green colorscale by error magnitude | X, Y, Z + err_mm |
Layers are toggle-able via the legend. Hover reveals coordinates and error values.
Error Trend Chart
A 2D subplot below the 3D scene charting per-layer error statistics against layer number:
| Series | Metric |
|---|---|
| RMS error | sqrt(mean(err_mm²)) |
| Mean | err |
| Max | err |
A downward slope confirms the controller is converging.
Summary CSV
stackup_summary.csv — one row per layer with columns:
layer, nominal_z, n_samples, mean_abs_err, rms_err, max_abs_err, std_err
Command
# from ros2_ws/lib/control/aggregate_error_stackup/
uv run python aggregate_error_stackup.py <state_dir> [options]
Working directory: ros2_ws/lib/control/aggregate_error_stackup/
Arguments
| Flag | Default | Purpose |
|---|---|---|
| Positional 1 | — | State directory containing L*.csv files |
-o, --output | <state_dir>/stackup.html | Output HTML path |
--summary | <state_dir>/stackup_summary.csv | Summary CSV path |
--title | auto from dir name | Custom plot title |
--layers | all discovered | Comma-separated layer subset |
--no-trend | false | Omit the 2D trend subplot |
Inputs
All L{N}.csv files in the state directory, each with schema:
X,Y,Z,err_mm
12.2021,47.3637,43.2479,4.0644
10.7972,47.6810,43.2649,4.0644
These are produced by Step 2 (map_surface_err_to_xyz_pos.py) and
accumulate naturally as the print loop runs.
When to run
- During a print job — run between layer batches to check that error
is trending downward. If not, consider adjusting
k_p. - After a completed job — produce a final report of controller performance across all layers.
- Comparing configurations — run on state directories from different
print jobs to compare
k_pvalues or other parameter changes.
Remote viewing
The output HTML is self-contained (Plotly JS is inlined). Serve it over the network from the robot host:
cd /path/to/STATE/ERR/job_dir/
python3 -m http.server 8080 --bind 0.0.0.0
# browse to http://<robot-host>:8080/stackup.html
Relationship to Steps 1–3
Steps 1–3 form the real-time closed loop. Step 4 is a post-hoc analysis tool that reads the same artifacts the loop produces. It does not modify any state and can be run repeatedly as new layers become available.
Steps 1–3 (per layer, real-time) Step 4 (aggregate, any time)
│ │
▼ ▼
state_dir/L{N}.csv ──────────────→ stackup.html
stackup_summary.csv