libstp.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:

  1. Profiled line follow (follow_line, follow_line_single, etc.) — built on LinearMotion for trapezoidal-profiled distance control along a single axis.

  2. Directional line follow (directional_follow_line, strafe_follow_line, etc.) — uses direct ChassisVelocity control with independent heading and strafe speed inputs, allowing line following while strafing, driving diagonally, or any combination.

Classes

LineFollowConfig

Configuration for LineFollow step with two sensors.

LineSide

Which edge of the line to track with a single sensor.

SingleLineFollowConfig

Configuration for single-sensor line following.

SingleLineFollowUntilBlackConfig

Configuration for single-sensor line following that stops when a second sensor sees black.

LineFollow

Follow a line using two IR sensors with PID steering.

SingleSensorLineFollow

Follow a line edge using a single IR sensor with PID edge-tracking.

SingleSensorLineFollowUntilBlack

Follow a line edge using one sensor, stopping when a second sensor sees black.

DirectionalLineFollowConfig

Configuration for directional line following with two sensors.

DirectionalLineFollow

Follow a line with independent heading and strafe velocity components.

DirectionalSingleLineFollowConfig

Configuration for directional single-sensor line following.

DirectionalSingleLineFollow

Follow a line edge with independent heading and strafe velocity.

Functions

follow_line(→ LineFollow)

Follow a line for a specified distance using two IR sensors for steering.

follow_line_until_both_black(→ LineFollow)

Follow a line until both sensors detect black, indicating an intersection.

follow_line_single(→ SingleSensorLineFollow)

Follow a line edge using a single IR sensor for a specified distance.

follow_line_single_until_black(...)

Follow a line edge using one sensor, stopping when a second sensor sees black.

directional_follow_line(→ DirectionalLineFollow)

Follow a line for a distance with independent heading and strafe speeds.

directional_follow_line_until_both_black(...)

Follow a line with heading and strafe until both sensors detect black.

strafe_follow_line(→ DirectionalLineFollow)

Follow a line by strafing right for a specified distance.

strafe_follow_line_until_both_black(...)

Follow a line by strafing right until both sensors detect black.

strafe_follow_line_single(→ DirectionalSingleLineFollow)

Follow a line edge by strafing right using a single sensor.

strafe_follow_line_single_until_black(...)

Follow a line edge by strafing, stopping when a second sensor sees black.

directional_follow_line_single(...)

Follow a line edge with a single sensor and independent heading/strafe speeds.

directional_follow_line_single_until_black(...)

Follow a line edge with heading/strafe, stopping when a second sensor sees black.

Module Contents

class libstp.step.motion.line_follow.LineFollowConfig

Configuration for LineFollow step with two sensors.

left_sensor: libstp.sensor_ir.IRSensor
right_sensor: libstp.sensor_ir.IRSensor
speed_scale: float
distance_cm: float | None = None
kp: float = 0.75
ki: float = 0.0
kd: float = 0.5
both_black_threshold: float = 0.7
class libstp.step.motion.line_follow.LineSide(*args, **kwds)

Bases: enum.Enum

Which edge of the line to track with a single sensor.

LEFT = 'left'
RIGHT = 'right'
class libstp.step.motion.line_follow.SingleLineFollowConfig

Configuration for single-sensor line following.

The sensor tracks the edge of a line using PID control. side selects which edge: LEFT means the sensor approaches from the left (steers right when it sees black), RIGHT is the opposite.

sensor: libstp.sensor_ir.IRSensor
speed_scale: float
distance_cm: float
side: LineSide
kp: float = 1.0
ki: float = 0.0
kd: float = 0.3
class libstp.step.motion.line_follow.SingleLineFollowUntilBlackConfig

Configuration for single-sensor line following that stops when a second sensor sees black.

The sensor tracks the line edge using PID control, while stop_sensor is monitored each cycle. When the stop sensor’s probabilityOfBlack exceeds stop_threshold, the step finishes.

