Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường
Làm xe robot tự tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 gắn trên servo quét trái phải, cầu phân áp cho chân ECHO, thuật toán chọn đường, lưu đồ và thí nghiệm STEM.
Xe tránh vật cản là bước đầu tiên từ "xe điều khiển" sang "robot tự hành". Xe tự chạy thẳng; khi cảm biến siêu âm thấy vật phía trước, xe dừng, lùi lại, quay cảm biến nhìn sang hai bên rồi chọn hướng thoáng hơn để đi tiếp. Dự án dùng lại khung xe, L298N và cách nối động cơ của bài xe robot điều khiển qua Wi-Fi, thêm cảm biến HC-SR04 gắn trên một servo SG90.
Bài viết giải thích cách HC-SR04 đo khoảng cách, cách nối an toàn với ESP32 (chân ECHO ra 5 V), chương trình tránh vật cản kèm lưu đồ, và gợi ý thí nghiệm STEM.
1. HC-SR04 đo khoảng cách thế nào

- ESP32 phát một xung 10 µs vào chân TRIG.
- Cảm biến phát 8 chu kỳ siêu âm 40 kHz và đưa chân ECHO lên mức cao.
- Khi nhận được sóng dội về, ECHO xuống mức thấp. Độ rộng xung ECHO bằng thời gian sóng đi tới vật và quay về.
- Âm thanh đi khoảng 0,0343 cm mỗi micro giây, nên khoảng cách (cm) ≈ thời gian (µs) / 58. Ví dụ ECHO rộng 1450 µs ứng với 25 cm.
HC-SR04 đo khoảng 2–400 cm theo mô tả của nhà sản xuất. Vật mềm như vải, rèm, hoặc mặt phẳng nghiêng nhiều làm sóng dội về yếu hoặc lệch hướng, nên có thể đo sai.
Lưu ý mức điện áp: HC-SR04 loại thường cần 5 V và chân ECHO ra 5 V. Phải hạ xuống khoảng 3,3 V bằng cầu phân áp 1 kΩ / 2 kΩ trước khi vào ESP32: 5 V × 2 / 3 ≈ 3,3 V. Chân TRIG nhận mức 3,3 V của ESP32 được.
2. Linh kiện cần chuẩn bị
- Xe robot hai bánh đã lắp theo bài xe robot ESP32 điều khiển qua Wi-Fi: ESP32 DevKit V1, L298N, khung xe 2 động cơ, khay pin 18650 loại 2S.
- Cảm biến siêu âm HC-SR04 và giá gắn.
- Servo SG90.
- Điện trở 1 kΩ và 2 kΩ (hoặc hai điện trở 1 kΩ nối tiếp thay cho 2 kΩ).
- Dây cắm test board, breadboard mini để cắm cầu phân áp.
3. Sơ đồ nối dây

- HC-SR04 và servo lấy 5 V từ cùng nguồn cấp cho chân VIN của ESP32 (cọc 5V của L298N hoặc mạch hạ áp). GND nối chung.
- Dán HC-SR04 lên càng servo, đặt ở đầu xe. Khi servo ở 90°, cảm biến phải nhìn thẳng về phía trước.
- Phần động cơ giữ nguyên như bài xe robot Wi-Fi.
4. Thuật toán tránh vật cản

