Skip to the content
PCBKitNew board
2 layers117.5 × 28.5 mmLineSensor, the printed circuit board in 3D

An autonomous line-following robot built on an STM32F401RE Nucleo board, combining custom C++/Mbed firmware, a bespoke six-sensor infrared PCB, and two parallel PID loops (steering + wheel speed) for fast, stable line…

Size
117.5 × 28.5 mm
Copper layers
2
Thickness
1.6 mm
Parts
24
Nets
38
Pads
83
Tracks, vias
111, 0
Pours
2
Routed
Yes
KiCad
KiCad 8.0 (file 20240108)
Created
7 Sep 2026
Updated
7 Sep 2026

Overview

LineSensor is an open-source printed circuit board by clin1146, from the clin1146/esp-buggy repository on GitHub, published under the MIT licence. It is a 2-layer board of 117.5 × 28.5 mm with 24 parts on 38 nets, routed with 111 tracks and 0 vias.

Its parts include 12 resistors and 9 connectors.

README

README.md

Autonomous Line-Following Buggy

An autonomous line-following robot built on an STM32F401RE Nucleo board, combining custom C++/Mbed firmware, a bespoke six-sensor infrared PCB, and two parallel PID loops (steering + wheel speed) for fast, stable line tracking. Built for the EEEN21000 Embedded Systems Project at the University of Manchester and raced in the end-of-year competition.

Course University MCU Framework Language Heats

The final line-following buggy

Heats result: completed the competition track in 10.0 s, finishing 6th in the Heats. Technical demonstrations averaged ~90%, with 100% in TD3.


Contents


Overview

The buggy follows a white line on a dark track using a six-sensor infrared array. Sensor voltages are sampled through the STM32's ADCs, converted to a line position with a weighted-average algorithm, and fed into two PID controllers running in parallel — one for steering, one for wheel speed. Motor commands are issued as bipolar PWM to an H-bridge motor-driver board.

PropertyValue
MicrocontrollerSTM32F401RE (Nucleo-64)
Language / frameworkC++ / Arm Mbed OS
Line sensors6 × TCRT5000 reflective IR on a custom PCB, 18 mm pitch
Speed feedback2 × quadrature encoders, 256 CPR, ×4 decoding
Actuation2 × brushed DC motors via H-bridge driver, bipolar PWM @ 20 kHz
Gearbox13.55:1 (16T pinion → 50/10 idler → 60T final drive)
ControlTwo parallel PID loops (steering error + per-wheel speed)
Chassis3-tier laser-cut acetal, rear-wheel drive
Top speed≈ 2.24 m/s flat / ≈ 1.57 m/s on the 18° slope (calculated)

Gallery

Final buggySolidWorks model
Custom line-sensor PCB (KiCad)Wiring

How it works

The firmware (firmware/main.cpp) runs the same pipeline every cycle, with no blocking calls:

  1. Sense. Six SamplingSensor objects sample the TCRT5000 array on a fixed-frequency Ticker, independently of the main loop.
  2. Localise. calculate_lineposition() normalises each reading and takes a weighted average — the weights are the physical sensor offsets — so the result is the buggy's lateral error, with the setpoint at 0.
  3. Correct. Two controllers act on that cycle's data in parallel: a steering PID on the line-position error (an equal-and-opposite nudge to the two wheels), and a speed PID per wheel on target − measured RPM from the encoders.
  4. Drive. Each wheel command is baseSpeed + speedCorrection ± steeringAdjustment, sent as bipolar PWM to the motor-driver board.

A three-state machine wraps the pipeline — initial (motors off, variables reset), run (PID line-following; exits when every sensor reads low, i.e. the all-black end zone), stop (motors halted). The on-board user button steps between states.

The control system was not originally parallel — see docs/control-system.md for the cascaded → parallel rework, the single change that most improved stability.


Repository layout

text
esp-buggy/
├── firmware/
│   └── main.cpp                The buggy's control firmware (Mbed / STM32F401RE)
├── docs/
│   ├── hardware.md             Board, pin map, custom PCB, chassis
│   ├── control-system.md       Weighted-average localisation + parallel PID
│   ├── sensor-subsystem.md     Why the TCRT5000 was chosen
│   ├── motor-characterisation.md   Motor constants + gearbox selection
│   └── img/                    Figures
└── hardware/
    ├── wiring-diagram.pdf
    ├── line-sensor-pcb/        KiCad 8 project + PDF / STEP exports
    └── chassis/                Laser-cut DXF

Documentation