sensor: libstp.sensor_ir.IRSensor
stop_sensor: libstp.sensor_ir.IRSensor
speed_scale: float
side: LineSide
stop_threshold: float = 0.7
kp: float = 1.0
ki: float = 0.0
kd: float = 0.3
class libstp.step.motion.line_follow.LineFollow(config: LineFollowConfig)

Bases: libstp.step.motion.motion_step.MotionStep

Follow 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 underlying LinearMotion, which handles profiled distance control and odometry integration.

Supports two modes: fixed-distance (stop after traveling a set distance) and until-both-black (stop when both sensors see black simultaneously, indicating an intersection).

config
to_simulation_step() libstp.step.SimulationStep
on_start(robot: libstp.robot.api.GenericRobot) None
on_update(robot: libstp.robot.api.GenericRobot, dt: float) bool
class libstp.step.motion.line_follow.SingleSensorLineFollow(config: SingleLineFollowConfig)

Bases: libstp.step.motion.motion_step.MotionStep

Follow a line edge using a single IR sensor with PID edge-tracking.

Targets probabilityOfBlack() = 0.5 (the line edge) as the setpoint. The side configuration flips the error sign to select left vs. right edge tracking. The PID output overrides the angular velocity on the underlying LinearMotion, which handles profiled distance control and odometry integration. Terminates when the configured distance has been traveled.

config
to_simulation_step() libstp.step.SimulationStep
on_start(robot: libstp.robot.api.GenericRobot) None
on_update(robot: libstp.robot.api.GenericRobot, dt: float) bool
class libstp.step.motion.line_follow.SingleSensorLineFollowUntilBlack(config: SingleLineFollowUntilBlackConfig)

Bases: libstp.step.motion.motion_step.MotionStep

Follow a line edge using one sensor, stopping when a second sensor sees black.

Combines single-sensor edge tracking (targeting probabilityOfBlack() = 0.5) with an event-based stop condition. The tracking sensor feeds a PID controller whose output overrides angular velocity on the underlying LinearMotion. Each cycle, the stop sensor is checked; when its probabilityOfBlack() exceeds the configured threshold the step finishes immediately.

config
to_simulation_step() libstp.step.SimulationStep
on_start(robot: libstp.robot.api.GenericRobot) None
on_update(robot: libstp.robot.api.GenericRobot, dt: float) bool
libstp.step.motion.line_follow.follow_line(left_sensor: libstp.sensor_ir.IRSensor, right_sensor: libstp.sensor_ir.IRSensor, distance_cm: float, speed: float = 0.5, kp: float = 0.75, ki: float = 0.0, kd: float = 0.5) LineFollow

Follow a line for a specified distance 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 underlying LinearMotion handles profiled velocity control and odometry-based distance tracking, while the PID output overrides the heading command as an angular velocity (omega).

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.

  • 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.

Returns:

A LineFollow step configured for distance-based line following.

Example:

from libstp.step.motion import follow_line

# Follow a line for 80 cm at half speed
step = follow_line(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    distance_cm=80.0,
    speed=0.5,
)

# Tighter tracking with higher kp
step = follow_line(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    distance_cm=120.0,
    speed=0.3,
    kp=1.2,
    kd=0.8,
)
libstp.step.motion.line_follow.follow_line_until_both_black(left_sensor: libstp.sensor_ir.IRSensor, right_sensor: libstp.sensor_ir.IRSensor, speed: float = 0.5, kp: float = 0.75, ki: float = 0.0, kd: float = 0.5, both_black_threshold: float = 0.7) LineFollow

Follow a line until both sensors detect black, indicating an intersection.

Drives forward with PID-based steering (same as follow_line) but instead of stopping after a fixed distance, the step monitors both sensors each cycle. When both probabilityOfBlack() readings exceed both_black_threshold simultaneously, the robot has reached a perpendicular line or intersection and the step finishes.

Internally the distance target is set very large so LinearMotion never finishes on its own – the both-black condition is the sole termination criterion.

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.

  • speed – Fraction of max velocity (0.0–1.0). Default 0.5.

  • 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.

  • both_black_threshold – The probabilityOfBlack() value that both sensors must exceed to trigger the stop. Default 0.7.

