Robot dò line với ESP32: dự án STEM cuối khóa cho học sinh

Làm robot dò line với ESP32, thanh 5 cảm biến TCRT5000 và L298N: bản 1 ba quy tắc nếu thì, bản 2 lái theo tỉ lệ độ lệch (điều khiển P), cách làm sân thi đấu cuối khóa.

Robot dò line là dự án quen thuộc nhất của các khóa học STEM và các cuộc thi robot cho học sinh: một chiếc xe nhỏ tự chạy theo vạch đen trên nền trắng. Dự án gom lại gần như mọi thứ đã học: cảm biến, câu lệnh điều kiện, vòng lặp, điều khiển động cơ, và cả một chút toán. Bài viết hướng dẫn làm robot dò line bằng ESP32, thanh 5 cảm biến hồng ngoại và driver L298N, với hai bản chương trình: bản 1 dùng ba quy tắc "nếu… thì…", bản 2 lái theo tỉ lệ độ lệch cho xe chạy mượt hơn. Cuối bài là gợi ý làm sân thi đấu cho buổi tổng kết khóa học.

1. Chuẩn bị

Phần khung xe, động cơ, L298N và pin giống hệt các bài xe robot ESP32 đã đăng, nên có thể dùng lại chiếc xe đã làm và chỉ thêm thanh dò line.

2. Nối dây

Sơ đồ khối: thanh dò line 5 kênh gửi S1 đến S5 vào ESP32 DevKit V1; ESP32 điều khiển L298N và 2 động cơ qua ENA IN1 IN2 là D27 D26 D25, ENB IN3 IN4 là D13 D33 D32; pin 2 viên 18650 qua công tắc vào L298N, 5V từ L298N vào VIN; bảng chân S1 D4, S2 S3 S4 là RX2 16, TX2 17, D18, S5 D19, VCC 3V3
Hình minh họa: chân giống loạt bài xe robot ESP32.
Chân nối robot dò line
Linh kiệnChânNối tới ESP32
Thanh dò lineS1, S2, S3, S4, S5D4, RX2 (16), TX2 (17), D18, D19
Thanh dò lineVCC, GND3V3, GND
L298N (động cơ trái)ENA, IN1, IN2D27, D26, D25
L298N (động cơ phải)ENB, IN3, IN4D13, D33, D32
L298N5V, GNDVIN, GND

Lắp thanh cảm biến ở đầu xe, cách mặt sân khoảng 1–2 cm, S1 bên trái và S5 bên phải (nhìn từ sau xe tới). Mọi dây GND (ESP32, L298N, pin, thanh cảm biến) phải nối chung với nhau.

3. Cảm biến dò line nhìn vạch thế nào?

Mỗi mắt TCRT5000 gồm một đèn phát hồng ngoại và một bộ thu đặt cạnh nhau. Nền trắng phản xạ nhiều ánh sáng hồng ngoại về bộ thu, vạch đen hấp thụ gần hết. Mạch trên thanh so sánh lượng ánh sáng nhận được với một ngưỡng và cho ra mức 0 hoặc 1 ở từng chân S1–S5.

Trước khi lắp lên xe, nên chạy chương trình 1 của bài thanh dò line TCRT5000 (link ở cuối bài) để xem kênh nằm trên vạch đen cho mức nào. Nếu là mức 1, đổi MUC_VACH thành HIGH trong cả hai chương trình dưới đây.

4. Bản 1: ba quy tắc "nếu… thì…"

Ba ô nhìn từ trên xuống: vạch ở giữa, mẫu 00100, đi thẳng trái 55 phải 55 phần trăm; vạch lệch trái, mẫu 01000, rẽ trái bánh trái 0 bánh phải 60 phần trăm; vạch lệch phải, mẫu 00010, rẽ phải bánh trái 60 bánh phải 0
Hình minh họa: chấm đen là kênh đang thấy vạch.
// PYWORLD.VN - Robot dò line cho học sinh, bản 1: ba quy tắc "nếu… thì…"
// Thanh dò line 5 kênh: S1..S5 -> D4, RX2 (16), TX2 (17), D18, D19; L298N như loạt xe robot
// Động cơ trái: ENA 27, IN1 26, IN2 25; động cơ phải: ENB 13, IN3 33, IN4 32

#define ENA 27
#define IN1 26
#define IN2 25
#define ENB 13
#define IN3 33
#define IN4 32