TopicRead
Board, full pin map, custom sensor PCB, chassisdocs/hardware.md
Control system — weighted-average line position, parallel PIDdocs/control-system.md
Sensor subsystem — why the TCRT5000docs/sensor-subsystem.md
Motor characterisation and gearbox selectiondocs/motor-characterisation.md

Real-time timing budget

The steering loop has a hard deadline, derived from the worst case (buggy at top speed):

QuantityValue
Distance from track centre to the nearest sensor0.9 cm
Maximum speed2.24 m/s
⇒ Steering must react within4.02 ms
⇒ Sensor sample period set to2 ms (≥ 2 samples per steering decision)

This is why the firmware is built entirely from tickers and interrupts and avoids blocking calls.


Tuning notes

  • Ki is kept deliberately small. A larger integral term accumulates error over time and delays corrective action; on a curve that reverses direction sharply, that lag makes the buggy overshoot and lose the line.
  • The array had a slight left bias. The buggy turned right a fraction late; increasing the left-hand sensor weights re-centred it.

What we would do differently

  • Weight. The three-tier chassis was bolted together with metal nuts and bolts. Laser-cut plastic standoffs would have cut mass and improved the uphill and post-slope cornering times.
  • Code bloat. Leftover debug printf statements burned MCU cycles and added latency to the control loop; they should have been compiled out for the race build.

Team

Group 31, EEEN21000 Embedded Systems Project, University of Manchester, 2024–25. Tutor: Emad Alsusa.

Charles Lin · Shuocheng Tian · Yefym Lunov · Zain Wilde · Yuncheng Zhang


Acknowledgements

Parts

24
QtyValueFootprintReferences
610KResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR2, R4, R6, R8, R10, R12
651Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR1, R3, R5, R7, R9, R11
68 pin DIL socketPackage_DIP:DIP-8_W7.62mm_SocketJ3, J4, J5, J6, J7, J8
2Conn_01x03_PinConnector_JST:JST_EH_S3B-EH_1x03_P2.50mm_HorizontalJ1, J10
2MountingHole_4.3mm_M4MountingHole:MountingHole_4.3mm_M4mountingHole2, mountingHole3
1Conn_01x02_PinConnector_JST:JST_EH_S2B-EH_1x02_P2.50mm_HorizontalJ2
1MountingHole1MountingHole:MountingHole_4.3mm_M4M3

Questions

How big is the LineSensor PCB?

It measures 117.5 × 28.5 mm and has 2 copper layers, 1.6 mm thick.

What parts does the LineSensor use?

24 parts. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the LineSensor KiCad files?

From the clin1146/esp-buggy repository on GitHub, at the commit this page was made from: the board is hardware/line-sensor-pcb/lineSensor.kicad_pcb and its schematic hardware/line-sensor-pcb/lineSensor.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the LineSensor design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers56 × 65 mmSeaTalk1, the printed circuit board in 3D

    SeaTalk1

    dotnet/iot

    This repo includes .NET Core implementations for various IoT boards, chips, displays and PCBs.

    24 parts2.4kMIT
  • 2 layers26.2 × 45.5 mmPL18 multiprotocol, the printed circuit board in 3D

    PL18 multiprotocol

    pascallanger/DIY-Multiprotocol-TX-Module

    Multiprotocol TX Module (or MULTI-Module) is a 2.4GHz transmitter module which controls many different receivers and models.

    24 parts1.9kGPL-3.0
  • 2 layers58 × 35.5 mmHat, the printed circuit board in 3D

    Hat

    menloresearch/asimov-1

    v1 of Asimov, an open-source humanoid robot

    24 parts1.4kCERN-OHL-S-2.0
  • 2 layers21.6 × 19.5 mmMicron Logo LED, the printed circuit board in 3D

    Micron Logo LED

    DraftShift/StealthChanger

    Tool changing system for Vorons and other front mount printer motion systems, not just stealthburner.

    24 parts1.2kGPL-3.0
  • 2 layers158 × 11 mmRainbow Matchstick, the printed circuit board in 3D

    Rainbow Matchstick

    VoronDesign/Voron-Hardware

    Cool Hardware designed by the Voron Design group

    24 parts1.1kGPL-3.0
  • 2 layers85.6 × 54 mmTRACED wio1262-carrier, the printed circuit board in 3D

    TRACED wio1262-carrier

    hackclub/OnBoard

    💡 Join 1,000 teenagers and make your first PCB with a $100 grant!

    24 parts915
  • 2 layers36 × 20 mmCombined, the printed circuit board in 3D

    Combined

    adamb314/ServoProject

    Getting the most out of your hobby servo

    24 parts545