IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series 37 Module Cảm Biến – Nguyên Lý Hoạt Động Line Tracking Sensor TCRT5000: Dò Đường IR, Khoảng Cách Tối Ưu & Robot Theo Vạch

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 ưu2mm – 5mm (TCRT5000)
Bước sóng IR890nm
Ngõ raDigital: logic phụ thuộc module
Dòng tiêu thụ mỗi sensor~20–40mA
Module 1 sensor1 OUT
Module 3 sensor3 OUT riêng biệt
Module 5 sensor5 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ânChức năng
VCC3.3V – 5V
GNDĐất
S1OUT / OUT_LDigital out sensor trái
S2OUT / OUT_MDigital out sensor giữa
S3OUT / OUT_RDigital 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 ưu2–5mm2–30cm
Hướng nhìnXuống bề mặtVề phía trước
Mục đíchPhân biệt đen/trắngPhát hiện vật thể
PackageLED+transistor cùng góiLED và photodiode rời
DetectorPhototransistor (có khuếch đại)Photodiode (thụ động hơn)
Khoảng cách moduleRất gần mặt đấtTrướ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ụngChi tiết
Robot dò đường đơn giảnVạch đen ~2cm trên nền trắng
Xe tự hành trong nhà khoTheo băng phản quang dán sàn
Máy tự động theo đường raySản xuất công nghiệp mini
Đếm vòng / Encoder đơn giảnGắn nhìn vào đĩa kẻ đen trắng → đếm vòng quay
Phát hiện cạnh bànSensor 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).

Bài tiếp theo: