Store
Training/Robotics

Build a line-following robot—and understand every steering decision

Wire an Arduino Uno, two reflectance sensors and a TB6612FNG driver. Calibrate with the motors disabled, explore steering interactively and run your first track with a repeatable test plan.

KKadosh Build24 October 2026⏱ 5 min readBeginner1 views

On this page

0% read

A small robot finds a black tape path and changes its wheel speeds to stay over it. The fun is watching it turn; the useful skill is knowing exactly which sensor reading made it turn.

This is a two-sensor, rule-based beginner build, not a PID racer. Allow two to three hours. We deliberately start with the wheels off the ground and the motors disabled in software. Get one subsystem working at a time.

Mounting illustration: the cover is a side elevation, so the second sensor is hidden behind the first. The drawn air gap is enlarged for visibility, not to scale; measure about 2.5 mm from the real optical face to your track before calibrating.

Steer the robot before building it

Try it yourself

Picture a shopping trolley with one powered wheel on each side. To turn left, the left wheel travels more slowly than the right. The sensors tell the robot which side still sees the tape.

ForwardPWM L 120 / R 120Green sensor = black detectedD2 left = LOW · D3 right = LOW · Forward · PWM L 120 / R 120

The tape is 30 mm wide and sensor centres are 20 mm apart. Both see black when centred; both seeing white stops the motors. This discrete model explains the decision table, not real tyre slip or motor dynamics. Two sensors cannot distinguish a wide junction from the centre of a line.

Slide the tape left and right under the two sensors. Watch the digital readings and motor commands. Change the sensor-polarity checkbox to see why calibration matters.

The shopping-trolley analogy is about relative speed. If both wheels turn forward equally, the chassis moves forward. Slow the left side and the right side travels farther, bending the path to the left. The real robot will also be affected by tyre grip, battery voltage, weight and motor mismatch.

Our geometry is deliberate: black tape is 30 mm wide and the sensor centres are 20 mm apart. Both sensors see black when centred. With a narrower tape or wider spacing, the truth table changes; do not copy this control rule onto a different geometry without checking it.

Build kit and power plan

🧰 Build kit

  • 1×Arduino Uno R3ATmega328P board; this is the compiled targetGet it →
  • 1×TB6612FNG motor driverBreakout with logic and motor supplies labelledGet it →
  • 2×TCRT5000 digital sensor moduleUse DO outputs; verify each module pin orderGet it →
  • 2×Geared DC motor and wheelChoose motors whose stall current suits your driverGet it →
  • 1 set×2WD robot chassis and casterRigid sensor mounting is essentialGet it →
  • 1×AA NiMH battery holderFour cells for the motors, with a switchGet it →
  • 1×USB power bank and cablePowers Uno logic during untethered runsGet it →
  • 1 set×Jumper wires30 mm black track and matte white baseGet it →
!

Separate the two power paths

The motor pack goes to driver VM, not the Uno 5V pin. USB powers the Uno; Uno 5V powers driver logic VCC and the sensors. Join all grounds. Check motor stall-current specifications against the breakout’s sustained-current and thermal limits; peak-current figures are not continuous operating ratings.

Wire the controller and driver

The robot sensors look at the floor

Side view · sensors ahead of the drive axleOptical windows face down · calibrate near 2.5 mm

Mount down: Side view of one reflectance module: its emitter and detector face down, ahead of the wheel axle. The robot uses two modules side by side.

Side view of one of the two reflectance modules. Both optical packages must face the floor, ahead of the drive axle.

Pin map for Uno R3, two digital reflectance sensors and TB6612FNG, showing separate VM motor power and shared ground.
Disconnect motor power while wiring. A01/A02 are motor outputs, not Arduino pins.
Printable robot wiring sheet

Pin map and the separate logic/motor power arrangement.

robot-wiring.pdf · PDF · 79 KB
Download Printable robot wiring sheet↓

Use D2 for the left sensor DO and D3 for the right. PWMA/D5, AIN1/D7 and AIN2/D8 control the left motor. PWMB/D6, BIN1/D9 and BIN2/D10 control the right. STBY connects to D4. Driver A01/A02 go to the left motor; B01/B02 go to the right.

Mount both reflectance sensors facing the floor, side by side with centres 20 mm apart and about 2.5 mm from the optical faces to the surface as a starting point. Follow the module’s actual operating distance and adjust experimentally. Keep both at the same height and ahead of the wheel axle.

