step.motion.line_follow¶
Line following using IR sensors.
This module provides steps for following lines using one or two IR sensors with PID-based steering control.
Two families of steps are available:
Profiled line follow (
FollowLine,FollowLineSingle, etc.) — built onLinearMotionfor trapezoidal-profiled distance control along a single axis.Directional line follow (
DirectionalFollowLine,StrafeFollowLine, etc.) — uses directChassisVelocitycontrol with independent heading and strafe speed inputs, allowing line following while strafing, driving diagonally, or any combination.
All steps support composable StopCondition via the .until() builder
method, enabling patterns like:
follow_line(left, right, speed=0.5).until(on_black(left) & on_black(right))
follow_line_single(sensor, speed=0.4).until(on_black(stop_sensor))
Classes¶
Configuration for LineFollow step with two sensors. |
|
Which edge of the line to track with a single sensor. |
|
Configuration for single-sensor line following. |
|
Follow a line using two IR sensors with PID steering. |
|
Follow a line edge using a single IR sensor with PID edge-tracking. |
|
Follow a line using two IR sensors for steering. |
|
Follow a line edge using a single IR sensor. |
|
Configuration for directional line following with two sensors. |
|
Follow a line with independent heading and strafe velocity components. |
|
Configuration for directional single-sensor line following. |
|
Follow a line edge with independent heading and strafe velocity. |
|
Follow a line with independent heading and strafe speeds. |
|
Follow a line forward, correcting position by strafing left/right. |
|
Follow a line edge forward, correcting position by strafing. |
|
Follow a line edge with a single sensor and independent heading/strafe speeds. |
Module Contents¶
- class step.motion.line_follow.LineFollowConfig¶
Configuration for LineFollow step with two sensors.
- left_sensor: raccoon.sensor_ir.IRSensor¶
- right_sensor: raccoon.sensor_ir.IRSensor¶
- class step.motion.line_follow.LineSide(*args, **kwds)¶
Bases:
enum.EnumWhich edge of the line to track with a single sensor.
- LEFT = 'left'¶
- RIGHT = 'right'¶
- class step.motion.line_follow.SingleLineFollowConfig¶
Configuration for single-sensor line following.
The sensor tracks the edge of a line using PID control.
sideselects which edge: LEFT means the sensor approaches from the left (steers right when it sees black), RIGHT is the opposite.- sensor: raccoon.sensor_ir.IRSensor¶
- class step.motion.line_follow.LineFollow(config: LineFollowConfig, until: step.condition.StopCondition | None = None)¶
Bases:
step.motion.motion_step.MotionStepFollow a line using two IR sensors with PID steering.
Computes a steering error as the difference between the left and right sensors’
probabilityOfBlack()readings and feeds it through a PID controller. The PID output is applied as an angular velocity (omega) override on the underlyingLinearMotion, which handles profiled distance control and odometry integration.Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first).- config¶
- to_simulation_step() step.SimulationStep¶
- class step.motion.line_follow.SingleSensorLineFollow(config: SingleLineFollowConfig, until: step.condition.StopCondition | None = None)¶
Bases:
step.motion.motion_step.MotionStepFollow a line edge using a single IR sensor with PID edge-tracking.
Targets
probabilityOfBlack() = 0.5(the line edge) as the setpoint. Thesideconfiguration flips the error sign to select left vs. right edge tracking. The PID output overrides the angular velocity on the underlyingLinearMotion, which handles profiled distance control and odometry integration.Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first).- config¶
- to_simulation_step() step.SimulationStep¶
- class step.motion.line_follow.FollowLine(left_sensor: raccoon.sensor_ir.IRSensor, right_sensor: raccoon.sensor_ir.IRSensor, distance_cm: float | None = None, speed: float = 0.5, kp: float = 0.4, ki: float = 0.0, kd: float = 0.1, until: step.condition.StopCondition | None = None)¶
Bases:
LineFollowFollow a line using two IR sensors for steering.
Drives forward while a PID controller steers the robot to keep it centered on a line. The error signal is the difference between the left and right sensors’
probabilityOfBlack()readings. A positive error (left sees more black) steers the robot back toward center. The underlyingLinearMotionhandles profiled velocity control and odometry-based distance tracking, while the PID output overrides the heading command as an angular velocity (omega).Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first). At least one ofdistance_cmoruntilmust be provided.Both sensors must be calibrated (white/black thresholds set) before use.
- Parameters:
left_sensor – Left IR sensor instance, positioned to the left of the line.
right_sensor – Right IR sensor instance, positioned to the right of the line.
distance_cm – Distance to follow in centimeters. The step finishes when this distance has been traveled according to odometry. Optional if
untilis provided.speed – Fraction of max velocity (0.0–1.0). Lower speeds give the PID more time to correct but are slower overall. Default 0.5.
kp – Proportional gain for steering PID. Higher values produce sharper corrections. Default 0.75.
ki – Integral gain for steering PID. Typically left at 0.0 unless there is a persistent drift. Default 0.0.
kd – Derivative gain for steering PID. Damps oscillation around the line. Default 0.5.
until – Composable stop condition (e.g.,
on_black(left) & on_black(right)). Can also be chained via the.until()builder method.
- Returns:
A
FollowLinestep configured for line following.
Example:
from raccoon.step.motion import FollowLine from raccoon.step.condition import on_black # Follow a line for 80 cm at half speed follow_line(left_sensor=left, right_sensor=right, distance_cm=80, speed=0.5) # Follow until both sensors see black (intersection) follow_line(left, right, speed=0.5).until(on_black(left) & on_black(right)) # Distance + early termination follow_line(left, right, distance_cm=100, speed=0.5).until(on_black(third))
- class step.motion.line_follow.FollowLineSingle(sensor: raccoon.sensor_ir.IRSensor, distance_cm: float | None = None, speed: float = 0.5, side: LineSide = LineSide.LEFT, kp: float = 0.4, ki: float = 0.0, kd: float = 0.1, until: step.condition.StopCondition | None = None)¶
Bases:
SingleSensorLineFollowFollow a line edge using a single IR sensor.
The sensor tracks the boundary between the line and the background, where
probabilityOfBlack()is approximately 0.5. The PID controller drives the error(reading - 0.5)toward zero, keeping the sensor positioned right on the edge. Thesideparameter controls which edge:LEFTmeans the sensor is to the left of the line (steers right when it sees black), andRIGHTis the opposite.This variant is useful when only one sensor is available, or when the line is too narrow for two sensors. The underlying
LinearMotionhandles profiled velocity and odometry-based distance tracking.Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first). At least one ofdistance_cmoruntilmust be provided.The sensor must be calibrated (white/black thresholds set) before use.
- Parameters:
sensor – The IR sensor instance used for edge tracking.
distance_cm – Distance to follow in centimeters. The step finishes when this distance has been traveled. Optional if
untilis provided.speed – Fraction of max velocity (0.0–1.0). Default 0.5.
side – Which edge of the line to track.
LineSide.LEFT(default) orLineSide.RIGHT.kp – Proportional gain for steering PID. Default 1.0.
ki – Integral gain for steering PID. Default 0.0.
kd – Derivative gain for steering PID. Default 0.3.
until – Composable stop condition (e.g.,
on_black(stop_sensor)). Can also be chained via the.until()builder method.
- Returns:
A
FollowLineSinglestep.
Example:
from raccoon.step.motion import FollowLineSingle, LineSide from raccoon.step.condition import on_black # Follow left edge for 60 cm follow_line_single(sensor=front_ir, distance_cm=60, speed=0.4) # Follow until stop sensor sees black follow_line_single(front_ir, speed=0.4, side=LineSide.LEFT).until(on_black(stop)) # Distance + early termination with timeout follow_line_single(front_ir, distance_cm=100).until(on_black(stop) | after_seconds(10))
- class step.motion.line_follow.DirectionalLineFollowConfig¶
Configuration for directional line following with two sensors.
Allows independent heading (forward/backward) and strafe (left/right) speed components. The PID controller steers via angular velocity based on the difference between left and right sensor readings.
When
lateral_correctionis True, the PID output controls lateral velocity (vy) instead of angular velocity (wz), keeping the robot’s heading constant while correcting position by strafing.- left_sensor: raccoon.sensor_ir.IRSensor¶
- right_sensor: raccoon.sensor_ir.IRSensor¶
- class step.motion.line_follow.DirectionalLineFollow(config: DirectionalLineFollowConfig, until: step.condition.StopCondition | None = None)¶
Bases:
step.motion.motion_step.MotionStepFollow a line with independent heading and strafe velocity components.
Uses direct
ChassisVelocitycontrol instead ofLinearMotion, enabling line following while strafing, driving diagonally, or any combination. A PID controller computes angular velocity from the difference between the left and right sensors’probabilityOfBlack()readings.Distance is tracked via odometry as euclidean distance from the start position. Supports distance-based termination, composable
StopCondition, or both.- config¶
- to_simulation_step() step.SimulationStep¶
- class step.motion.line_follow.DirectionalSingleLineFollowConfig¶
Configuration for directional single-sensor line following.
The sensor tracks the edge of a line using PID control while the robot moves with the given heading and strafe velocity components.
When
lateral_correctionis True, the PID output controls lateral velocity (vy) instead of angular velocity (wz), keeping the robot’s heading constant while correcting position by strafing.- sensor: raccoon.sensor_ir.IRSensor¶
- class step.motion.line_follow.DirectionalSingleLineFollow(config: DirectionalSingleLineFollowConfig, until: step.condition.StopCondition | None = None)¶
Bases:
step.motion.motion_step.MotionStepFollow a line edge with independent heading and strafe velocity.
Targets
probabilityOfBlack() = 0.5(the line edge) as the setpoint. Thesideconfiguration flips the error sign to select left vs. right edge tracking. The PID output controls angular velocity while heading and strafe velocities are set directly viaChassisVelocity.Supports distance-based and composable
StopCondition-based termination.- config¶
- to_simulation_step() step.SimulationStep¶
- class step.motion.line_follow.DirectionalFollowLine(left_sensor: raccoon.sensor_ir.IRSensor, right_sensor: raccoon.sensor_ir.IRSensor, distance_cm: float | None = None, heading_speed: float = 0.0, strafe_speed: float = 0.0, kp: float = 0.4, ki: float = 0.0, kd: float = 0.1, until: step.condition.StopCondition | None = None)¶
Bases:
DirectionalLineFollowFollow a line with independent heading and strafe speeds.
Drive along a line using any combination of forward and lateral velocity while a PID controller steers the robot via angular velocity. The error signal is the difference between the left and right sensors’
probabilityOfBlack()readings. Distance is tracked via odometry as the euclidean distance from the start position.Unlike
FollowLinewhich only drives forward, this step accepts bothheading_speed(forward/backward) andstrafe_speed(left/right) as independent fractions of max velocity, enabling line following while strafing or driving diagonally.Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first). At least one ofdistance_cmoruntilmust be provided.Both sensors must be calibrated (white/black thresholds set) before use. Requires a mecanum or omni-wheel drivetrain if
strafe_speedis nonzero.- Parameters:
left_sensor – Left IR sensor instance, positioned to the left of the line.
right_sensor – Right IR sensor instance, positioned to the right of the line.
distance_cm – Distance to follow in centimeters. The step finishes when this euclidean distance has been traveled. Optional if
untilis provided.heading_speed – Forward/backward speed as a fraction of max velocity (-1.0 to 1.0). Positive = forward, negative = backward. Default 0.0.
strafe_speed – Lateral speed as a fraction of max velocity (-1.0 to 1.0). Positive = right, negative = left. Default 0.0.
kp – Proportional gain for steering PID. Default 0.75.
ki – Integral gain for steering PID. Default 0.0.
kd – Derivative gain for steering PID. Default 0.5.
until – Composable stop condition. Can also be chained via the
.until()builder method.
- Returns:
A
DirectionalFollowLinestep.
Example:
from raccoon.step.motion import DirectionalFollowLine from raccoon.step.condition import on_black # Strafe right while following a line for 50 cm directional_follow_line(left, right, distance_cm=50, strafe_speed=0.5) # Follow until both sensors see black directional_follow_line(left, right, strafe_speed=0.4).until( on_black(left) & on_black(right) )
- class step.motion.line_follow.StrafeFollowLine(left_sensor: raccoon.sensor_ir.IRSensor, right_sensor: raccoon.sensor_ir.IRSensor, distance_cm: float | None = None, speed: float = 0.5, kp: float = 0.4, ki: float = 0.0, kd: float = 0.1, until: step.condition.StopCondition | None = None)¶
Bases:
DirectionalLineFollowFollow a line forward, correcting position by strafing left/right.
The robot drives forward at the given speed while a PID controller corrects lateral position using two sensors. Unlike
FollowLinewhich steers by rotating, this step keeps the robot’s heading constant and corrects by strafing, which is useful when the robot must maintain a fixed orientation (e.g. to keep a side-mounted mechanism aligned).Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first). At least one ofdistance_cmoruntilmust be provided.Both sensors must be calibrated. Requires a mecanum or omni-wheel drivetrain.
- Parameters:
left_sensor – Left IR sensor instance.
right_sensor – Right IR sensor instance.
distance_cm – Distance to follow in centimeters. Optional if
untilis provided.speed – Forward speed as fraction of max velocity (0.0 to 1.0). Default 0.5. Use negative values to drive backward.
kp – Proportional gain for lateral PID. Default 0.75.
ki – Integral gain for lateral PID. Default 0.0.
kd – Derivative gain for lateral PID. Default 0.5.
until – Composable stop condition. Can also be chained via the
.until()builder method.
- Returns:
A
StrafeFollowLinestep configured for lateral correction.
Example:
from raccoon.step.motion import StrafeFollowLine from raccoon.step.condition import on_black # Follow a line for 40 cm, correcting via strafe strafe_follow_line(left, right, distance_cm=40, speed=0.4) # Follow until both sensors see black strafe_follow_line(left, right, speed=0.4).until( on_black(left) & on_black(right) )
- class step.motion.line_follow.StrafeFollowLineSingle(sensor: raccoon.sensor_ir.IRSensor, distance_cm: float | None = None, speed: float = 0.5, side: LineSide = LineSide.LEFT, kp: float = 0.4, ki: float = 0.0, kd: float = 0.1, until: step.condition.StopCondition | None = None)¶
Bases:
DirectionalSingleLineFollowFollow a line edge forward, correcting position by strafing.
The robot drives forward at the given speed while a PID controller corrects lateral position using a single sensor tracking the line edge. Unlike
FollowLineSinglewhich steers by rotating, this step keeps the robot’s heading constant and corrects by strafing.Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first). At least one ofdistance_cmoruntilmust be provided.The sensor must be calibrated. Requires a mecanum or omni-wheel drivetrain.
- Parameters:
sensor – IR sensor for edge tracking.
distance_cm – Distance to follow in centimeters. Optional if
untilis provided.speed – Forward speed as fraction of max velocity (0.0 to 1.0). Default 0.5. Use negative values to drive backward.
side – Which edge of the line to track. Default
LineSide.LEFT.kp – Proportional gain for lateral PID. Default 1.0.
ki – Integral gain for lateral PID. Default 0.0.
kd – Derivative gain for lateral PID. Default 0.3.
until – Composable stop condition. Can also be chained via the
.until()builder method.
- Returns:
A
StrafeFollowLineSinglestep configured for lateral correction.
Example:
from raccoon.step.motion import StrafeFollowLineSingle, LineSide from raccoon.step.condition import on_black # Follow a line edge for 40 cm, correcting via strafe strafe_follow_line_single(front_ir, distance_cm=40, speed=0.4) # Follow until stop sensor sees black strafe_follow_line_single(front_ir, speed=0.4).until(on_black(stop))
- class step.motion.line_follow.DirectionalFollowLineSingle(sensor: raccoon.sensor_ir.IRSensor, distance_cm: float | None = None, heading_speed: float = 0.0, strafe_speed: float = 0.0, side: LineSide = LineSide.LEFT, kp: float = 0.4, ki: float = 0.0, kd: float = 0.1, until: step.condition.StopCondition | None = None)¶
Bases:
DirectionalSingleLineFollowFollow a line edge with a single sensor and independent heading/strafe speeds.
The sensor tracks the boundary between the line and the background, where
probabilityOfBlack()is approximately 0.5. Thesideparameter selects which edge to track. The PID output controls angular velocity while heading and strafe velocities are set independently.Supports distance-based termination, composable
StopConditionvia.until(), or both (whichever triggers first). At least one ofdistance_cmoruntilmust be provided.The sensor must be calibrated (white/black thresholds set) before use. Requires a mecanum or omni-wheel drivetrain if
strafe_speedis nonzero.- Parameters:
sensor – IR sensor for edge tracking.
distance_cm – Distance to follow in centimeters. Optional if
untilis provided.heading_speed – Forward/backward speed fraction (-1.0 to 1.0). Default 0.0.
strafe_speed – Lateral speed fraction (-1.0 to 1.0). Default 0.0.
side – Which edge of the line to track. Default
LineSide.LEFT.kp – Proportional gain for steering PID. Default 1.0.
ki – Integral gain for steering PID. Default 0.0.
kd – Derivative gain for steering PID. Default 0.3.
until – Composable stop condition. Can also be chained via the
.until()builder method.
- Returns:
A
DirectionalFollowLineSinglestep.
Example:
from raccoon.step.motion import DirectionalFollowLineSingle, LineSide from raccoon.step.condition import on_black # Strafe right while tracking the left edge for 50 cm directional_follow_line_single(front_ir, distance_cm=50, strafe_speed=0.4) # Follow until stop sensor sees black directional_follow_line_single(front_ir, strafe_speed=0.4).until(on_black(stop))