Returns:

A LineFollow step that stops when an intersection is detected.

Example:

from libstp.step.motion import follow_line_until_both_black

# Follow a line until hitting a cross-line
step = follow_line_until_both_black(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    speed=0.4,
)

# More sensitive intersection detection
step = follow_line_until_both_black(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    speed=0.3,
    both_black_threshold=0.6,
)
libstp.step.motion.line_follow.follow_line_single(sensor: libstp.sensor_ir.IRSensor, distance_cm: float, speed: float = 0.5, side: LineSide = LineSide.LEFT, kp: float = 1.0, ki: float = 0.0, kd: float = 0.3) SingleSensorLineFollow

Follow a line edge using a single IR sensor for a specified distance.

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. The side parameter controls which edge: LEFT means the sensor is to the left of the line (steers right when it sees black), and RIGHT is the opposite.

This variant is useful when only one sensor is available, or when the line is too narrow for two sensors. The underlying LinearMotion handles profiled velocity and odometry-based distance tracking.

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.

  • speed – Fraction of max velocity (0.0–1.0). Default 0.5.

  • side – Which edge of the line to track. LineSide.LEFT (default) or LineSide.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.

Returns:

A SingleSensorLineFollow step.

Example:

from libstp.step.motion import follow_line_single, LineSide

# Follow the left edge of a line for 60 cm
step = follow_line_single(
    sensor=robot.front_ir,
    distance_cm=60.0,
    speed=0.4,
    side=LineSide.LEFT,
)

# Follow the right edge with custom PID gains
step = follow_line_single(
    sensor=robot.front_ir,
    distance_cm=100.0,
    speed=0.5,
    side=LineSide.RIGHT,
    kp=1.5,
    kd=0.5,
)
libstp.step.motion.line_follow.follow_line_single_until_black(sensor: libstp.sensor_ir.IRSensor, stop_sensor: libstp.sensor_ir.IRSensor, speed: float = 0.5, side: LineSide = LineSide.LEFT, stop_threshold: float = 0.7, kp: float = 1.0, ki: float = 0.0, kd: float = 0.3) SingleSensorLineFollowUntilBlack

Follow a line edge using one sensor, stopping when a second sensor sees black.

Combines single-sensor edge tracking with an event-based stop condition. The sensor tracks the line edge (targeting probabilityOfBlack() ~ 0.5) using PID control, while the stop_sensor is polled each cycle. When the stop sensor’s probabilityOfBlack() exceeds stop_threshold, the step finishes immediately.

This is useful for following a line until the robot reaches a perpendicular marker or a specific position detected by a second sensor (e.g., a side- mounted sensor that crosses a branch line).

Both sensors must be calibrated (white/black thresholds set) before use.

Parameters:
  • sensor – The IR sensor used for edge-tracking along the line.

  • stop_sensor – A second IR sensor monitored for the stop condition. The step finishes when this sensor’s probabilityOfBlack() exceeds stop_threshold.

  • speed – Fraction of max velocity (0.0–1.0). Default 0.5.

  • side – Which edge of the line to track. LineSide.LEFT (default) or LineSide.RIGHT.

  • stop_threshold – The probabilityOfBlack() value the stop sensor must exceed to trigger the stop. Default 0.7.

  • 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.

Returns:

A SingleSensorLineFollowUntilBlack step.

Example:

from libstp.step.motion import follow_line_single_until_black, LineSide

# Follow left edge until the right sensor hits a cross-line
step = follow_line_single_until_black(
    sensor=robot.left_ir,
    stop_sensor=robot.right_ir,
    speed=0.4,
    side=LineSide.LEFT,
)

# Lower stop threshold for earlier detection
step = follow_line_single_until_black(
    sensor=robot.front_ir,
    stop_sensor=robot.side_ir,
    speed=0.3,
    stop_threshold=0.5,
    kp=1.2,
)
class libstp.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.

