Skip to content

Step 3 — Proportional Control Correction

The error map from Step 2 is fed into a proportional controller that adjusts the G-code feedrates for the next layer to compensate for measured surface-height deviations. This closes the control loop.

F_corrected = F_nominal * (1 + K_p * z_err_mm)

Where:

  • F_nominal — the feedrate in the original (uncorrected) G-code for the next layer.
  • K_p — proportional gain (default: 1.0). Tuned experimentally.
  • z_err_mm — the surface height error at the nearest measured point from the previous layer’s error map.
  • Positive error (surface too high) → increase feedrate → robot moves faster → deposits less material → surface drops.
  • Negative error (surface too low) → decrease feedrate → robot moves slower → deposits more material → surface rises.

For each extruding G-code point (E > 0) in the next layer’s toolpath, the controller finds the nearest point in the error map CSV (by 3D Euclidean distance) and applies that point’s err_mm value to the feedrate formula. Only extruding moves are modified; travel moves are passed through unchanged.

Terminal window
uv run python simple_proportional.py \
<next_layer.gcode> \
<L<N>_error_map.csv> \
-k <K_p> \
-o <next_layer_corrected.gcode>

Working directory: ros2_ws/lib/control/simple_proportional/

FlagDefaultPurpose
Positional 1Next layer’s nominal G-code file
Positional 2Previous layer’s error_map.csv
-k, --proportional_constant1.0Proportional gain K_p
-oOutput path for corrected G-code
--lower_bounds_corrected_feed3.2Minimum allowed corrected feedrate
--previewGenerate an HTML 3D plot of the feedrate corrections (path auto-derived if flag given without value)

Standard slicer output. Only G1 moves with non-zero E values have their F parameter adjusted.

G1 X-7.119 Y-17.261 E24.0 F3.4 ;N4
G1 X-5.676 Y-16.964 E24.0 F3.4 ;N5
X,Y,Z,err_mm
12.2021,47.3637,43.2479,4.0644
10.7972,47.6810,43.2649,4.0644

A corrected G-code file identical to the input except that feedrate (F) values on extruding moves have been scaled according to the control law. This file becomes the input to Step 1 for the next iteration.

The current controller is purely proportional (P-only). Planned extensions include:

  • Integral (I) term — accumulate historical error across multiple layers to eliminate steady-state offset.
  • Derivative (D) term — respond to the rate of error change between consecutive layers.
  • Full PID tuning with per-region gain scheduling.