IR Obstacle Sensor (cảm biến tránh vật cản hồng ngoại) hoạt động bằng cách phát sóng IR và phát hiện IR phản xạ về. Đơn giản nhưng có nhiều chi tiết quan trọng: tại sao bị nhiễu ánh sáng mặt trời, màu sắc và chất liệu vật thể ảnh hưởng thế nào, và tại sao không nên dùng ngoài trời. Bài này phân tích nguyên lý đầy đủ và code robot tránh vật cản thực tế.
Nguyên Lý Hoạt Động
1. Cặp Phát-Thu Hồng Ngoại
Module gồm 2 thành phần chính đặt cạnh nhau:
Vật thể
╱╲
IR phát ──→╱ ╲──→ IR phản xạ
╱ ╲
LED IR Photodiode
(940nm) ────→ IR thu
[Phát] [Nhận]
LED IR (Emitter):
- Phát liên tục sóng IR, bước sóng 850–950nm (thường 940nm)
- Mắt người không nhìn thấy nhưng camera điện thoại thấy (thử chiếu vào camera điện thoại — thấy màu tím/hồng)
- Góc phát: 20°–40° (khá hẹp)
Photodiode IR (Receiver):
- Thay đổi điện trở (hoặc tạo dòng ngược) khi nhận IR
- Nhạy nhất với 940nm (khớp với emitter)
- Trường nhìn: ~60°
Khi có vật cản: Vật thể phản xạ IR về phía receiver → cường độ IR nhận được tăng → photodiode dẫn nhiều hơn → điện áp ở điểm đo thay đổi → LM393 phát hiện → OUT thay đổi.
2. Mạch Điện — Cầu Phân Áp + LM393
VCC
│
[R_LED] (thường ~100Ω – 330Ω)
│
[LED IR] (emitter — phát liên tục)
│
GND
VCC
│
[R_pull] (pull-up, thường 10kΩ – 47kΩ)
│
├──── V_sense (đến LM393 input +)
│
[Photodiode] (bị phân cực ngược — reverse bias)
│
GND
LM393 comparator:
V_sense (+) vs V_ref (-) → OUT
V_ref điều chỉnh bằng triết áp (reference voltage = ngưỡng)
Logic output:
| Trạng thái | V_sense | Vsense vs Vref | OUT | LED báo |
|---|---|---|---|---|
| Không vật cản | Cao (photodiode nhận ít IR) | Vsense > Vref | HIGH | Tắt |
| Có vật cản | Thấp (photodiode nhận nhiều IR phản xạ) | Vsense < Vref | LOW | Sáng |
OUT LOW = có vật cản — đây là logic âm (active LOW). Cần chú ý khi viết code: if (digitalRead(OUT_PIN) == LOW) thì có vật cản.
3. Triết Áp Điều Chỉnh Khoảng Cách
Triết áp trên module thay đổi V_ref của LM393:
- Vặn tăng V_ref: Cần ít IR phản xạ hơn để trigger → phát hiện vật thể xa hơn, nhạy hơn
- Vặn giảm V_ref: Cần nhiều IR phản xạ hơn → chỉ phát hiện vật gần hơn, kém nhạy hơn
Khoảng cách điều chỉnh được: thường 2cm–30cm tùy module.
4. Tại Sao Màu Và Chất Liệu Ảnh Hưởng Kết Quả
IR 940nm phản xạ rất khác nhau tùy vật liệu:
| Vật liệu / Màu | Phản xạ IR | Kết quả |
|---|---|---|
| Trắng, nhẵn | Cao (~90%) | Phát hiện dễ, xa |
| Đen, nhám | Thấp (<5%) | Phát hiện khó, gần |
| Gương, kim loại | Phản xạ specular (lệch góc) | Có thể không phát hiện |
| Kính | Trong suốt một phần với IR | Phụ thuộc loại kính |
| Vải đen | Rất thấp | Thường không phát hiện |
Thực tế robot: Tường trắng → phát hiện từ 20–30cm. Vải đen → chỉ phát hiện từ 3–5cm hoặc không phát hiện.
5. Vấn Đề Nhiễu Ánh Sáng Mặt Trời
Ánh sáng mặt trời chứa lượng lớn IR ở mọi bước sóng, bao gồm 940nm. Khi photodiode nhận nhiều IR từ ánh sáng mặt trời → V_sense luôn thấp → module báo “có vật cản” liên tục dù không có gì.
Dấu hiệu bị nhiễu nắng: Module báo vật cản ngay cả khi không có vật thể, hoặc LED OUT sáng liên tục.
Giải pháp:
- Chỉ dùng trong nhà hoặc bóng râm — không dùng ngoài trời có nắng
- Module E18-D80NK có vỏ ống chắn sáng xung quanh — ít bị nhiễu hơn FC-51 dạng phẳng
- Sensor dùng IR điều chế 38kHz (như Sharp GP2Y hoặc sensor dùng TSOP) — khả năng lọc nhiễu tốt hơn nhiều
- Tăng cường độ LED IR (giảm điện trở R_LED) để thắng nhiễu ánh sáng — nhưng tiêu hao dòng nhiều hơn
Thông Số Kỹ Thuật (Module FC-51)
| Thông số | Giá trị |
|---|---|
| Điện áp hoạt động | 3.3V – 5V |
| Dòng tiêu thụ | ~20–40mA |
| Tầm phát hiện | 2cm – 30cm (điều chỉnh bằng triết áp) |
| Góc phát hiện | ~35° |
| Bước sóng LED IR | 940nm |
| Ngõ ra | Digital: LOW khi có vật cản, HIGH khi không |
| Comparator | LM393 |
| Kích thước | 31mm × 14mm |
Sơ Đồ Chân (Pinout)
[LED IR] [Photodiode]
┌──────────────────────┐
│ IR Obstacle Sensor │
│ [Triết áp] [LED báo]│
│ LM393 Comparator │
└──────────────────────┘
VCC GND OUT
| Chân | Chức năng |
|---|---|
| VCC | 3.3V – 5V |
| GND | Đất |
| OUT | Digital: LOW = có vật cản, HIGH = không có vật cản |
Module 4 chân (một số loại): Có thêm chân EN (enable) để bật/tắt emitter — hữu ích khi muốn cấp nguồn xung để tiết kiệm điện.
So Sánh Các Loại Sensor Tránh Vật Cản
| Sensor | Nguyên lý | Tầm xa | Đầu ra | Chú ý |
|---|---|---|---|---|
| FC-51 / TCRT5000 | IR phản xạ | 2–30cm | Digital | Dễ bị nhiễu nắng |
| E18-D80NK | IR phản xạ (có vỏ ống) | 3–80cm | Digital | Ít nhiễu hơn FC-51 |
| Sharp GP2Y0A21YK | IR phản xạ (PSD) | 10–80cm | Analog | Chính xác hơn, ít nhiễu |
| Sharp GP2Y0A02YK | IR phản xạ (PSD) | 20–150cm | Analog | Tầm xa hơn |
| HC-SR04 | Siêu âm | 2–400cm | Pulse | Không bị nhiễu nắng |
| VL53L0X | Laser ToF | 2–200cm | I2C | Chính xác nhất |
Khi nào dùng loại nào:
- Robot trong nhà đơn giản: FC-51 (rẻ nhất)
- Cần tầm xa hoặc ngoài nhà: Sharp GP2Y hoặc HC-SR04
- Cần khoảng cách chính xác (mm): VL53L0X (ToF)
Kết Nối Phần Cứng
Kết Nối với ESP32 DevKit V1
FC-51 chạy 3.3V–5V → tương thích trực tiếp với ESP32:
ESP32 DevKit V1 IR Obstacle Sensor (FC-51)
───────────────────── ────────────────────────────
3V3 ─────────────────→ VCC (hoặc 5V từ VIN)
GND ─────────────────→ GND
GPIO4 (Input) ←───────── OUT (3.3V hay 5V → an toàn với cả 2)
Cấp 3.3V: OUT HIGH = ~3.3V, OUT LOW = ~0V → tương thích GPIO ESP32. Cấp 5V: OUT HIGH = ~5V → cần kiểm tra module có phân áp out không. Hầu hết module FC-51 out thấp hơn VCC vì qua LM393 open collector → an toàn.
An toàn nhất: Cấp 3.3V cho module khi dùng ESP32.
Kết Nối với Arduino Uno
Arduino Uno IR Obstacle Sensor (FC-51)
───────────────────── ────────────────────────────
5V ─────────────────→ VCC
GND ─────────────────→ GND
Pin 7 (Input) ←────────── OUT
Code Arduino IDE
Code Đơn Giản — Arduino Uno
/*
* IR Obstacle Sensor FC-51 — Phát hiện vật cản
* Board: Arduino Uno
* Kết nối: VCC→5V, GND→GND, OUT→Pin7
*
* Điều chỉnh triết áp trên module:
* - Vặn theo chiều kim đồng hồ: tăng khoảng cách phát hiện
* - Vặn ngược: giảm khoảng cách
*
* OUT LOW = có vật cản (logic âm — chú ý!)
* OUT HIGH = không có vật cản
*/
const int IR_SENSOR_PIN = 7;
void setup() {
Serial.begin(9600);
pinMode(IR_SENSOR_PIN, INPUT);
Serial.println("=== IR Obstacle Sensor - Arduino Uno ===");
Serial.println("Điều chỉnh triết áp để đặt khoảng cách phát hiện.");
}
void loop() {
// LOW = có vật cản (logic đảo!)
bool obstacleDetected = (digitalRead(IR_SENSOR_PIN) == LOW);
if (obstacleDetected) {
Serial.println("VẬT CẢN PHÁT HIỆN!");
} else {
Serial.println("Đường thông.");
}
delay(200);
}
Code Robot Tránh Vật Cản — Arduino Uno (2 Sensor)
/*
* IR Obstacle Sensor — Robot 2 bánh tránh vật cản
* Board: Arduino Uno
* 2 sensor IR: trái và phải
* Kết nối sensor: VCC→5V, GND→GND, OUT_TRÁI→Pin6, OUT_PHẢI→Pin7
* Motor driver L298N (ví dụ):
* ENA→Pin9(PWM), IN1→Pin2, IN2→Pin3 (Motor trái)
* ENB→Pin10(PWM), IN3→Pin4, IN4→Pin5 (Motor phải)
*/
// Sensor pins
const int IR_LEFT = 6; // Sensor hồng ngoại bên trái
const int IR_RIGHT = 7; // Sensor hồng ngoại bên phải
// Motor pins (L298N)
const int ENA = 9; // PWM - tốc độ motor trái
const int IN1 = 2;
const int IN2 = 3;
const int ENB = 10; // PWM - tốc độ motor phải
const int IN3 = 4;
const int IN4 = 5;
const int SPEED = 150; // Tốc độ 0-255
// Điều khiển motor: tốc độ>0=tiến, <0=lùi, =0=dừng
void setMotors(int leftSpeed, int rightSpeed) {
// Motor trái
analogWrite(ENA, abs(leftSpeed));
if (leftSpeed > 0) { digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); }
else if (leftSpeed < 0) { digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); }
else { digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); }
// Motor phải
analogWrite(ENB, abs(rightSpeed));
if (rightSpeed > 0) { digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); }
else if (rightSpeed < 0) { digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); }
else { digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); }
}
void setup() {
Serial.begin(9600);
pinMode(IR_LEFT, INPUT);
pinMode(IR_RIGHT, INPUT);
pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
Serial.println("=== Robot Tránh Vật Cản - IR ===");
}
void loop() {
// LOW = có vật cản (logic âm của FC-51)
bool leftBlocked = (digitalRead(IR_LEFT) == LOW);
bool rightBlocked = (digitalRead(IR_RIGHT) == LOW);
if (!leftBlocked && !rightBlocked) {
// Không có vật cản → tiến thẳng
setMotors(SPEED, SPEED);
Serial.println("Tiến thẳng");
} else if (leftBlocked && !rightBlocked) {
// Trái có vật cản → rẽ phải (motor trái dừng, phải chạy)
setMotors(0, SPEED);
Serial.println("Vật cản TRÁI → Rẽ phải");
} else if (!leftBlocked && rightBlocked) {
// Phải có vật cản → rẽ trái
setMotors(SPEED, 0);
Serial.println("Vật cản PHẢI → Rẽ trái");
} else {
// Cả hai có vật cản → lùi
setMotors(-SPEED, -SPEED);
delay(300);
// Sau khi lùi → quay phải
setMotors(SPEED, -SPEED);
delay(400);
Serial.println("Cả hai vật cản → Lùi + Quay");
}
delay(100);
}
Code ESP32 — Interrupt Phát Hiện Vật Cản Tức Thì
/*
* IR Obstacle Sensor FC-51 — ESP32, phát hiện và cảnh báo
* Board: ESP32 DevKit V1
* Kết nối: VCC→3V3, GND→GND, OUT→GPIO4
*/
const int IR_PIN = 4;
const int LED_PIN = 2; // LED onboard ESP32
volatile bool obstacleFlag = false;
volatile bool clearFlag = false;
unsigned long lastObstacleTime = 0;
void IRAM_ATTR onObstacleChange() {
if (digitalRead(IR_PIN) == LOW) {
// LOW = vật cản
obstacleFlag = true;
lastObstacleTime = millis();
} else {
// HIGH = đường thông
clearFlag = true;
}
}
void setup() {
Serial.begin(115200);
pinMode(IR_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
// Interrupt CHANGE — bắt cả lên và xuống
attachInterrupt(digitalPinToInterrupt(IR_PIN), onObstacleChange, CHANGE);
Serial.println("=== IR Obstacle Sensor - ESP32 Interrupt Mode ===");
Serial.println("Điều chỉnh triết áp module để đặt khoảng cách cần phát hiện.");
}
void loop() {
if (obstacleFlag) {
obstacleFlag = false;
digitalWrite(LED_PIN, HIGH); // Bật LED cảnh báo
Serial.printf("[%lums] VẬT CẢN!\n", lastObstacleTime);
// Thêm: bật còi, dừng động cơ, gửi MQTT...
}
if (clearFlag) {
clearFlag = false;
digitalWrite(LED_PIN, LOW);
Serial.printf("[%lums] Đường thông.\n", millis());
}
delay(10);
}
Kết Quả Mong Đợi
=== IR Obstacle Sensor - ESP32 Interrupt Mode ===
Điều chỉnh triết áp module để đặt khoảng cách cần phát hiện.
[1234ms] VẬT CẢN!
[1890ms] Đường thông.
[2450ms] VẬT CẢN!
Ứng Dụng Thực Tế
| Ứng dụng | Chi tiết |
|---|---|
| Robot tránh vật cản | 2-4 sensor xung quanh robot |
| Dò đường line following | Nhìn xuống mặt đất, phân biệt đen/trắng |
| Đếm sản phẩm trên băng chuyền | Mỗi sản phẩm đi qua = 1 count |
| Phát hiện tiếp giáp cửa | Sensor trong khe cửa — phát hiện đóng/mở |
| Smart dustbin tự mở nắp | Phát hiện tay đưa vào → servo mở nắp |
| Phát hiện giấy vào máy in | Trong các thiết bị văn phòng |
Lưu Ý Khi Sử Dụng
1. Logic đảo — OUT LOW = có vật cản
Nhiều người bị nhầm viết if (digitalRead(PIN) == HIGH) cho “có vật cản” → code không bao giờ phát hiện. Phải là if (digitalRead(PIN) == LOW). LED báo trên module sáng khi có vật cản — dùng LED này để kiểm tra logic trước khi đọc code.
2. Không dùng ngoài trời có nắng
Ánh sáng mặt trời chứa IR 940nm đậm đặc → module luôn báo “có vật cản” dù không có gì. Chỉ dùng trong nhà hoặc bóng râm. Nếu cần ngoài trời: dùng HC-SR04 (siêu âm) hoặc Sharp GP2Y (IR điều chế).
3. Vật đen không phản xạ IR — có thể không phát hiện được
Vật có màu đen hoặc bề mặt hấp thu (vải nhung, cao su đen) phản xạ rất ít IR → sensor không phát hiện dù vật ở ngay trước. Điều này đặc biệt quan trọng với robot dò đường: vạch đen cần phản xạ thấp, nền trắng phản xạ cao.
4. Triết áp cần điều chỉnh thực tế
Không có “vị trí chuẩn” cho triết áp — phụ thuộc màu sắc, chất liệu vật thể, và ánh sáng môi trường. Điều chỉnh với vật thể thực tế sẽ dùng trong ứng dụng. Vặn từ từ và quan sát LED báo trên module.
5. Nhiễu chéo nếu nhiều sensor
Nếu dùng nhiều IR sensor gần nhau → IR từ emitter của sensor này có thể đến receiver của sensor khác → đọc sai. Giải pháp: luân phiên kích hoạt từng sensor (bật emitter 1, đọc receiver 1, tắt, rồi bật emitter 2…) hoặc đặt sensor đủ xa nhau.