Mỗi vòng lặp, chương trình đo khoảng cách phía trước. Xa hơn 25 cm thì chạy tiếp. Gần hơn thì xe dừng, lùi một đoạn ngắn để có chỗ quay, rồi quay servo nhìn sang phải và sang trái. Bên nào thoáng hơn thì xe rẽ về bên đó. Nếu cả hai bên đều bị chặn, xe quay đầu.
5. Chương trình
/*
PYWORLD.VN - Xe robot tự tránh vật cản: ESP32 + cảm biến siêu âm HC-SR04 trên servo quét + L298N
HC-SR04: TRIG -> GPIO18, ECHO -> cầu phân áp 1k/2k -> GPIO19, VCC 5 V. Servo quét -> GPIO23
Động cơ như bài xe robot Wi-Fi: ENA 27, IN1 26, IN2 25 (trái); ENB 13, IN3 33, IN4 32 (phải)
*/
#define TRIG_PIN 18
#define ECHO_PIN 19
#define SERVO_PIN 23
#define ENA 27
#define IN1 26
#define IN2 25
#define ENB 13
#define IN3 33
#define IN4 32
const int KHOANG_DUNG = 25; // cm: gặp vật gần hơn thì dừng và tìm đường
const int TOC_DO = 60; // % khi chạy thẳng
const int TOC_DO_QUAY = 70; // % khi quay tại chỗ
const int GOC_THANG = 90, GOC_PHAI = 20, GOC_TRAI = 160; // góc servo, chỉnh theo cách lắp
void banh(int chanEN, int chanA, int chanB, int v) {
v = constrain(v, -100, 100);
digitalWrite(chanA, v > 0 ? HIGH : LOW);
digitalWrite(chanB, v < 0 ? HIGH : LOW);
ledcWrite(chanEN, (uint32_t)abs(v) * 1023 / 100);
}
void chay(int trai, int phai) {
banh(ENA, IN1, IN2, trai);
banh(ENB, IN3, IN4, phai);
}
void datGoc(int goc) { // servo 50 Hz, 500..2400 micro giây cho 0..180 độ
uint32_t us = 500 + 1900UL * constrain(goc, 0, 180) / 180;
ledcWrite(SERVO_PIN, (uint32_t)((uint64_t)us * 65536 / 20000));
}
// Một lần đo: xung TRIG 10 micro giây, đo độ rộng xung ECHO; quá 30 ms (khoảng 5 m) coi như không có vật
float doMotLan() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long t = pulseIn(ECHO_PIN, HIGH, 30000);
return (t == 0) ? 400 : t / 58.0; // cm: âm thanh đi và về, khoảng 58 micro giây cho mỗi cm
}
// Lấy trung vị của 3 lần đo để bỏ số đo sai lẻ tẻ
float doKhoangCach() {
float a = doMotLan(); delay(15);
float b = doMotLan(); delay(15);
float c = doMotLan();
return max(min(a, b), min(max(a, b), c));
}
float nhin(int goc) {
datGoc(goc);
delay(300); // chờ servo quay tới nơi
return doKhoangCach();
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
int chan[] = {IN1, IN2, IN3, IN4};
for (int p : chan) pinMode(p, OUTPUT);
ledcAttach(ENA, 1000, 10);
ledcAttach(ENB, 1000, 10);
ledcAttach(SERVO_PIN, 50, 16);
datGoc(GOC_THANG);
chay(0, 0);
delay(2000); // đặt xe xuống sàn
}
void loop() {
float truoc = doKhoangCach();
if (truoc > KHOANG_DUNG) {
chay(TOC_DO, TOC_DO);
delay(40);
return;
}
// Gặp vật cản: dừng, lùi một đoạn, quay đầu cảm biến nhìn hai bên
chay(0, 0);
Serial.printf("Truoc: %.0f cm -> dung", truoc);
delay(200);
chay(-TOC_DO, -TOC_DO);
delay(300);
chay(0, 0);
float phai = nhin(GOC_PHAI);
float trai = nhin(GOC_TRAI);
datGoc(GOC_THANG);
Serial.printf(", quet: phai %.0f cm, trai %.0f cm", phai, trai);
if (phai < KHOANG_DUNG && trai < KHOANG_DUNG) {
Serial.println(" -> quay dau");
chay(TOC_DO_QUAY, -TOC_DO_QUAY);
delay(700);
} else if (phai >= trai) {
Serial.println(" -> re phai");
chay(TOC_DO_QUAY, -TOC_DO_QUAY);
delay(350);
} else {
Serial.println(" -> re trai");
chay(-TOC_DO_QUAY, TOC_DO_QUAY);
delay(350);
}
chay(0, 0);
delay(200);
}
doMotLan()phát xung TRIG, đo độ rộng xung ECHO bằngpulseIn()với thời gian chờ tối đa 30 ms (khoảng 5 m). Không có tiếng vọng thì trả về 400 cm, nghĩa là phía trước thoáng.doKhoangCach()đo 3 lần và lấy số ở giữa (trung vị), để một lần đo sai không làm xe dừng vô cớ.- Servo được điều khiển bằng PWM 50 Hz, 16 bit như bài servo SG90 trong cùng loạt, không cần thư viện.
- Các hằng số
KHOANG_DUNG,TOC_DO, thời gian rẽ 350 ms phụ thuộc xe của bạn. Chỉnh để xe rẽ được khoảng 90°.
Serial Monitor (115200 baud) in quyết định mỗi lần gặp vật, ví dụ: Truoc: 22 cm -> dung, quet: phai 80 cm, trai 35 cm -> re phai. Khi thử, có thể nhấc bánh xe lên khỏi bàn và đưa tay trước cảm biến để xem.
6. Gợi ý dùng trong giờ học STEM
Mục tiêu: học sinh hiểu cảm biến, ra quyết định và chấp hành trong một robot tự hành; đo đạc và thử nghiệm để cải tiến thuật toán.
- Kiểm chứng tốc độ âm thanh. Đặt một tấm bìa cách cảm biến 10, 20, 30, 50 cm (đo bằng thước). In ra thời gian ECHO, tính tốc độ âm thanh từ số liệu và so với 343 m/s.
- Vật nào khó thấy? Thử với tấm gỗ, cốc thủy tinh, vải, bọt biển, tấm bìa đặt nghiêng 45°. Ghi lại khoảng cách đo được và giải thích.
- Mê cung bằng hộp giấy. Xếp hộp thành mê cung, đo thời gian xe thoát ra. Các nhóm đổi
KHOANG_DUNG, tốc độ, thời gian rẽ để cải thiện kết quả. - Cải tiến thuật toán. Thay vì dừng hẳn, cho xe giảm tốc dần khi lại gần vật, với tốc độ tỉ lệ với khoảng cách. Đây là bước đầu của điều khiển tỉ lệ (P).
7. Xử lý lỗi thường gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| Luôn đo được 400 cm | Không có xung ECHO: sai dây, thiếu 5 V, nối nhầm TRIG và ECHO | Kiểm tra VCC 5 V, GND chung; kiểm tra cầu phân áp |
| Khoảng cách nhảy lung tung | Sóng dội từ sàn hoặc thân xe; nguồn nhiễu khi động cơ chạy | Gắn cảm biến cao hơn mặt sàn và nhô ra khỏi thân xe; thêm tụ 100 µF ở nguồn 5 V của cảm biến |
| Xe rẽ quá ít hoặc quá nhiều | Thời gian rẽ không hợp với xe | Chỉnh 350 ms và 700 ms; pin yếu thì xe rẽ ít hơn |
| Xe đâm vào vật trước khi dừng | Chạy nhanh, khoảng dừng ngắn | Tăng KHOANG_DUNG, giảm TOC_DO |
| Cảm biến không nhìn đúng hướng | Góc servo khác cách lắp | Chỉnh GOC_THANG, GOC_PHAI, GOC_TRAI |
8. Xem thêm
- Thanh cảm biến dò line 5 kênh TCRT5000 với ESP32, để làm xe dò line
- Mức logic 3,3 V và 5 V: khi nào cần chuyển mức
- PWM trên ESP32
Cùng loạt: xe robot ESP32 điều khiển qua Wi-Fi, ESP32 điều khiển servo SG90, ESP32 điều khiển động cơ DC với L298N.
Xem thêm