const int CHAN_LINE[5] = {4, 16, 17, 18, 19};   // S1 (trái) ... S5 (phải)
const int MUC_VACH = LOW;       // mức của một kênh khi nằm trên vạch đen; đổi thành HIGH nếu module ngược lại
const int TOC_DO = 55;          // % khi đi thẳng
const int TOC_DO_RE = 60;       // % bánh ngoài khi rẽ

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);
}

bool thayVach(int kenh) {
  return digitalRead(CHAN_LINE[kenh]) == MUC_VACH;
}

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < 5; i++) pinMode(CHAN_LINE[i], INPUT);
  int chan[] = {IN1, IN2, IN3, IN4};
  for (int p : chan) pinMode(p, OUTPUT);
  ledcAttach(ENA, 1000, 10);
  ledcAttach(ENB, 1000, 10);
  chay(0, 0);
  delay(2000);                  // đặt xe lên vạch
}

void loop() {
  bool trai = thayVach(0) || thayVach(1);
  bool giua = thayVach(2);
  bool phai = thayVach(3) || thayVach(4);

  if (giua && !trai && !phai) {
    chay(TOC_DO, TOC_DO);       // vạch ở giữa: đi thẳng
  } else if (trai) {
    chay(0, TOC_DO_RE);         // vạch lệch sang trái: rẽ trái
  } else if (phai) {
    chay(TOC_DO_RE, 0);         // vạch lệch sang phải: rẽ phải
  } else {
    chay(0, 0);                 // không thấy vạch: dừng lại
  }
  delay(5);
}
  • Chương trình gộp năm kênh thành ba nhóm: trái (S1, S2), giữa (S3), phải (S4, S5).
  • Vạch ở giữa: hai bánh cùng chạy, xe đi thẳng. Vạch lệch trái: bánh trái dừng, bánh phải chạy, xe quẹo trái về phía vạch. Lệch phải thì ngược lại.
  • Không kênh nào thấy vạch: xe dừng lại cho an toàn.

Bản này rất dễ hiểu với học sinh, nhưng xe thường lắc qua lắc lại vì chỉ có ba cách lái: thẳng, quẹo hẳn trái, quẹo hẳn phải.

5. Bản 2: lái theo tỉ lệ độ lệch

Bảng 9 mẫu 5 kênh từ 10000 đến 00001 với vị trí vạch từ âm 2 đến cộng 2 và tốc độ bánh trái, bánh phải; vị trí 0 thì hai bánh 50 phần trăm, vị trí âm 2 thì trái 6 phải 94; đồ thị hai đường thẳng cắt nhau ở vị trí 0; công thức bánh trái bằng 50 cộng KP nhân vị trí, bánh phải bằng 50 trừ KP nhân vị trí, KP bằng 22
Hình minh họa: tính đúng như chương trình bản 2.
// PYWORLD.VN - Robot dò line cho học sinh, bản 2: lái theo tỉ lệ độ lệch (điều khiển P)
// Vị trí vạch tính từ 5 kênh (-2 bên trái ... +2 bên phải); lệch càng nhiều, lái càng mạnh
// Mất vạch thì quay về phía vạch vừa thấy lần cuối; chân giống bản 1

#define ENA 27
#define IN1 26
#define IN2 25
#define ENB 13
#define IN3 33
#define IN4 32

const int CHAN_LINE[5] = {4, 16, 17, 18, 19};   // S1 (trái) ... S5 (phải)
const int TRONG_SO[5] = {-2, -1, 0, 1, 2};
const int MUC_VACH = LOW;       // đổi thành HIGH nếu module cho mức 1 khi gặp vạch
const int TOC_DO = 50;          // % tốc độ nền
const float KP = 22.0;          // hệ số lái: vạch lệch 1 thì chênh tốc độ 2 bánh là 2 x 22 %
const int TOC_DO_TIM = 45;      // % khi quay tại chỗ để tìm lại vạch

float viTriCuoi = 0;

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 setup() {
  Serial.begin(115200);
  for (int i = 0; i < 5; i++) pinMode(CHAN_LINE[i], INPUT);
  int chan[] = {IN1, IN2, IN3, IN4};
  for (int p : chan) pinMode(p, OUTPUT);
  ledcAttach(ENA, 1000, 10);
  ledcAttach(ENB, 1000, 10);
  chay(0, 0);
  delay(2000);
}

