step.condition

Composable stop conditions for motion steps.

A StopCondition determines when a motion step should terminate. Conditions can be combined with | (any/or), & (all/and), > / + (then/sequence) operators.

Example:

from raccoon.step.condition import on_black, on_white, after_seconds, after_cm, over_line

# Stop when sensor sees black OR after 10 seconds
drive_forward(speed=1.0).until(on_black(sensor) | after_seconds(10))

# Sequential: first wait for black, then travel 10 more cm
# Use + instead of > to avoid Python's chained-comparison gotcha
drive_forward(speed=1.0).until(on_black(sensor) + after_cm(10))

# Cross a line (black then white) three times
drive_forward(speed=1.0).until(over_line(sensor) + over_line(sensor) + over_line(sensor))

Classes

StopCondition

Base class for composable stop conditions.

on_black

Stop when an IR sensor detects a black surface.

on_white

Stop when an IR sensor detects a white surface.

after_seconds

Stop after a fixed duration.

after_cm

Stop after traveling a distance (uses odometry path length).

after_forward_cm

Stop after traveling a forward/backward displacement.

after_lateral_cm

Stop after traveling a lateral (sideways) displacement.

after_degrees

Stop after turning a given angle (degrees).

on_digital

Stop when a digital sensor reads a given state.

on_analog_above

Stop when an analog sensor reading exceeds a threshold.

on_analog_below

Stop when an analog sensor reading drops below a threshold.

stall_detected

Stop when a motor appears stalled.

custom

Stop based on a user-provided callable.

Functions

over_line(→ StopCondition)

Stop after crossing a line (black then white).

Module Contents

class step.condition.StopCondition

Base class for composable stop conditions.

start(robot: raccoon.robot.api.GenericRobot) None

Called once when the motion step starts. Override to initialize state.

abstract check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.on_black(sensor: raccoon.sensor_ir.IRSensor, threshold: float = 0.7)

Bases: StopCondition

Stop when an IR sensor detects a black surface.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.on_white(sensor: raccoon.sensor_ir.IRSensor, threshold: float = 0.7)

Bases: StopCondition

Stop when an IR sensor detects a white surface.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.after_seconds(seconds: float)

Bases: StopCondition

Stop after a fixed duration.

start(robot: raccoon.robot.api.GenericRobot) None

Called once when the motion step starts. Override to initialize state.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.after_cm(cm: float, *, absolute: bool = False)

Bases: StopCondition

Stop after traveling a distance (uses odometry path length).

By default operates in relative mode: the distance is measured from the robot’s position when the condition starts. In absolute mode (absolute=True) the distance is measured from the odometry origin (last reset()), so centimeters traveled before the condition started also count.

Uses the cumulative path length (odometer) so it works correctly regardless of travel direction (forward, strafe, curved paths).

start(robot: raccoon.robot.api.GenericRobot) None

Called once when the motion step starts. Override to initialize state.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.after_forward_cm(cm: float, *, absolute: bool = False)

Bases: _AxisDisplacementCondition

Stop after traveling a forward/backward displacement.

Unlike after_cm (which uses cumulative path length), this measures the signed forward component of displacement relative to the robot’s heading at the moment this condition started. Any turning that happens after start() does not rotate the axis — it stays pinned to the original heading.

A positive cm triggers after the robot has moved that far forward of its baseline pose; a negative cm triggers after moving that far backward.

In absolute mode (absolute=True) the displacement is read directly from get_distance_from_origin().forward — i.e. measured from the odometry origin, projected onto the origin heading.

class step.condition.after_lateral_cm(cm: float, *, absolute: bool = False)

Bases: _AxisDisplacementCondition

Stop after traveling a lateral (sideways) displacement.

Measures the signed lateral component of displacement relative to the robot’s heading at the moment this condition started. Sign convention matches DistanceFromOrigin.lateral: positive values point along the +lateral axis as defined there.

Only meaningful on drivetrains that support lateral motion (e.g. mecanum / omni). On a differential drive this will stay near zero unless the robot rotates and then drives forward — in which case the world-frame displacement has a component sideways of the original heading.

In absolute mode (absolute=True) the displacement is read directly from get_distance_from_origin().lateral.

class step.condition.after_degrees(degrees: float)

Bases: StopCondition

Stop after turning a given angle (degrees).

Uses the absolute IMU heading so it is unaffected by odometry resets. Tracks total unsigned rotation — works regardless of turn direction.

start(robot: raccoon.robot.api.GenericRobot) None

Called once when the motion step starts. Override to initialize state.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.on_digital(sensor: raccoon.hal.DigitalSensor, pressed: bool = True)

Bases: StopCondition

Stop when a digital sensor reads a given state.

By default stops when the sensor reads True (pressed). Set pressed to False to stop when the sensor is released instead.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.on_analog_above(sensor: raccoon.hal.AnalogSensor, threshold: int)

Bases: StopCondition

Stop when an analog sensor reading exceeds a threshold.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.on_analog_below(sensor: raccoon.hal.AnalogSensor, threshold: int)

Bases: StopCondition

Stop when an analog sensor reading drops below a threshold.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.stall_detected(motor: raccoon.hal.Motor, threshold_tps: int = 10, duration: float = 0.25)

Bases: StopCondition

Stop when a motor appears stalled.

A motor is considered stalled when its position changes by fewer than threshold_tps ticks per second for at least duration seconds continuously.

start(robot: raccoon.robot.api.GenericRobot) None

Called once when the motion step starts. Override to initialize state.

check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

class step.condition.custom(fn: Callable[[raccoon.robot.api.GenericRobot], bool])

Bases: StopCondition

Stop based on a user-provided callable.

The callable receives the robot and returns True to stop:

custom(lambda robot: robot.et_sensor.value() < 15)
check(robot: raccoon.robot.api.GenericRobot) bool

Return True to stop the motion. Called each update cycle.

step.condition.over_line(sensor: raccoon.sensor_ir.IRSensor, black_threshold: float = 0.7, white_threshold: float = 0.7) StopCondition

Stop after crossing a line (black then white).

Equivalent to on_black(sensor) > on_white(sensor) — waits for the sensor to see black, then waits for it to see white again.

Parameters:
  • sensor – IR sensor to monitor.

  • black_threshold – Probability threshold for the black phase.

  • white_threshold – Probability threshold for the white phase.