Line Tracking Sensor (cảm biến dò đường) dùng cặp LED IR + phototransistor để phân biệt vạch đen trên nền trắng (hoặc ngược lại). Tương tự IR Obstacle Sensor nhưng được thiết kế cho khoảng cách rất gần (2–5mm từ mặt đất). Bài này phân tích TCRT5000 — linh kiện cảm biến phổ biến nhất trong line follower module — từ cấu tạo đến code robot theo vạch 3-sensor.
Nguyên Lý Hoạt Động
1. TCRT5000 — Cặp Phát Thu Trong Một Package
TCRT5000 (Vishay) là reflective optical sensor — emitter và detector tích hợp trong cùng một vỏ nhựa.
Nhựa trong suốt (bảo vệ và định hướng)
┌────────────────────────────────┐
│ [IR LED 890nm] [Phototrans.] │
│ Emitter Detector │
└────────────────────────────────┘
↓↓ IR ↑↑ IR phản xạ
───────────────────────────
Bề mặt đo (vạch/nền)
IR LED (Emitter):
- Bước sóng 890nm — hơi ngắn hơn FC-51 (940nm)
- Luôn bật khi có nguồn (qua điện trở hạn dòng)
- Góc phát hẹp — định hướng xuống bề mặt
Phototransistor NPN (Detector):
- Không phải photodiode — là transistor silicon NPN
- Khi nhận IR → transistor dẫn (collector-emitter) → dòng chảy
- Đây là transistor nên có khuếch đại nội tại (h_FE) → nhạy hơn photodiode
Khoảng cách tối ưu: 0.5mm – 5mm, tốt nhất ~2.5mm từ bề mặt. Quá xa → IR phân tán → không đủ phản xạ. Quá gần → IR phản xạ bão hòa cả trên đen và trắng → không phân biệt được.
2. Phân Biệt Trắng Và Đen Theo Phản Xạ IR
Bề mặt TRẮNG:
IR ──→ [ Bề mặt trắng phản xạ ~90% IR ] ──→ Phototransistor nhận nhiều IR
→ Transistor DẪN nhiều
→ Điện áp đầu ra THẤP
→ OUT = LOW (thường)
Bề mặt ĐEN:
IR ──→ [ Bề mặt đen hấp thu ~95% IR ] ──→ Phototransistor nhận ít IR
→ Transistor NGẮT
→ Điện áp đầu ra CAO
→ OUT = HIGH (thường)
Logic phổ biến của module:
- Trên trắng: OUT = LOW (đen = 0 trên trắng = 1? Không nhất quán giữa các module)
- Trên đen: OUT = HIGH
Lưu ý: Một số module đảo logic. Luôn test thực tế để xác định: đặt sensor trên vạch đen, đọc OUT; đặt trên nền trắng, đọc OUT. Đừng giả định.
3. Mạch Module — LM393 + Pull-Up
VCC
│
[R_LED ~100Ω] ← Hạn dòng LED IR (TCRT5000 emitter)
│
[LED IR TCRT5000]
│
GND
VCC
│
[R_pull ~10kΩ] ← Pull-up điện trở
│
├──── V_collector (đến LM393 comparator)
│
[Phototransistor Collector] ← Collector kết nối lên pull-up
[Phototransistor Emitter] ← Emitter nối GND
│
GND
LM393 comparator so sánh Vcollector với Vref (triết áp) → xuất digital OUT.
Khi phototransistor dẫn nhiều (bề mặt trắng): V_collector giảm → có thể xuống LOW → OUT theo logic LM393.
4. Khoảng Cách Lắp Đặt — Cực Quan Trọng
TCRT5000 nhạy nhất ở 2–3mm từ bề mặt đo. Robot line follower cần gắn sensor sao cho khoảng cách này được duy trì ổn định khi di chuyển.
Lỗi thường gặp:
- Gắn quá cao (>8mm): cả đen và trắng đều phản xạ như nhau → không phân biệt
- Gắn quá thấp (<1mm): sensor cọ bề mặt → hỏng sensor hoặc nạo sơn
- Không đồng đều: 3 sensor ở 3 độ cao khác nhau → đọc sai
Kiểm tra nhanh: Nhìn vào LED báo trên module — trên trắng LED sáng (phản xạ tốt), trên đen LED tắt.
Thông Số Kỹ Thuật
| Thông số | Giá trị |
|---|---|
| Điện áp hoạt động (module) | 3.3V – 5V |
| Khoảng cách tối ưu | 2mm – 5mm (TCRT5000) |
| Bước sóng IR | 890nm |
| Ngõ ra | Digital: logic phụ thuộc module |
| Dòng tiêu thụ mỗi sensor | ~20–40mA |
| Module 1 sensor | 1 OUT |
| Module 3 sensor | 3 OUT riêng biệt |
| Module 5 sensor | 5 OUT riêng biệt |
Sơ Đồ Chân (Pinout)
Module 1 Sensor (3 chân)
┌────────────────────────┐
│ [TCRT5000] [LED báo] │
│ [Triết áp] LM393 │
└────────────────────────┘
VCC GND OUT
Module 3 Sensor (5 chân phổ biến)
┌──────────────────────────────────┐
│ [S1] [S2] [S3] │
│ Trái Giữa Phải │
└──────────────────────────────────┘
VCC GND S1OUT S2OUT S3OUT
| Chân | Chức năng |
|---|---|
| VCC | 3.3V – 5V |
| GND | Đất |
| S1OUT / OUT_L | Digital out sensor trái |
| S2OUT / OUT_M | Digital out sensor giữa |
| S3OUT / OUT_R | Digital out sensor phải |
So Sánh Line Tracking vs IR Obstacle
| Line Tracking (TCRT5000) | IR Obstacle (FC-51) | |
|---|---|---|
| Khoảng cách tối ưu | 2–5mm | 2–30cm |
| Hướng nhìn | Xuống bề mặt | Về phía trước |
| Mục đích | Phân biệt đen/trắng | Phát hiện vật thể |
| Package | LED+transistor cùng gói | LED và photodiode rời |
| Detector | Phototransistor (có khuếch đại) | Photodiode (thụ động hơn) |
| Khoảng cách module | Rất gần mặt đất | Trước mặt robot |
Kết Nối Phần Cứng
Kết Nối Module 3 Sensor với ESP32 DevKit V1
ESP32 DevKit V1 Module 3 Line Sensor
───────────────────── ─────────────────────────
3V3 ─────────────────→ VCC
GND ─────────────────→ GND
GPIO32 (ADC/Input) ←──── S1OUT (Sensor trái)
GPIO33 (ADC/Input) ←──── S2OUT (Sensor giữa)
GPIO34 (ADC/Input) ←──── S3OUT (Sensor phải)
GPIO32, 33, 34 là các ADC1 pin — cũng là digital input. Dùng được cả digitalRead().
Kết Nối Module 3 Sensor với Arduino Uno
Arduino Uno Module 3 Line Sensor
───────────────────── ─────────────────────────
5V ─────────────────→ VCC
GND ─────────────────→ GND
Pin 4 ←───────────────── S1OUT (Sensor trái)
Pin 5 ←───────────────── S2OUT (Sensor giữa)
Pin 6 ←───────────────── S3OUT (Sensor phải)
Code Arduino IDE
Code Test Cơ Bản — 3 Sensor, Arduino Uno
/*
* Line Tracking Sensor — 3 sensor, đọc và in Serial
* Board: Arduino Uno
* Kết nối: VCC→5V, GND→GND, S1→Pin4, S2→Pin5, S3→Pin6
*
* Chạy code này trước để xác định:
* - Trên VẠch ĐEN: OUT = HIGH hay LOW?
* - Trên NỀN TRẮNG: OUT = HIGH hay LOW?
* Ghi nhớ kết quả để viết code đúng cho robot
*/
const int LEFT_PIN = 4; // Sensor trái
const int MIDDLE_PIN = 5; // Sensor giữa
const int RIGHT_PIN = 6; // Sensor phải
void setup() {
Serial.begin(9600);
pinMode(LEFT_PIN, INPUT);
pinMode(MIDDLE_PIN, INPUT);
pinMode(RIGHT_PIN, INPUT);
Serial.println("=== Line Tracking Sensor Test ===");
Serial.println("Đặt sensor lên vạch ĐEN và NỀN TRẮNG để xác định logic");
Serial.println("L=Trái M=Giữa R=Phải");
}
void loop() {
int L = digitalRead(LEFT_PIN);
int M = digitalRead(MIDDLE_PIN);
int R = digitalRead(RIGHT_PIN);
// In dạng bản đồ: dễ hình dung vị trí vạch
Serial.print("L:");
Serial.print(L == HIGH ? "BLK" : "WHT"); // Thay tùy logic thực tế của module
Serial.print(" M:");
Serial.print(M == HIGH ? "BLK" : "WHT");
Serial.print(" R:");
Serial.println(R == HIGH ? "BLK" : "WHT");
delay(200);
}
Code Robot Dò Đường — Arduino Uno (3 Sensor)
/*
* Line Tracking Robot — Arduino Uno, 3 sensor, motor L298N
* Board: Arduino Uno
* Sensor: Trái→Pin4, Giữa→Pin5, Phải→Pin6
* Motor L298N: ENA→Pin9, IN1→Pin2, IN2→Pin3 (Trái)
* ENB→Pin10, IN3→Pin7, IN4→Pin8 (Phải)
*
* LOGIC sensor: điều chỉnh ON_BLACK theo kết quả test thực tế!
* Thường: ON BLACK → HIGH (1), ON WHITE → LOW (0)
*/
// Sensor pins
const int S_LEFT = 4;
const int S_MIDDLE = 5;
const int S_RIGHT = 6;
// Motor pins
const int ENA = 9, IN1 = 2, IN2 = 3; // Motor trái
const int ENB = 10, IN3 = 7, IN4 = 8; // Motor phải
// Tốc độ cơ bản và tốc độ rẽ
const int SPEED_BASE = 150;
const int SPEED_TURN = 100;
// Logic sensor: thay HIGH↔LOW nếu module bạn đảo ngược
// HIGH = trên vạch ĐEN
#define ON_BLACK HIGH
// Chạy motor: speed dương = tiến, âm = lùi, 0 = dừng
void motor(int leftSpeed, int rightSpeed) {
analogWrite(ENA, abs(leftSpeed));
digitalWrite(IN1, leftSpeed >= 0 ? HIGH : LOW);
digitalWrite(IN2, leftSpeed >= 0 ? LOW : HIGH);
analogWrite(ENB, abs(rightSpeed));
digitalWrite(IN3, rightSpeed >= 0 ? HIGH : LOW);
digitalWrite(IN4, rightSpeed >= 0 ? LOW : HIGH);
}
void setup() {
Serial.begin(9600);
pinMode(S_LEFT, INPUT); pinMode(S_MIDDLE, INPUT); pinMode(S_RIGHT, INPUT);
for (int p : {ENA, IN1, IN2, ENB, IN3, IN4}) pinMode(p, OUTPUT);
Serial.println("=== Line Following Robot ===");
}
void loop() {
bool L = (digitalRead(S_LEFT) == ON_BLACK);
bool M = (digitalRead(S_MIDDLE) == ON_BLACK);
bool R = (digitalRead(S_RIGHT) == ON_BLACK);
// --- Logic điều hướng ---
if (!L && M && !R) {
// Chỉ giữa trên vạch → đi thẳng
motor(SPEED_BASE, SPEED_BASE);
Serial.println("Thẳng");
} else if (!L && !M && R) {
// Vạch lệch sang phải → rẽ phải (giảm motor phải)
motor(SPEED_BASE, SPEED_TURN);
Serial.println("Rẽ phải nhẹ");
} else if (L && !M && !R) {
// Vạch lệch sang trái → rẽ trái
motor(SPEED_TURN, SPEED_BASE);
Serial.println("Rẽ trái nhẹ");
} else if (!L && !M && !R) {
// Mất vạch hoàn toàn → giảm tốc tiến thẳng (hy vọng bắt lại)
motor(SPEED_TURN, SPEED_TURN);
Serial.println("Mất vạch — chậm lại");
} else if (L && M && R) {
// Tất cả trên đen → giao cắt hoặc điểm cuối → dừng/hoặc tiếp tục
motor(SPEED_BASE, SPEED_BASE);
Serial.println("Giao cắt — tiếp tục thẳng");
} else if (L && !M && R) {
// Trái và phải — không có giữa → góc nhọn hoặc chữ T ngược
motor(SPEED_BASE, SPEED_BASE);
} else {
// Các trường hợp còn lại
motor(SPEED_BASE, SPEED_BASE);
}
delay(20);
}
Code ESP32 — 3 Sensor Với Non-Blocking Loop
/*
* Line Tracking — ESP32, 3 sensor, non-blocking
* Board: ESP32 DevKit V1
* Sensor: S1→GPIO32, S2→GPIO33, S3→GPIO34
*
* Không dùng delay() trong loop chính — thân thiện với WiFi/MQTT
*/
const int S_LEFT = 32;
const int S_MIDDLE = 33;
const int S_RIGHT = 34;
// Thay HIGH↔LOW theo logic module thực tế
#define ON_BLACK HIGH
unsigned long lastLogTime = 0;
// Lưu vị trí vạch từ lần đo trước (dùng khi mất vạch)
int lastError = 0; // -1=trái, 0=giữa, +1=phải
// Tính "error" — độ lệch vạch so với giữa
int getLineError(bool L, bool M, bool R) {
if (!L && M && !R) return 0; // Đúng giữa
if (!L && !M && R) return 1; // Lệch phải
if (L && !M && !R) return -1; // Lệch trái
if (!L && M && R) return 1; // Lệch phải nhiều
if (L && M && !R) return -1; // Lệch trái nhiều
// Mất vạch hoặc giao cắt
return lastError; // Giữ vị trí cuối — tránh dao động
}
void setup() {
Serial.begin(115200);
pinMode(S_LEFT, INPUT);
pinMode(S_MIDDLE, INPUT);
pinMode(S_RIGHT, INPUT);
Serial.println("=== Line Tracking - ESP32 ===");
}
void loop() {
bool L = (digitalRead(S_LEFT) == ON_BLACK);
bool M = (digitalRead(S_MIDDLE) == ON_BLACK);
bool R = (digitalRead(S_RIGHT) == ON_BLACK);
int error = getLineError(L, M, R);
lastError = error;
// In log mỗi 100ms để không spam
unsigned long now = millis();
if (now - lastLogTime >= 100) {
lastLogTime = now;
Serial.printf("L:%d M:%d R:%d → Error:%+d\n", L, M, R, error);
// Error: -1=lệch trái, 0=đúng giữa, +1=lệch phải
// Dùng error để điều khiển motor với P hoặc PID controller
}
// Điều khiển motor ở đây (thêm tùy robot):
// int baseSpeed = 200;
// int kP = 100;
// int leftSpeed = baseSpeed + kP * error;
// int rightSpeed = baseSpeed - kP * error;
// setMotors(leftSpeed, rightSpeed);
delay(10); // Ngắn thôi — không block dài
}
Kết Quả Mong Đợi (Serial Monitor)
=== Line Tracking - ESP32 ===
L:0 M:1 R:0 → Error:+0 ← Robot đúng giữa vạch
L:0 M:0 R:1 → Error:+1 ← Robot lệch trái (vạch sang phải)
L:0 M:1 R:1 → Error:+1 ← Robot lệch trái nhiều
L:0 M:1 R:0 → Error:+0 ← Về giữa
L:1 M:0 R:0 → Error:-1 ← Robot lệch phải (vạch sang trái)
Ứng Dụng Thực Tế
| Ứng dụng | Chi tiết |
|---|---|
| Robot dò đường đơn giản | Vạch đen ~2cm trên nền trắng |
| Xe tự hành trong nhà kho | Theo băng phản quang dán sàn |
| Máy tự động theo đường ray | Sản xuất công nghiệp mini |
| Đếm vòng / Encoder đơn giản | Gắn nhìn vào đĩa kẻ đen trắng → đếm vòng quay |
| Phát hiện cạnh bàn | Sensor nhìn xuống — khi thấy “đen” (ngoài bàn) → dừng |
Lưu Ý Khi Sử Dụng
1. Xác định logic module trước khi viết code
Không giả định HIGH=đen hay LOW=đen. Chạy code test đơn giản đọc và in giá trị, đặt sensor lên vạch đen và nền trắng, ghi lại kết quả. Sau đó mới viết điều kiện cho robot.
2. Khoảng cách 2–5mm từ mặt đất — cố định khi di chuyển
Khoảng cách này phải giữ ổn định. Nếu robot rung lắc → khoảng cách thay đổi → đọc sai liên tục. Gắn module sensor chắc chắn vào chassis robot, không dùng dây nối dài lủng lẳng.
3. Chất lượng vạch và nền quan trọng
- Vạch đen in trên giấy trắng: tốt nhất
- Bề mặt bóng (sàn gạch men): phản xạ specular → có thể gây nhiễu
- Vạch quá hẹp (<1cm): sensor giữa có thể không phủ đủ
- Vạch quá rộng (>10cm với module 3 sensor): tất cả sensor đều trên đen → không biết hướng
4. Ánh sáng mạnh / Nắng mặt trời
Như IR obstacle, ánh sáng mạnh gây nhiễu IR. Với sensor nhìn xuống, ảnh hưởng ít hơn (nắng không chiếu thẳng vào sensor) nhưng vẫn cần chú ý. Test trong điều kiện ánh sáng thực tế của ứng dụng.
5. Cân nhắc P/PID controller thay vì if-else đơn giản
If-else chỉ có 3 mức (rẽ trái, thẳng, rẽ phải) → robot chạy giật cục, khó ổn định trên đường cong. Dùng Proportional control: motorDiff = Kp × error → điều chỉnh tốc độ mượt mà hơn. Với đường phức tạp: PID controller (P + I + D).