void loop() {
  int tong = 0, dem = 0;
  for (int i = 0; i < 5; i++) {
    if (digitalRead(CHAN_LINE[i]) == MUC_VACH) {
      tong += TRONG_SO[i];
      dem++;
    }
  }

  if (dem == 0) {               // mất vạch: quay tại chỗ về phía vạch vừa thấy
    if (viTriCuoi < 0) chay(-TOC_DO_TIM, TOC_DO_TIM);
    else chay(TOC_DO_TIM, -TOC_DO_TIM);
  } else {
    float viTri = (float)tong / dem;          // -2.0 ... +2.0
    viTriCuoi = viTri;
    int lai = (int)(KP * viTri);              // vạch lệch phải (dương): bánh trái nhanh hơn
    chay(TOC_DO + lai, TOC_DO - lai);
  }
  delay(5);
}
  • Vị trí vạch: mỗi kênh có một trọng số từ −2 (S1) tới +2 (S5). Vị trí là trung bình trọng số của các kênh đang thấy vạch, ví dụ S2 và S3 cùng thấy vạch thì vị trí là (−1 + 0) : 2 = −0,5. Đây là phép trung bình cộng học sinh đã biết từ lớp 4.
  • Lái tỉ lệ: vạch lệch càng xa, chênh lệch tốc độ hai bánh càng lớn: bánh trái = 50 + KP × vị trí, bánh phải = 50 − KP × vị trí. Lệch ít thì quẹo nhẹ, lệch nhiều thì quẹo gắt, nên xe đi mượt hơn hẳn bản 1. Cách lái này gọi là điều khiển P (tỉ lệ), phần đầu tiên của bộ điều khiển PID.
  • Mất vạch: xe nhớ vị trí vạch lần cuối (viTriCuoi) và quay tại chỗ về phía đó để tìm lại, thay vì dừng hẳn.
  • Chỉnh KP: xe không kịp vào cua thì tăng KP; xe lắc mạnh trên đường thẳng thì giảm KP hoặc giảm TOC_DO.

6. Sân thi đấu cho buổi tổng kết

Sân đua dạng vòng kín vẽ vạch đen trên nền trắng, có khúc cua rộng và khúc S, vạch xuất phát màu đỏ; ghi chú: nền giấy trắng khổ lớn, vạch băng dính điện màu đen rộng khoảng 2 cm, khúc cua đầu tiên bán kính từ 20 cm
Hình minh họa: vòng đua có khúc cua và khúc S.
  • Sân: nền giấy trắng khổ lớn hoặc tấm xốp trắng ghép lại, vạch bằng băng dính điện màu đen rộng khoảng 2 cm.
  • Độ khó tăng dần: vòng đầu chỉ có khúc cua rộng (bán kính từ 20 cm); vòng sau thêm khúc S, góc vuông, ngã tư.
  • Luật gợi ý: mỗi đội chạy 2 lượt, tính thời gian một vòng tốt nhất; trượt khỏi vạch quá 3 giây thì lượt đó không tính. Có thêm giải "xe chạy mượt nhất" và "thuyết trình hay nhất" để mọi đội đều có động lực.

7. Xử lý lỗi thường gặp

Lỗi thường gặp và cách xử lý
Hiện tượngNguyên nhân thường gặpCách xử lý
Xe chạy lùi thay vì tiếnDây động cơ nối ngượcĐổi hai dây của động cơ đó ở cọc OUT của L298N
Vạch lệch trái mà xe quẹo phải, càng chạy càng xa vạchThanh cảm biến lắp ngược (S1 bên phải) hoặc hai động cơ bị đổi chỗLắp S1 bên trái; hoặc đổi chỗ dây hai động cơ ở cọc OUT1/OUT2 và OUT3/OUT4
Xe không bao giờ thấy vạch, hoặc luôn thấy vạchSai mức MUC_VACH; cảm biến quá cao hoặc quá thấpKiểm tra bằng chương trình đọc 5 kênh; chỉnh độ cao cảm biến 1–2 cm
ESP32 tự khởi động lại khi động cơ chạyPin yếu, sụt áp khi động cơ kéo dòngSạc đầy pin; giảm TOC_DO; kiểm tra dây GND chung
Xe lắc mạnh trên đường thẳngKP quá lớn hoặc chạy quá nhanhGiảm KP từng bước 2–3, giảm TOC_DO

8. Gợi ý cho phụ huynh và giáo viên

  • Làm theo đội: mỗi đội 3–4 học sinh với các vai: lắp ráp, nối dây, lập trình, thử nghiệm và ghi chép. Đổi vai giữa các buổi.
  • Ghi chép như kỹ sư: mỗi lần đổi KP hay tốc độ, ghi lại giá trị và thời gian chạy một vòng. Cuối khóa, đội trình bày biểu đồ "KP và thời gian".
  • Kiến thức gom lại: cảm biến hồng ngoại (Khoa học), trung bình cộng và tỉ lệ (Toán), điều kiện và vòng lặp (Tin học), động cơ và bánh xe (Công nghệ).
  • Thời lượng: 3–4 buổi 60 phút: lắp xe và nối dây; bản 1; bản 2 và chỉnh KP; thi đấu và thuyết trình.
  • An toàn: pin 18650 nằm trong khay, có công tắc nguồn; tắt công tắc khi nạp chương trình và khi không chạy xe.