Calibrate the eyes, with motors disabled

Upload the sketch with CALIBRATION_ONLY = true. Open Serial Monitor at 115200. Hold both sensors over white, then over black tape. Record raw L and R. Turn each module’s comparator adjustment slowly until it switches consistently between your actual track colours.

The default is BLACK = LOW. Some sensor boards or comparator settings behave the other way; set BLACK to HIGH if that matches your observations. Test under the lighting you will use. A shiny base, bright sunlight or a high sensor mount can overwhelm the difference between tape and background.

Left seesRight seesLogical actionLeft / right PWM
BlackBlackForward120 / 120
BlackWhiteSteer left70 / 150
WhiteBlackSteer right150 / 70
WhiteWhiteStop: no line detected0 / 0

Upload the complete control sketch

Select Arduino Uno in Arduino IDE. The sketch was compile-checked with Arduino AVR Boards 1.8.8. No third-party library is required. The PWM values are starting points on a 0–255 scale, not measured wheel speeds. A heavily loaded motor may not turn at a low command.

The two sensor booleans describe what the modules see after applying BLACK. That keeps the decision table independent of whether a module outputs HIGH or LOW on tape.

line_follower.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* Kadosh Build: two-sensor line follower, Arduino Uno R3 + TB6612FNG.
   30 mm black tape; 20 mm sensor-centre spacing. Start with wheels raised.
   Original example code, MIT license. */
#include <Arduino.h>
constexpr uint8_t LEFT_SENSOR = 2, RIGHT_SENSOR = 3;
constexpr uint8_t PWMA = 5, AIN1 = 7, AIN2 = 8;
constexpr uint8_t PWMB = 6, BIN1 = 9, BIN2 = 10, STBY = 4;
constexpr uint8_t BLACK = LOW;  // Check your own modules in calibration mode.
constexpr bool CALIBRATION_ONLY = true; // Change to false only after the sensor test.
constexpr uint8_t FORWARD = 120, INNER = 70, OUTER = 150;
uint32_t lastLog = 0;
void drive(uint8_t left, uint8_t right) {
  digitalWrite(STBY, left || right ? HIGH : LOW);
  digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW);
  digitalWrite(BIN1, HIGH); digitalWrite(BIN2, LOW);
  analogWrite(PWMA, left); analogWrite(PWMB, right);
}
void setup() {
  Serial.begin(115200);
  pinMode(LEFT_SENSOR, INPUT); pinMode(RIGHT_SENSOR, INPUT);
  const uint8_t outputs[] = {PWMA, AIN1, AIN2, PWMB, BIN1, BIN2, STBY};
  for (uint8_t pin : outputs) pinMode(pin, OUTPUT);
  drive(0, 0);
  Serial.println(CALIBRATION_ONLY ? "CALIBRATION: motors disabled" : "RUN: stop by switching motor power off");
}
void loop() {
  const int rawL = digitalRead(LEFT_SENSOR), rawR = digitalRead(RIGHT_SENSOR);
  const bool left = rawL == BLACK, right = rawR == BLACK;
  uint8_t speedL = 0, speedR = 0;
  if (left && right) { speedL = FORWARD; speedR = FORWARD; }
  else if (left) { speedL = INNER; speedR = OUTER; }
  else if (right) { speedL = OUTER; speedR = INNER; }
  // Neither sees the tape: stop; no blind searching.
  drive(CALIBRATION_ONLY ? 0 : speedL, CALIBRATION_ONLY ? 0 : speedR);
  if (millis() - lastLog > 100) {
    lastLog = millis();
    Serial.print("raw L="); Serial.print(rawL); Serial.print(" R="); Serial.print(rawR);
    Serial.print(" | PWM L="); Serial.print(CALIBRATION_ONLY ? 0 : speedL);
    Serial.print(" R="); Serial.println(CALIBRATION_ONLY ? 0 : speedR);
  }
  delay(20);
}
Download the line-follower sketch

Starts in calibration mode. Read the run checklist before setting CALIBRATION_ONLY to false.

line_follower.ino · INO · 2 KB
Download Download the line-follower sketch↓

Check motor direction before a floor run

Turn by changing the two wheel commands

L 120R 120ForwardCommand duty cyclePWM is not a measured wheel speed