left_sensor: libstp.sensor_ir.IRSensor
right_sensor: libstp.sensor_ir.IRSensor
heading_speed: float
strafe_speed: float
distance_cm: float | None = None
kp: float = 0.75
ki: float = 0.0
kd: float = 0.5
both_black_threshold: float = 0.7
class libstp.step.motion.line_follow.DirectionalLineFollow(config: DirectionalLineFollowConfig)

Bases: libstp.step.motion.motion_step.MotionStep

Follow a line with independent heading and strafe velocity components.

Uses direct ChassisVelocity control instead of LinearMotion, 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 two stop modes: fixed distance and until-both-black.

config
to_simulation_step() libstp.step.SimulationStep
on_start(robot: libstp.robot.api.GenericRobot) None
on_update(robot: libstp.robot.api.GenericRobot, dt: float) bool
class libstp.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.

sensor: libstp.sensor_ir.IRSensor
heading_speed: float
strafe_speed: float
distance_cm: float | None = None
side: LineSide
stop_sensor: libstp.sensor_ir.IRSensor | None = None
stop_threshold: float = 0.7
kp: float = 1.0
ki: float = 0.0
kd: float = 0.3
class libstp.step.motion.line_follow.DirectionalSingleLineFollow(config: DirectionalSingleLineFollowConfig)

Bases: libstp.step.motion.motion_step.MotionStep

Follow a line edge with independent heading and strafe velocity.

Targets probabilityOfBlack() = 0.5 (the line edge) as the setpoint. The side configuration 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 via ChassisVelocity.

Supports distance-based and stop-sensor-based termination.

config
to_simulation_step() libstp.step.SimulationStep
on_start(robot: libstp.robot.api.GenericRobot) None
on_update(robot: libstp.robot.api.GenericRobot, dt: float) bool
libstp.step.motion.line_follow.directional_follow_line(left_sensor: libstp.sensor_ir.IRSensor, right_sensor: libstp.sensor_ir.IRSensor, distance_cm: float, heading_speed: float = 0.0, strafe_speed: float = 0.0, kp: float = 0.75, ki: float = 0.0, kd: float = 0.5) DirectionalLineFollow

Follow a line for a distance 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 follow_line which only drives forward, this step accepts both heading_speed (forward/backward) and strafe_speed (left/right) as independent fractions of max velocity, enabling line following while strafing or driving diagonally.

Both sensors must be calibrated (white/black thresholds set) before use. Requires a mecanum or omni-wheel drivetrain if strafe_speed is 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.

  • 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.

Returns:

A DirectionalLineFollow step.

Example:

from libstp.step.motion import directional_follow_line

# Strafe right while following a line for 50 cm
directional_follow_line(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    distance_cm=50.0,
    strafe_speed=0.5,
)

# Drive diagonally forward-right along a line
directional_follow_line(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    distance_cm=80.0,
    heading_speed=0.3,
    strafe_speed=0.4,
)
libstp.step.motion.line_follow.directional_follow_line_until_both_black(left_sensor: libstp.sensor_ir.IRSensor, right_sensor: libstp.sensor_ir.IRSensor, heading_speed: float = 0.0, strafe_speed: float = 0.0, kp: float = 0.75, ki: float = 0.0, kd: float = 0.5, both_black_threshold: float = 0.7) DirectionalLineFollow

Follow a line with heading and strafe until both sensors detect black.

Same as directional_follow_line but instead of stopping after a fixed distance, the step monitors both sensors each cycle and finishes when both probabilityOfBlack() readings exceed both_black_threshold simultaneously, indicating an intersection.

Both sensors must be calibrated (white/black thresholds set) before use. Requires a mecanum or omni-wheel drivetrain if strafe_speed is nonzero.

Parameters:
  • left_sensor – Left IR sensor instance.

  • right_sensor – Right IR sensor instance.

  • 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.

  • 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.

  • both_black_thresholdprobabilityOfBlack() value that both sensors must exceed to trigger the stop. Default 0.7.

