step.calibration.setup.steps

Setup-calibration steps: opportunistic collectors + a finalizing gate.

collect_drive / collect_ir_set wrap an existing setup motion and, while it runs, record ground-truth distance and IR samples into the SetupCalibrationSession. calibration_gate then folds that evidence into the persisted compensation layers — distance trim via MotionTrimService.set_axis_scale (the measured scale is the absolute target, so it is assigned, not composed) and IR thresholds via the calibration store — running a measured fallback drive only for axes/sets that never gathered enough samples.

Classes

CollectDrive

Wrap a setup motion and opportunistically record a distance sample.

CollectIrSet

Wrap a setup motion and sample IR sensors into a named calibration set.

CalibrationGate

Finalize all accumulated setup-calibration evidence exactly once.

Functions

collect_drive(→ CollectDrive)

Wrap a setup motion to opportunistically record a distance sample.

collect_ir_set(→ CollectIrSet)

Wrap a setup motion to sample IR sensors into a named calibration set.

calibration_gate(→ CalibrationGate)

Finalize the accumulated setup-calibration evidence exactly once.

Module Contents

class step.calibration.setup.steps.CollectDrive(step, manual_measurement: bool = True)

Bases: raccoon.ui.step.UIStep

Wrap a setup motion and opportunistically record a distance sample.

Runs the wrapped step unchanged. When a calibration board is connected, it captures the internal-odometry and board-ground-truth displacement across the drive, infers the driven axis from the dominant internal displacement, and records a DriveCalibrationSample.

Without a usable board ground truth (no board, dropout, or ~0cm reading) the behaviour depends on manual_measurement: when True (default) it prompts the operator to measure the travelled distance by hand and records that as the sample; when False it rejects the drive and records nothing (the axis is left for the CalibrationGate to handle, or left untrimmed). Users go through collect_drive().

class step.calibration.setup.steps.CollectIrSet(step, set_name: str, sensors: list[raccoon.sensor_ir.IRSensor] | None = None)

Bases: raccoon.step.base.Step

Wrap a setup motion and sample IR sensors into a named calibration set.

Runs the wrapped step while polling each IR sensor at ~100 Hz, appending the readings to set_name in the SetupCalibrationSession. The CalibrationGate later turns the accumulated samples into stored black/white thresholds. Users go through collect_ir_set().

class step.calibration.setup.steps.CalibrationGate(require_axes: list[step.calibration.setup.session.CalibrationAxis] | None = None, require_ir_sets: list[str] | None = None, forward_fallback_cm: float = _FALLBACK_FORWARD_CM, lateral_fallback_cm: float = _FALLBACK_LATERAL_CM)

Bases: raccoon.ui.step.UIStep

Finalize all accumulated setup-calibration evidence exactly once.

For each required drive axis it assigns the median sample scale as the distance trim via MotionTrimService.set_axis_scale (it is the absolute target scale, so composing it would diverge on repeat), running a measured fallback drive first if the axis gathered no samples — using the calibration board for ground truth when present, otherwise prompting the operator to measure the travelled distance by hand. For each required IR set it applies stored thresholds, driving a fallback sampling pass if needed. Idempotent: once finalized it returns immediately until new evidence arrives. Distance is only marked calibrated when an axis was actually trimmed. Under --no-calibrate it is a no-op. Users go through calibration_gate().

step.calibration.setup.steps.collect_drive(step, manual_measurement: bool = True) CollectDrive

Wrap a setup motion to opportunistically record a distance sample.

The wrapped step runs unchanged. While it executes, the calibration board (if connected) is read as ground truth alongside the internal odometry, and a per-axis distance sample is stored in the setup calibration session for the calibration_gate() to fold into the distance trim.

Without a usable board ground truth, manual_measurement decides what happens: when True (default) the operator is prompted to measure the travelled distance by hand and that becomes the sample; when False the drive is rejected and no sample is recorded (the axis is left for the gate fallback, or left untrimmed).

Prerequisites:

A calibration board for ground-truth sampling (optional — see manual_measurement).

Parameters:
  • step – Any step (e.g. a seq([...])) whose motion should be measured.

  • manual_measurement – When no board ground truth is available, prompt the operator to measure the distance by hand (True, default) instead of rejecting the drive (False).

Returns:

A step wrapping step.

Return type:

CollectDrive

Example:

from raccoon.step.calibration.setup import collect_drive

# Ask for a manual measurement if no board is connected (default):
collect_drive(
    seq(
        [
            drive_forward().until(over_line(front.left)),
            strafe_right().until(over_line(front.left)),
        ]
    ),
)

# Board-only: silently skip the sample when no board is present.
collect_drive(drive_forward().until(over_line(front.left)), manual_measurement=False)
step.calibration.setup.steps.collect_ir_set(step, set_name: str, sensors: list[raccoon.sensor_ir.IRSensor] | None = None) CollectIrSet

Wrap a setup motion to sample IR sensors into a named calibration set.

The wrapped step runs while every IR sensor is polled at ~100 Hz; the readings accumulate under set_name in the setup calibration session. The calibration_gate() later converts the samples into stored black/white thresholds.

Parameters:
  • step – Any step whose motion sweeps the sensors over the surface(s).

  • set_name – Name of the IR calibration set (e.g. "default", "upper").

  • sensors – Explicit IR sensors to sample; defaults to all IR sensors in robot.defs.analog_sensors.

Returns:

A step wrapping step.

Return type:

CollectIrSet

Example:

from raccoon.step.calibration.setup import collect_ir_set

collect_ir_set(drive_backward(cm=50), set_name="upper")
step.calibration.setup.steps.calibration_gate(require_axes: list[step.calibration.setup.session.CalibrationAxis] | None = None, require_ir_sets: list[str] | None = None, fallback_cm: float | None = None, forward_fallback_cm: float = _FALLBACK_FORWARD_CM, lateral_fallback_cm: float = _FALLBACK_LATERAL_CM) CalibrationGate

Finalize the accumulated setup-calibration evidence exactly once.

Assigns each required drive axis’ median sample scale as the distance trim via MotionTrimService.set_axis_scale (it is the absolute target scale, so it is set, not composed — composing would diverge on repeated calibration) and applies each required IR set’s thresholds. A drive axis with no samples triggers a measured fallback drive: with a calibration board the board supplies the ground truth, otherwise the operator is prompted to measure the travelled distance by hand. Idempotent and a no-op under --no-calibrate.

Parameters:
  • require_axes – Drive axes that must be finalized. None finalizes every axis that accumulated a sample or was marked required by a collector.

  • require_ir_sets – IR set names that must be finalized. None finalizes every set seen so far.

  • fallback_cm – Distance (cm) for the fallback drive, applied to both axes. A convenience override — when given it replaces both forward_fallback_cm and lateral_fallback_cm. None keeps the per-axis defaults.

  • forward_fallback_cm – Distance (cm) of the forward fallback drive when the forward axis has no samples.

  • lateral_fallback_cm – Distance (cm) of the lateral fallback strafe.

Returns:

The finalizing step.

Return type:

CalibrationGate

Example:

from raccoon.step.calibration.setup import CalibrationAxis, calibration_gate

# Default per-axis fallback distances:
calibration_gate(
    require_axes=[CalibrationAxis.FORWARD],
    require_ir_sets=["default", "upper"],
)

# Drive 80 cm for any fallback (both axes):
calibration_gate(require_axes=[CalibrationAxis.FORWARD], fallback_cm=80)