Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Line follower

Follows the left edge of a dark line on a light surface, using a light sensor on input 3 pointing at the floor. A touch sensor on input 1 stops the robot.

The robot steers proportionally: the further the reading is from the target, halfway between the line and the floor, the harder it turns.

use nxt_rs::prelude::*;

/// Speed on a straight line.
const BASE: i32 = 35;
/// How hard to steer per percent of error.
const GAIN: i32 = 2;

fn main() -> nxt_rs::Result<()> {
    let brick = Brick::usb_first().block()?;
    let (left, right, light, stop) =
        brick.take((B.motor(), C.motor(), S3.light(), S1.touch())).block()?;

    // Calibrate: place the sensor over the line, then over the floor.
    println!("put the sensor over the line and press enter");
    std::io::stdin().read_line(&mut String::new()).ok();
    let line = i32::from(light.read().block()?.get());
    println!("now over the floor and press enter");
    std::io::stdin().read_line(&mut String::new()).ok();
    let floor = i32::from(light.read().block()?.get());
    let target = (line + floor) / 2;

    while !stop.read().block()? {
        let error = i32::from(light.read().block()?.get()) - target;
        left.run(Power::saturating(BASE + GAIN * error)).block()?;
        right.run(Power::saturating(BASE - GAIN * error)).block()?;
    }

    brick.stop_all().block()?;
    Ok(())
}

Tuning

  • Increase GAIN if the robot loses the line in curves. Decrease it if the robot wobbles on straight lines.
  • Every loop iteration takes three round trips. Over USB that’s fast enough; over Bluetooth, use lower speeds.
  • Power::saturating clamps the computed power to −100…100, so a large error can’t produce an invalid value.

Testing it

Swap Brick::usb_first() for a simulator and feed it light readings with sim.set_sensor(InputPort::S3, raw, percent) to check the steering logic.