print_loop

-- The closed-loop WAAM print cycle, orchestrated.
print_loop :: PrintJobConfig -> IO ()
-- For each layer N in [start..end]:
--   1. record_bag + execute_gcode   :: GCode -> IO BagDirectory
--   2. map_surface_error             :: BagDirectory -> (HTML, CSV)
--   3. proportional_correction       :: (CSV, GCode_next) -> GCode_corrected
--   [operator inspects HTML, confirms]
--   loop.

Interactive CLI orchestrator that drives the three-step WAAM print loop from a single YAML config file. Eliminates manual path copy-pasting between steps; the only human input required is a visual sanity-check of the error-map plot before each subsequent layer prints.

Usage

# from ros2_ws/lib/control/print_loop/
uv run python print_loop.py my_job.yaml

Verify path resolution without touching the robot:

uv run python print_loop.py my_job.yaml --dry-run

What it automates

Manual step you used to doNow handled by
Compose ros2 bag record with ~10 topic flagsConfig YAML topics list
Copy-paste long gcode pathsAuto-resolved from slices_dir using *_layers_{N}-{N}_1layers.gcode naming convention
Remember bag dir name, feed to Step 2Derived: {bag_output_dir}/L{N}_Z{nominal_z}
Derive CSV path from HTML outputDerived: {state_dir}/L{N}.csv
Increment layer numbers, compute nominal Znominal_z(layer) = z_base + layer * z_per_layer
Run Step 2 + Step 3 as manual uv run invocationsSubprocess orchestration with error handling

Config

Copy example_config.yaml and fill in your job parameters:

job_name: mayor_1
slices_dir: /path/to/layer_slices/
bag_output_dir: /path/to/BAGS/
state_dir: ~/PhotogrammetryWAAM/STATE/ERR/
start_layer: 21
end_layer: 43
z_base: 5.0
z_per_layer: 2.0

error_mapping:
  smooth: 12
  trim_first: 32
  trim_last: 32

control:
  k_p: 0.25
  lower_bounds_corrected_feed: 4.2

Operator interaction

Per layer, the orchestrator runs Steps 1-2 automatically, then:

  Error map: ~/STATE/ERR/L21.html
  Opening in browser...

  Review the error map. Continue? [Y/n/q]

On confirmation it runs Step 3 and prompts once more before printing the next layer. Answering q at any prompt saves state and exits; rerunning the same command resumes from where you left off.

Resumable state

Progress is persisted to {state_dir}/{job_name}_state.json after every step. If the process is interrupted (Ctrl-C, SSH drop, power loss), relaunch the same command and it picks up at the last incomplete step.

Architecture

The orchestrator calls the existing scripts as subprocesses (uv run / ros2 run) rather than importing them, keeping the uv environments independent:

  • Step 1: ros2 bag record (Popen + SIGINT) and ros2 run gcode_file_parser_client
  • Step 2: uv run python map_surface_err_to_xyz_pos.py (in shared/rosbag_parser/)
  • Step 3: uv run python simple_proportional.py (in ros2_ws/lib/control/simple_proportional/)

Files

FilePurpose
print_loop.pyMain orchestrator CLI
models.pyPrintJobConfig, LayerState, PrintLoopState (Pydantic)
example_config.yamlTemplate job configuration
tests/test_print_loop.pyConfig loading, path resolution, state persistence

Full specification (../spec/)