Forward: Both sensors see black: both motor channels receive PWM 120 / 255.

Watch both wheel commands and duty-cycle bars. Verify real motor polarity with the chassis raised before the first floor run.

Raise the chassis securely so both wheels are free. Turn motor power off, set CALIBRATION_ONLY to false, upload and disconnect the laptop cable before moving to the floor. Use a USB power bank for logic. Have the motor power switch within reach.

With both sensors over black, the wheels should both drive the chassis forward. If one turns backwards, power everything off and swap that motor’s two output leads at the driver. Do not swap logic supply wires. With only the left sensor over black, the left wheel should run more slowly than the right.

!

A physical stop is part of the build

The software stops when both sensors see white, but software and sensors can fail. Use the motor power switch to stop the robot. Keep it on a clear floor, away from table edges, stairs, fingers and loose clothing.

Lay a track it can actually follow

Line-following animation with top-view sensor decisions and a side-view inset showing downward optical orientation.
Animated walkthrough
The inset shows the mounting direction. The top view uses the same 30 mm tape and 20 mm sensor spacing as the control table.

Make a 30 mm wide track from matte black tape on a matte white base. Two overlapping strips can make the required width. Start with a straight section and broad curves, not sharp right-angle turns. The sensor geometry must match the interactive model.

Start centred, both sensors over black. Increase only one setting at a time: forward PWM, turning PWM or sensor height. If the robot oscillates from side to side, lower the speed and confirm the sensor readings before making the turning correction more aggressive.

TestPass condition
Straight sectionBoth sensors report black and the robot moves forward
Gentle left/right curveCorrect inside wheel slows; robot stays near the tape
Lift off the lineBoth sensors white; motors stop
Wide black patchRobot continues forward: both sensors see black, just like the centred case
Five repeat runsRecord finishes, departures and battery condition instead of keeping only the best run
Track-test worksheet

Record calibration polarity, PWM settings, sensor height and repeat-run results.

robot-checks.csv · CSV · 1 KB
Download Track-test worksheet↓

Diagnose the movement

SymptomLikely explanationTry this
Spins on the spotOne motor’s forward direction is reversedWheel-up direction test; swap that motor’s leads with power off
Stops immediatelyWrong BLACK polarity or tape too narrowRe-run raw sensor calibration and check geometry
Moves but cannot turnDriver channel/pin mix-up or wrong motor sideCover one sensor at a time with wheels raised
Keeps wobblingToo much speed, inconsistent sensor height or thresholdReduce forward PWM; fix the mechanical mounting
Arduino resets when motors startSupply sag, motor noise or poor groundingCheck separate supplies, wiring and the driver breakout’s decoupling guidance

What this beginner robot cannot know

Two sensors cannot distinguish a broad black junction from a centred black line. This program stops when both see white; it does not search for a lost path. Those are explicit limits, not bugs to hide. Next, try a multi-sensor array and a proportional controller only after collecting a reliable baseline.

For a research exercise, compare five runs at each of three forward PWM settings, keeping the track and sensor height unchanged. Discuss completion rate and time together. The code compiles for the stated target; validate mounting, current and motion on your actual chassis.

References and further reading: Toshiba TB6612FNG datasheet · SparkFun driver hookup guide · Vishay TCRT5000 mounting distance · Arduino digital input examples · Arduino analogWrite reference

Did you build it? 🎉

Tell us if this tutorial helped and share it with your classmates.

Need parts or a hand with your project?

Get the components from our store, or talk to a Kadosh engineer about your build or research.

Shop componentsExplore project topics

Questions & comments

Stuck on a step? Ask here — our engineers and other builders reply.

Sign in to ask a question or leave a comment.

Sign inCreate a free account
  • Loading comments…

You might also like

All tutorials →
IoT

Send sensor readings between two ESP32 boards—without a router

Build a direct ESP-NOW temperature-and-humidity link. Understand channels with an interactive packet demo, configure the receiver MAC and recognise missing or stale readings.

5 min read·Beginner·1 viewsRead →
ESP32 & ESP8266

Build an ESP32 water-tank monitor: see the level, understand the echo

Turn an ultrasonic echo into a useful water-level reading. Build a tabletop monitor, calibrate it, try the interactive tank and add a low-water alarm without alarm chatter.

5 min read·Beginner·1 viewsRead →