Triple IR Line Tracking Sensor
Details
Summary
The Triple IR Line Tracking Sensor combines three reflective IR sensors (left/center/right) to detect dark lines on light surfaces (or vice-versa). Each channel outputs a digital signal via an onboard comparator (often with adjustable threshold), and some variants also expose analog outputs.
Tip: For best results, mount 2–8 mm above the surface and adjust the trimmers until each channel cleanly toggles when passing over the line.
Pins & Adjustments›
- VCC: 3.3–5 V (check your board’s silkscreen)
- GND: Ground
- D0 / D1 / D2: Digital outputs (active state depends on board; often active LOW on dark line)
- A0 / A1 / A2 (if present): Analog reflectance level
- TRIM POTS: One per channel to set the digital threshold
- LEDs: Power and/or channel status indicators (varies by version)
Note: Some boards invert logic (LOW = line). If readings look backwards, invert in code.
Mounting & Wiring›
Keep the sensor parallel to the surface. Connect VCC/GND and three outputs to your controller.
Wiring Diagram
Arduino Code›
Read 3 Digital Channels
// Triple IR — digital read (invert if your board is active-high)
const int L = 4, C = 3, R = 2; // D4,D3,D2 -> sensor D0,D1,D2
void setup(){ Serial.begin(115200); pinMode(L,INPUT_PULLUP); pinMode(C,INPUT_PULLUP); pinMode(R,INPUT_PULLUP); }
void loop(){
bool l = digitalRead(L)==LOW; // LOW = line (typical)
bool c = digitalRead(C)==LOW;
bool r = digitalRead(R)==LOW;
Serial.print("L:");Serial.print(l); Serial.print(" C:");Serial.print(c); Serial.print(" R:");Serial.println(r);
delay(60);
}
Simple Line-Follow (Differential Drive)
// Basic P-control using L/C/R for two motors (A: left, B: right)
const int L=4, C=3, R=2;
const int MA1=5, MA2=6, MB1=9, MB2=10; // motor driver pins (PWM capable)
int base=140, kp=80; // tune for your chassis
void setup(){
pinMode(L,INPUT_PULLUP); pinMode(C,INPUT_PULLUP); pinMode(R,INPUT_PULLUP);
pinMode(MA1,OUTPUT); pinMode(MA2,OUTPUT); pinMode(MB1,OUTPUT); pinMode(MB2,OUTPUT);
}
void drive(int left, int right){
left = constrain(left, -255, 255);
right= constrain(right,-255, 255);
analogWrite(MA1, left>0? left:0); analogWrite(MA2, left<0? -left:0);
analogWrite(MB1, right>0?right:0); analogWrite(MB2, right<0? -right:0);
}
void loop(){
bool l=(digitalRead(L)==LOW), c=(digitalRead(C)==LOW), r=(digitalRead(R)==LOW);
int err = (r?1:0) - (l?1:0); // right minus left
int corr = kp*err; // proportional correction
int left = base - corr;
int right= base + corr;
if(!l && !c && !r){ left=right=0; } // lost line: stop (or spin search)
drive(left,right);
delay(10);
}
Optional: Read Analog Channels
// If your board exposes A0/A1/A2 (wired to A0/A1/A2 on Arduino)
void setup(){ Serial.begin(115200); }
void loop(){
int l=analogRead(A0), c=analogRead(A1), r=analogRead(A2);
Serial.print("L:");Serial.print(l); Serial.print(" C:");Serial.print(c); Serial.print(" R:");Serial.println(r);
delay(40);
}
Tip: If your outputs read HIGH on dark lines, invert the logic in code or tweak the trimmers.
Raspberry Pi›
Use 3 GPIO inputs for digital outputs. For analog sensing, add an ADC (e.g., MCP3008).
Read 3 Digital Channels
# sudo apt install python3-rpi.gpio
import time, RPi.GPIO as GPIO
L,C,R = 17,27,22 # BCM pins
GPIO.setmode(GPIO.BCM)
for p in (L,C,R): GPIO.setup(p, GPIO.IN, pull_up_down=GPIO.PUD_UP)
try:
while True:
l = GPIO.input(L)==GPIO.LOW # LOW = line (typical)
c = GPIO.input(C)==GPIO.LOW
r = GPIO.input(R)==GPIO.LOW
print(f"L:{int(l)} C:{int(c)} R:{int(r)}")
time.sleep(0.06)
finally:
GPIO.cleanup()
Read Analog via MCP3008 (optional)
# pip install adafruit-circuitpython-mcp3xxx
import time, board, busio
from digitalio import DigitalInOut
from adafruit_mcp3xxx.mcp3008 import MCP3008
from adafruit_mcp3xxx.analog_in import AnalogIn
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
cs = DigitalInOut(board.CE0)
mcp = MCP3008(spi, cs)
l = AnalogIn(mcp, MCP3008.P0)
c = AnalogIn(mcp, MCP3008.P1)
r = AnalogIn(mcp, MCP3008.P2)
while True:
print(f"L:{l.value} C:{c.value} R:{r.value}") # 0..65535
time.sleep(0.05)
ESP Coding›
ESP32/ESP8266 (Arduino core): Sensor works at 3.3–5 V; ESP GPIO is 3.3 V. Use INPUT_PULLUP on the three digital channels. For analog variants, read with ADC-capable pins.
ESP32: Read 3 Digital Channels
#include
const int L=13, C=12, R=14; // GPIOs to D0/D1/D2 (adjust as wired)
void setup(){
Serial.begin(115200);
pinMode(L, INPUT_PULLUP);
pinMode(C, INPUT_PULLUP);
pinMode(R, INPUT_PULLUP);
}
void loop(){
bool l = digitalRead(L)==LOW; // LOW = line (typical)
bool c = digitalRead(C)==LOW;
bool r = digitalRead(R)==LOW;
Serial.printf("L:%d C:%d R:%d\n", l, c, r);
delay(60);
}
ESP32: Simple Line-Follow (LEDC PWM)
#include
const int L=13, C=12, R=14;
const int MA1=25, MA2=26, MB1=27, MB2=33; // motor driver pins (PWM-capable)
const int CH_A1=0, CH_A2=1, CH_B1=2, CH_B2=3;
int base=140, kp=80; // tune for your chassis
void pwmWrite(int ch, int val){ ledcWrite(ch, constrain(val,0,255)); }
void setup(){
Serial.begin(115200);
pinMode(L,INPUT_PULLUP); pinMode(C,INPUT_PULLUP); pinMode(R,INPUT_PULLUP);
ledcSetup(CH_A1, 20000, 8); ledcAttachPin(MA1, CH_A1);
ledcSetup(CH_A2, 20000, 8); ledcAttachPin(MA2, CH_A2);
ledcSetup(CH_B1, 20000, 8); ledcAttachPin(MB1, CH_B1);
ledcSetup(CH_B2, 20000, 8); ledcAttachPin(MB2, CH_B2);
}
void drive(int left, int right){
left = constrain(left,-255,255);
right= constrain(right,-255,255);
pwmWrite(CH_A1, left>0? left:0); pwmWrite(CH_A2, left<0? -left:0);
pwmWrite(CH_B1, right>0?right:0); pwmWrite(CH_B2, right<0? -right:0);
}
void loop(){
bool l=(digitalRead(L)==LOW), c=(digitalRead(C)==LOW), r=(digitalRead(R)==LOW);
int err = (r?1:0) - (l?1:0);
int corr = kp*err;
int left = base - corr;
int right= base + corr;
if(!l && !c && !r){ left=right=0; } // lost line
drive(left,right);
delay(10);
}
ESP8266: Read 3 Digital Channels
#include
// Choose GPIOs that exist on your module (e.g., D5=14, D6=12, D7=13 on NodeMCU)
const int L=D5, C=D6, R=D7;
void setup(){
Serial.begin(115200);
pinMode(L, INPUT_PULLUP);
pinMode(C, INPUT_PULLUP);
pinMode(R, INPUT_PULLUP);
}
void loop(){
bool l = digitalRead(L)==LOW, c = digitalRead(C)==LOW, r = digitalRead(R)==LOW;
Serial.printf("L:%d C:%d R:%d\n", l, c, r);
delay(60);
}
ESP-IDF: Use GPIO inputs with internal pull-ups and poll/ISR as needed. For motor control, use ledc PWM. See Espressif links in Resources below.
Drivers›
The sensor itself requires no drivers. If you use a USB-serial bridge for logging/control, you may need:
Resources›
Arduino
Raspberry Pi
Espressif
- ESP-IDF Programming Guide (Official)
- ESP-IDF “Get Started”
- Espressif Technical Docs / Datasheets / Design Guidelines
- Espressif Docs (ReadTheDocs mirror)
- ESP-IDF GitHub Repository
- ESP-IDF Examples (Resources)
- ESP8266 RTOS SDK Documentation (Legacy)
- ESP8266 RTOS SDK (GitHub)
- Espressif Matter (Docs)
- Espressif Matter (GitHub)
- Espressif Systems — YouTube
- ESP-IDF Tutorials — Playlist/Search
- PlatformIO + ESP-IDF
- Arduino Core for ESP32 (GitHub)
Drivers / Other
Specifications›
| Channels | 3 (Left / Center / Right) |
|---|---|
| Operating Voltage | 3.3–5 V (typ.) |
| Outputs | Digital (comparator) per channel; some boards also provide analog |
| Indicators | Per-channel LEDs (varies) |
| Adjustments | Trimmer potentiometer(s) for threshold |
| Sensing Height | ~2–8 mm above surface (tune to surface) |
| Use Case | Line following, edge detection, basic reflectance sensing |
| Interface | 3× digital pins (plus optional 3× analog) |
| Dimensions | Module-dependent |
Note: Polarity of “line detected” (HIGH vs LOW) and pin names can vary — follow your PCB silkscreen.
FAQ›
Sensor doesn’t detect the line ›
Readings inverted (line = HIGH) ›
Noisy outputs at edges of the line ›
Safety & Compliance›
Important Notice For educational, prototype, experimental, laboratory and R&D use only. (non-RoHs)
WEEE
Not subject to WEEE marking; obligations apply to final equipment.
Manufacturer
Little Muffins Things Limited
166 River Heights, 90 High Street
London E15 2GQ
littlemuffinsthings.com
EU Responsible Person
eucomply OU
Parnu mnt. 139b–141
13117 Tallinn, Estonia
hello@eucompliancepartner.com