Returns:

A DirectionalLineFollow step that stops at an intersection.

Example:

from libstp.step.motion import directional_follow_line_until_both_black

# Strafe right along a line until hitting a cross-line
directional_follow_line_until_both_black(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    strafe_speed=0.4,
)
libstp.step.motion.line_follow.strafe_follow_line(left_sensor: libstp.sensor_ir.IRSensor, right_sensor: libstp.sensor_ir.IRSensor, distance_cm: float, speed: float = 0.5, kp: float = 0.75, ki: float = 0.0, kd: float = 0.5) DirectionalLineFollow

Follow a line by strafing right for a specified distance.

Convenience wrapper around directional_follow_line for pure lateral line following. The robot strafes right at the given speed while PID steering keeps it centered on the line using two sensors.

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 strafe in centimeters.

  • speed – Strafe speed as fraction of max lateral velocity (0.0 to 1.0). Default 0.5. Use negative values to strafe left.

  • 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.

Returns:

A DirectionalLineFollow step configured for lateral motion.

Example:

from libstp.step.motion import strafe_follow_line

# Strafe right along a line for 40 cm
strafe_follow_line(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    distance_cm=40.0,
    speed=0.4,
)

# Strafe left along a line for 30 cm
strafe_follow_line(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    distance_cm=30.0,
    speed=-0.4,
)
libstp.step.motion.line_follow.strafe_follow_line_until_both_black(left_sensor: libstp.sensor_ir.IRSensor, right_sensor: libstp.sensor_ir.IRSensor, speed: float = 0.5, kp: float = 0.75, ki: float = 0.0, kd: float = 0.5, both_black_threshold: float = 0.7) DirectionalLineFollow

Follow a line by strafing right until both sensors detect black.

Convenience wrapper around directional_follow_line_until_both_black for pure lateral line following until an intersection is reached.

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.

  • speed – Strafe speed as fraction of max lateral velocity (0.0 to 1.0). Default 0.5. Use negative values to strafe left.

  • 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.

  • both_black_thresholdprobabilityOfBlack() value that both sensors must exceed to trigger the stop. Default 0.7.

Returns:

A DirectionalLineFollow step that stops at an intersection.

Example:

from libstp.step.motion import strafe_follow_line_until_both_black

# Strafe right along a line until a cross-line
strafe_follow_line_until_both_black(
    left_sensor=robot.left_ir,
    right_sensor=robot.right_ir,
    speed=0.4,
)
libstp.step.motion.line_follow.strafe_follow_line_single(sensor: libstp.sensor_ir.IRSensor, distance_cm: float, speed: float = 0.5, side: LineSide = LineSide.LEFT, kp: float = 1.0, ki: float = 0.0, kd: float = 0.3) DirectionalSingleLineFollow

Follow a line edge by strafing right using a single sensor.

Convenience wrapper around directional_follow_line_single for pure lateral single-sensor line following. The robot strafes at the given speed while PID edge-tracking keeps the sensor on the line boundary.

The sensor must be calibrated. Requires a mecanum or omni-wheel drivetrain.

Parameters:
  • sensor – IR sensor for edge tracking.

  • distance_cm – Distance to strafe in centimeters.

  • speed – Strafe speed as fraction of max lateral velocity (0.0 to 1.0). Default 0.5. Use negative values to strafe left.

  • 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.

Returns:

A DirectionalSingleLineFollow step configured for lateral motion.

Example:

from libstp.step.motion import strafe_follow_line_single, LineSide

# Strafe right along a line edge for 40 cm
strafe_follow_line_single(
    sensor=robot.front_ir,
    distance_cm=40.0,
    speed=0.4,
    side=LineSide.LEFT,
)

