libstp.step.motion.lineup.single

Single-sensor lineup on a line with known width.

Drives across the line, measures the apparent crossing width, and computes the angular displacement from acos(actual_width / apparent_width). Then executes a corrective turn.

The direction of the correction cannot be determined from a single crossing, so it must be provided by the caller.

Classes

CorrectionSide

Which direction to apply the angular correction.

SingleSensorLineupConfig

SingleSensorCrossing

Drive across a line with one IR sensor and measure the apparent crossing width.

Functions

single_sensor_lineup(→ libstp.step.Sequential)

Compose a single-sensor crossing measurement with a deferred corrective turn.

forward_single_lineup(→ libstp.step.Sequential)

Drive forward across a black line, measure skew, and correct with a turn.

backward_single_lineup(→ libstp.step.Sequential)

Drive backward across a black line, measure skew, and correct with a turn.

Module Contents

class libstp.step.motion.lineup.single.CorrectionSide(*args, **kwds)

Bases: enum.Enum

Which direction to apply the angular correction.

LEFT = 'left'
RIGHT = 'right'
class libstp.step.motion.lineup.single.SingleSensorLineupConfig
sensor: libstp.sensor_ir.IRSensor
line_width_cm: float
correction_side: CorrectionSide
forward_speed: float = 0.15
entry_threshold: float = 0.7
exit_threshold: float = 0.3
class libstp.step.motion.lineup.single.SingleSensorCrossing(config: SingleSensorLineupConfig)

Bases: libstp.step.motion.motion_step.MotionStep

Drive across a line with one IR sensor and measure the apparent crossing width.

The robot drives at the configured speed while monitoring a single IR sensor’s black-surface confidence. The crossing proceeds in two phases:

  • Phase 1 (searching): Drive until the sensor reads above entry_threshold – this marks the leading edge of the line. The odometry position is recorded.

  • Phase 2 (on line): Continue driving until the sensor drops below exit_threshold – this marks the trailing edge. The odometry position is recorded again.

The apparent crossing width (leading-to-trailing distance) is compared against the known physical line_width_cm to compute the angular displacement via acos(actual_width / apparent_width). A wider apparent crossing means the robot is more skewed relative to the line.

Because a single sensor cannot determine which direction the robot is skewed, the caller must supply correction_side to indicate the turn direction.

This is an internal building-block step – use forward_single_lineup or backward_single_lineup instead.

Parameters:

config – A SingleSensorLineupConfig containing the sensor, line width, thresholds, speed, and correction direction.

config
apparent_width_m = 0.0
crossing_angle_rad = 0.0
to_simulation_step() libstp.step.SimulationStep

Convert this step to a simulation-friendly summary.

The default implementation uses timing history only when it can query the tracker synchronously; otherwise it returns conservative defaults. Override in subclasses that know their motion delta or exact duration.

on_start(robot: libstp.robot.api.GenericRobot) None

Called once before the loop. Override to set up motion/velocity.

on_update(robot: libstp.robot.api.GenericRobot, dt: float) bool

Called each cycle with dt in seconds. Return True when motion is complete.

libstp.step.motion.lineup.single.single_sensor_lineup(sensor: libstp.sensor_ir.IRSensor, line_width_cm: float = 5.0, correction_side: CorrectionSide = CorrectionSide.LEFT, forward_speed: float = 0.15, entry_threshold: float = 0.7, exit_threshold: float = 0.3) libstp.step.Sequential

Compose a single-sensor crossing measurement with a deferred corrective turn.

Drives across the line with one sensor, measures the apparent crossing width, computes the angular displacement from the known line width, and executes a corrective turn in the specified direction. If the measured skew is less than 1 degree the turn is skipped.

This is an internal helper – prefer forward_single_lineup or backward_single_lineup.