9. Xem thêm


Tin tức liên quan

Jack Type-C sạc pin loại 4 dây: một cổng vừa sạc pin 1S vừa truyền dữ liệu USB
Jack Type-C sạc pin loại 4 dây: một cổng vừa sạc pin 1S vừa truyền dữ liệu USB

Jack Type-C tích hợp mạch sạc loại 4 dây có thêm D+ D− để một cổng vừa sạc pin 1S vừa nối USB với máy tính. Bài hướng dẫn xác định từng dây bằng đồng hồ, nối vào vi điều khiển và các lưu ý khi dùng chung cổng.

G-code là gì: các lệnh G0, G1, G2, G3, M3, M5 cơ bản và cách đọc một file G-code
G-code là gì: các lệnh G0, G1, G2, G3, M3, M5 cơ bản và cách đọc một file G-code

G-code là gì, các lệnh G0 G1 G2 G3 G90 G91 M3 M5 F S dùng nhiều nhất trên máy CNC, máy laser chạy GRBL, cung tròn I J, gốc phôi, kèm chương trình Python tự sinh G-code.

Cách đọc giấy chứng nhận hiệu chuẩn: sai số, độ không đảm bảo, số hiệu chính và điểm cần kiểm tra
Cách đọc giấy chứng nhận hiệu chuẩn: sai số, độ không đảm bảo, số hiệu chính và điểm cần kiểm tra

Cách đọc giấy chứng nhận hiệu chuẩn: các phần bắt buộc theo ISO/IEC 17025, bảng sai số chiều tăng giảm, độ không đảm bảo và hệ số phủ k, áp dụng số hiệu chính và lỗi hay gặp.

Hiệu chuẩn load cell tại hiện trường: tải thật, mô phỏng mV/V, thế chỗ, ISO 376 và ASTM E74
Hiệu chuẩn load cell tại hiện trường: tải thật, mô phỏng mV/V, thế chỗ, ISO 376 và ASTM E74

Hiệu chuẩn hệ load cell tại hiện trường: chuỗi đo và nguồn sai số, tải thật so với mô phỏng mV/V, thế chỗ cho cân bồn, lưu ý lắp đặt, so sánh ISO 376 và ASTM E74.

Op-amp: so sánh, khuếch đại không đảo, mạch đệm và đo hệ số khuếch đại bằng ESP32
Op-amp: so sánh, khuếch đại không đảo, mạch đệm và đo hệ số khuếch đại bằng ESP32

Op-amp là gì, hai quy tắc tính mạch, mạch so sánh với quang trở, mạch đệm, khuếch đại không đảo và đảo, giới hạn của LM358 ở 3,3 V và thí nghiệm đo hệ số khuếch đại, bão hòa bằng ESP32.

Hướng dẫn nạp file .bin vào ESP32 bằng Flash Download Tool
Hướng dẫn nạp file .bin vào ESP32 bằng Flash Download Tool

Hướng dẫn lấy đúng file và offset theo từng ESP32, nạp bằng Flash Download Tool, xử lý lỗi boot và xóa flash an toàn.

Đèn trung thu nhấp nháy với ESP32 và pin 18650: dự án STEM cho học sinh
Đèn trung thu nhấp nháy với ESP32 và pin 18650: dự án STEM cho học sinh

Làm đèn ông sao trung thu với ESP32, 3 LED và mô đun pin 18650: 4 hiệu ứng chạy vòng, thở, lung linh, chạm cán đổi hiệu ứng, PWM, cách làm vỏ đèn và an toàn với pin.

Máy khắc laser là gì: laser diode, CO2, fiber khác nhau thế nào, khắc và cắt được vật liệu gì
Máy khắc laser là gì: laser diode, CO2, fiber khác nhau thế nào, khắc và cắt được vật liệu gì

Máy khắc laser hoạt động thế nào, so sánh laser diode, CO2 và fiber theo bước sóng, công suất, vật liệu khắc cắt được, cách lấy nét, đọc công suất quang và chọn máy phù hợp.


Bình luận
Đã thêm vào giỏ hàng