# Strafe left along a line edge for 30 cm
strafe_follow_line_single(
    sensor=robot.front_ir,
    distance_cm=30.0,
    speed=-0.4,
    side=LineSide.RIGHT,
)
libstp.step.motion.line_follow.strafe_follow_line_single_until_black(sensor: libstp.sensor_ir.IRSensor, stop_sensor: libstp.sensor_ir.IRSensor, speed: float = 0.5, side: LineSide = LineSide.LEFT, stop_threshold: float = 0.7, kp: float = 1.0, ki: float = 0.0, kd: float = 0.3) DirectionalSingleLineFollow

Follow a line edge by strafing, stopping when a second sensor sees black.

Convenience wrapper around directional_follow_line_single_until_black for pure lateral single-sensor line following with a stop-sensor trigger.

Both sensors must be calibrated. Requires a mecanum or omni-wheel drivetrain.

Parameters:
  • sensor – IR sensor for edge tracking.

  • stop_sensor – Second IR sensor for the stop condition.

  • speed – Strafe speed as fraction of max lateral velocity (0.0 to 1.0). Default 0.5. Use negative values to strafe left.

  • side – Which edge of the line to track. Default LineSide.LEFT.

  • stop_thresholdprobabilityOfBlack() the stop sensor must exceed. Default 0.7.

  • 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.

Returns:

A DirectionalSingleLineFollow step that stops on sensor trigger.

Example:

from libstp.step.motion import strafe_follow_line_single_until_black, LineSide

# Strafe right along a line edge until the stop sensor hits a cross-line
strafe_follow_line_single_until_black(
    sensor=robot.left_ir,
    stop_sensor=robot.right_ir,
    speed=0.4,
    side=LineSide.LEFT,
)
libstp.step.motion.line_follow.directional_follow_line_single(sensor: libstp.sensor_ir.IRSensor, distance_cm: float, heading_speed: float = 0.0, strafe_speed: float = 0.0, side: LineSide = LineSide.LEFT, kp: float = 1.0, ki: float = 0.0, kd: float = 0.3) DirectionalSingleLineFollow

Follow 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. The side parameter selects which edge to track. The PID output controls angular velocity while heading and strafe velocities are set independently.

The sensor must be calibrated (white/black thresholds set) before use. Requires a mecanum or omni-wheel drivetrain if strafe_speed is nonzero.

Parameters:
  • sensor – IR sensor for edge tracking.

  • distance_cm – Distance to follow in centimeters.

  • 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.

Returns:

A DirectionalSingleLineFollow step.

Example:

from libstp.step.motion import directional_follow_line_single, LineSide

# Strafe right while tracking the left edge of a line
directional_follow_line_single(
    sensor=robot.front_ir,
    distance_cm=50.0,
    strafe_speed=0.4,
    side=LineSide.LEFT,
)
libstp.step.motion.line_follow.directional_follow_line_single_until_black(sensor: libstp.sensor_ir.IRSensor, stop_sensor: libstp.sensor_ir.IRSensor, heading_speed: float = 0.0, strafe_speed: float = 0.0, side: LineSide = LineSide.LEFT, stop_threshold: float = 0.7, kp: float = 1.0, ki: float = 0.0, kd: float = 0.3) DirectionalSingleLineFollow

Follow a line edge with heading/strafe, stopping when a second sensor sees black.

Combines single-sensor edge tracking with an event-based stop condition. The sensor tracks the line edge using PID control while the stop_sensor is polled each cycle.

Both sensors must be calibrated before use. Requires a mecanum or omni-wheel drivetrain if strafe_speed is nonzero.

Parameters:
  • sensor – IR sensor for edge tracking.

  • stop_sensor – Second IR sensor for the stop condition.

  • 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.

  • stop_thresholdprobabilityOfBlack() the stop sensor must exceed. Default 0.7.

  • 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.

Returns:

A DirectionalSingleLineFollow step.

Example:

from libstp.step.motion import directional_follow_line_single_until_black, LineSide

# Strafe right along a line edge until the stop sensor hits a cross-line
directional_follow_line_single_until_black(
    sensor=robot.left_ir,
    stop_sensor=robot.right_ir,
    strafe_speed=0.4,
    side=LineSide.LEFT,
)