Parameters:
  • sensor – The IR sensor instance used to detect the line.

  • line_width_cm – Known physical width of the line in centimeters.

  • correction_side – Direction to turn for correction (LEFT or RIGHT). Must be determined by the caller since a single sensor cannot detect skew direction.

  • forward_speed – Approach speed in m/s (negative for backward).

  • entry_threshold – Black confidence (0–1) for detecting the leading edge of the line.

  • exit_threshold – Black confidence (0–1) for detecting the trailing edge of the line. Should be lower than entry_threshold to avoid false exits.

Returns:

A two-step sequence (crossing measurement + corrective turn).

Return type:

Sequential

libstp.step.motion.lineup.single.forward_single_lineup(sensor: libstp.sensor_ir.IRSensor, line_width_cm: float = 5.0, correction_side: CorrectionSide = CorrectionSide.LEFT, forward_speed: float = 0.15, entry_threshold: float = 0.7, exit_threshold: float = 0.3) libstp.step.Sequential

Drive forward across a black line, measure skew, and correct with a turn.

The robot drives forward at forward_speed while a single IR sensor watches for a black line. As it crosses, the apparent width of the line is measured via odometry and compared against the known line_width_cm to compute the angular displacement using acos(line_width / apparent_crossing_width). A corrective turn is then executed in the direction given by correction_side.

Because a single sensor cannot determine which way the robot is skewed, the caller must know (from the arena layout or prior steps) whether to correct left or right.

Prerequisites:

One IR line sensor and odometry. No lateral-drive capability required.

Parameters:
  • sensor – The IR sensor instance used to detect the line.

  • line_width_cm – Known physical width of the line in centimeters.

  • correction_side – Direction to turn for correction (LEFT or RIGHT).

  • forward_speed – Approach speed in m/s. Always driven forward (the absolute value is used).

  • entry_threshold – Black confidence (0–1) for detecting the leading edge of the line.

  • exit_threshold – Black confidence (0–1) for detecting the trailing edge. Should be lower than entry_threshold.

Returns:

crossing measurement + corrective turn.

Return type:

Sequential

Example:

from libstp.step.motion.lineup.single import (
    forward_single_lineup, CorrectionSide,
)

step = forward_single_lineup(
    sensor=robot.center_line_sensor,
    line_width_cm=5.0,
    correction_side=CorrectionSide.LEFT,
    forward_speed=0.10,
)
step.run(robot)
libstp.step.motion.lineup.single.backward_single_lineup(sensor: libstp.sensor_ir.IRSensor, line_width_cm: float = 5.0, correction_side: CorrectionSide = CorrectionSide.LEFT, forward_speed: float = 0.15, entry_threshold: float = 0.7, exit_threshold: float = 0.3) libstp.step.Sequential

Drive backward across a black line, measure skew, and correct with a turn.

Identical to forward_single_lineup but the robot reverses into the line instead of driving forward. The forward_speed value is negated internally so the robot always moves backward regardless of the sign passed in. The same acos(line_width / apparent_crossing_width) computation is used to determine the corrective angle.

Prerequisites:

One IR line sensor and odometry. No lateral-drive capability required.

Parameters:
  • sensor – The IR sensor instance used to detect the line.

  • line_width_cm – Known physical width of the line in centimeters.

  • correction_side – Direction to turn for correction (LEFT or RIGHT).

  • forward_speed – Approach speed in m/s. The absolute value is negated so the robot always drives backward.

  • entry_threshold – Black confidence (0–1) for detecting the leading edge of the line.

  • exit_threshold – Black confidence (0–1) for detecting the trailing edge. Should be lower than entry_threshold.

Returns:

crossing measurement (backward) + corrective turn.

Return type:

Sequential

Example:

from libstp.step.motion.lineup.single import (
    backward_single_lineup, CorrectionSide,
)

step = backward_single_lineup(
    sensor=robot.center_line_sensor,
    line_width_cm=5.0,
    correction_side=CorrectionSide.RIGHT,
    forward_speed=0.12,
)
step.run(robot)