Lesson 4 of 8Robotics with LEGO SPIKE
Robotics with LEGO SPIKE · Lesson 4 · 30 minutes
Following lines with a P controller
What you'll learn
- Understand why on/off steering jerks around
- Build a P controller from error and gain
- Tune KP and speed sensibly
The code in this lesson comes from the book “Python for Robots”, chapter 2.8, and runs unchanged in the simulator. German edition on Amazon ↗
The problem with on and off
A line follower should drive along a black line. The simplest idea: “If I see black, steer left, otherwise steer right.” That works – but the robot keeps jerking back and forth.
A controller is better: it steers hard when the robot is far off the line and gently when it’s almost right.
The P controller
The colour sensor sits exactly on the edge of the line. There it measures a medium brightness, the target value. The difference from it is called the error. The P controller simply calculates steering = KP * error.
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, ColorSensor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase
from pybricks.tools import wait
hub = PrimeHub()
left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
color_sensor = ColorSensor(Port.C)
drive_base = DriveBase(left_motor, right_motor,
wheel_diameter=56, axle_track=114)
TARGET_BRIGHTNESS = 50 # sensor value exactly at the line's edge (0-100)
KP = 1.2 # the larger, the stronger the correction
BASE_SPEED = 120 # mm/s - better to start slowly!
while True:
brightness = color_sensor.reflection()
error_value = brightness - TARGET_BRIGHTNESS # deviation from the line's edge
steering = KP * error_value # only the P component
drive_base.drive(BASE_SPEED, steering)
wait(10)Press Run and watch the robot follow the line. Then experiment:
| Change | What happens? |
|---|---|
KP = 0.3 | The robot reacts too weakly and loses the line in the curve. |
KP = 6 | It corrects very hard. On a real robot it often starts to wobble. |
BASE_SPEED = 250 | Faster – KP = 1.2 still just about works. At 300 it doesn’t (see the task). |
Remember:
drive_base.drive(speed, turn_rate)keeps driving until a new command comes. That’s why it fits perfectly into a control loop.
See the readings: In the example above, add
print("error:", error_value, "steering:", steering)below thesteeringline (same indentation). The simulator then draws the values as curves while the robot drives – so you can see how much it swings back and forth withKP = 6. With 💾 CSV you save the readings for a spreadsheet (the file stays on your device).
The book then continues with the PID controller, which also learns from the past (I) and from the change (D) – so the robot drives fast and cleanly even through tight curves.
Your task
Your turn
The line follower should get faster: set BASE_SPEED to 300. Then the old KP is no longer enough – find a value that keeps the robot on the line anyway. The check lets it drive for one minute.
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, ColorSensor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase
from pybricks.tools import wait
hub = PrimeHub()
left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
color_sensor = ColorSensor(Port.C)
drive_base = DriveBase(left_motor, right_motor,
wheel_diameter=56, axle_track=114)
TARGET_BRIGHTNESS = 50 # sensor value exactly at the line's edge (0-100)
KP = 1.2 # the larger, the stronger the correction
BASE_SPEED = 120 # mm/s - better to start slowly!
while True:
brightness = color_sensor.reflection()
error_value = brightness - TARGET_BRIGHTNESS # deviation from the line's edge
steering = KP * error_value # only the P component
drive_base.drive(BASE_SPEED, steering)
wait(10)- Something to think about
Change the line
BASE_SPEED=120 toBASE_SPEED=300. - Which command helps?
The robot got stuck or is too slow. Is the speed really 300?
The robot lost the line. Try a bigger KP, e.g. 2 or 3 – but not too big, or it will wobble.
- Gap code – fill in the ___
from pybricks.hubs import PrimeHub from pybricks.pupdevices import Motor, ColorSensor from pybricks.parameters import Port, Direction from pybricks.robotics import DriveBase from pybricks.tools import wait hub = PrimeHub() left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE) right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE) color_sensor = ColorSensor(Port.C) drive_base = DriveBase(left_motor, right_motor, wheel_diameter=56, axle_track=114) TARGET_BRIGHTNESS = 50 # sensor value exactly at the line's edge (0-100) KP = ___ BASE_SPEED = ___ while True: brightness = color_sensor.reflection() error_value = brightness - TARGET_BRIGHTNESS # deviation from the line's edge steering = KP * error_value # only the P component drive_base.drive(BASE_SPEED, steering) wait(10)
Solve it without hints to earn a ⭐ on your progress page.
Show solution🔒 Unlocks after all hints or 2 checks
Try it yourself first – mistakes teach you the most. Here is one possible solution:
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, ColorSensor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase
from pybricks.tools import wait
hub = PrimeHub()
left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
color_sensor = ColorSensor(Port.C)
drive_base = DriveBase(left_motor, right_motor,
wheel_diameter=56, axle_track=114)
TARGET_BRIGHTNESS = 50 # sensor value exactly at the line's edge (0-100)
KP = 3 # the larger, the stronger the correction
BASE_SPEED = 300 # mm/s - better to start slowly!
while True:
brightness = color_sensor.reflection()
error_value = brightness - TARGET_BRIGHTNESS # deviation from the line's edge
steering = KP * error_value # only the P component
drive_base.drive(BASE_SPEED, steering)
wait(10)