Debug bằng Serial Monitor - kỹ năng tìm lỗi robot quan trọng số 1

Khai thác Serial Monitor và Serial Plotter tìm lỗi robot có hệ thống - in đúng chỗ, định dạng dễ đọc, đo thời gian vòng lặp và quy trình khoanh vùng lỗi. Trong bài viết này, chúng ta sẽ cùng tìm hiểu chi tiết và ứng dụng thực tế trong robot.
Robot không có màn hình báo lỗi
Chương trình máy tính lỗi thì hiện thông báo; robot lỗi thì... đứng im, hoặc quay vòng tròn, hoặc lao vào tường — không một lời giải thích. Serial Monitor là cách robot "nói" cho bạn biết chuyện gì đang xảy ra bên trong: giá trị cảm biến thực, nhánh code nào đang chạy, biến nào mang giá trị bất thường.
Người mới sửa lỗi bằng cách nhìn robot và đoán; người có nghề bắt robot khai báo bằng Serial rồi đọc lời khai. Khác biệt tốc độ giữa hai cách là 10 lần.
Nền tảng trong 2 phút
void setup() {
Serial.begin(115200); // tốc độ chuẩn cho ESP32
Serial.println("Khoi dong xong!");
}
void loop() {
long d = readDistanceCm();
Serial.print("Khoang cach: "); // print - KHÔNG xuống dòng
Serial.println(d); // println - CÓ xuống dòng
delay(200);
}Mở Monitor: Tools - Serial Monitor (hoặc icon kính lúp), chọn baud 115200 khớp với code — lệch baud là màn hình đầy ký tự loạn. Số hiện đều đặn nghĩa là kênh liên lạc đã thông.
In nhiều giá trị một dòng cho dễ đọc:
Serial.printf("L:%d C:%d R:%d | pos:%d out:%.2f\n",
left, center, right, position, output);
// ESP32 hỗ trợ printf - gọn hơn chuỗi print nối đuôiQuy trình debug 4 bước - áp dụng cho mọi lỗi
Bước 1: Mô tả lỗi thành câu cụ thể
"Robot bị ngu" không sửa được; "robot rẽ trái ngay cả khi đường thẳng" mới sửa được. Câu mô tả tốt chứa: làm gì, mong đợi gì, thực tế gì, tần suất (luôn luôn hay thỉnh thoảng?).
Bước 2: Khoanh vùng bằng nguyên tắc chia đôi
Chuỗi xử lý của robot: cảm biến → đọc giá trị → tính toán → lệnh motor → chuyển động. Lỗi nằm đâu đó trên chuỗi — in giá trị ở ĐIỂM GIỮA trước:
Serial.printf("raw:%d -> position:%d\n", rawSensor, position);Giá trị giữa chuỗi đúng → lỗi nửa sau (tính toán/motor); sai → lỗi nửa trước (phần cứng/đọc). Lặp lại chia đôi ở nửa nghi vấn — 3-4 lần chia là trúng ổ, kể cả chương trình 500 dòng.
Bước 3: Bắt quả tang bằng log có điều kiện
Lỗi "thỉnh thoảng" là loại khó nhất — đừng in tất cả (trôi màn hình), chỉ in khi bất thường:
if (d > 400 || d <= 0) {
Serial.printf("!!! Gia tri la: %ld tai t=%lu\n", d, millis());
}Chạy robot 5 phút rồi đọc lại log: bất thường xuất hiện theo quy luật gì (mỗi lần motor khởi động? mỗi 32 giây?) — quy luật chính là chữ ký của thủ phạm.
Bước 4: Sửa MỘT thứ, thử lại, lặp
Sửa 3 thứ cùng lúc mà hết lỗi thì không biết thứ nào ăn tiền — và có thể vừa cấy 2 lỗi mới. Kỷ luật một-thay-đổi-một-lần chậm mà nhanh.
Serial Plotter - đồ thị thời gian thực miễn phí
Tools - Serial Plotter biến dòng số thành đồ thị chạy. Chỉ cần in số thuần, nhiều kênh cách nhau bằng dấu phẩy hoặc tab kèm nhãn:
Serial.printf("position:%d,output:%.1f\n", position, output);Ứng dụng đắt giá nhất: chỉnh PID bằng mắt — dao động, độ trễ, quá đà hiện rõ trên đồ thị thay vì đoán qua dáng xe chạy (phối hợp với quy trình trong bài Tinh chỉnh PID ở mục Kiến thức). Cũng tuyệt cho: soi nhiễu cảm biến (đường gai góc = cần lọc), xem đáp ứng lọc trung bình trượt, kiểm tra tốc độ hai bánh có khớp nhau.
Ba kỹ thuật nâng tầm
Đo thời gian vòng lặp - sát thủ thầm lặng
Vòng loop chậm làm PID ì, robot phản ứng trễ. Đo ngay:
void loop() {
unsigned long t0 = micros();
// ... toàn bộ việc của loop ...
static int n = 0;
if (++n >= 500) { // in mỗi 500 vòng - không tự làm chậm mình
Serial.printf("loop: %lu us\n", micros() - t0);
n = 0;
}
}Trên 5.000 µs (200 Hz) cho robot dò line là đáng soi: thủ phạm quen thuộc là delay() sót lại và Serial.print mỗi vòng.
Log theo cấp độ - tắt bật không xóa code
#define DEBUG 1 // đổi 0 khi thi đấu
#if DEBUG
#define LOG(...) Serial.printf(__VA_ARGS__)
#else
#define LOG(...) // biến mất khỏi bản dịch
#endif
LOG("state=%d d=%ld\n", state, d); // dùng thoải máiTrước giờ thi chỉnh DEBUG 0: mọi log biến mất, loop nhanh tối đa, không phải xóa tay từng dòng rồi tiếc.
Nói chuyện hai chiều - gõ lệnh xuống robot
Serial nhận được cả chiều xuống — biến Monitor thành bàn điều khiển:
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c == 'p') Kp += 0.01; // chỉnh PID không cần nạp lại
if (c == 'o') Kp -= 0.01;
if (c == 's') Serial.printf("Kp=%.3f Kd=%.3f\n", Kp, Kd);
}
// ...
}Mỗi lần nạp code mất 30 giây; gõ một phím mất 1 giây — buổi chỉnh PID 2 tiếng co lại còn 20 phút.
Khi robot chạy rời máy tính thì debug kiểu gì?
Serial cần cáp USB — robot đang chạy trên sàn thì sao?
- LED nháy mã: 2 nháy = mất vạch, 3 nháy = pin yếu — thô sơ mà cứu nguy
- Bluetooth Serial: ESP32 phát BluetoothSerial, điện thoại cài app serial terminal — Monitor không dây trong tầm 10 m, gần như miễn phí về công sức
- WebSerial/WiFi log: xem log qua trình duyệt — một lợi ích phụ của các dự án trong bài WiFi web server ở mục Kiến thức
- Ghi thẻ SD: log ra file cho phân tích sau — chuẩn cho nghiên cứu KHKT
Câu hỏi thường gặp
Vì sao Serial Monitor toàn ký tự ô vuông loạn xạ?
Baud không khớp — 99% trường hợp. Code Serial.begin(115200) thì góc dưới Monitor phải chọn đúng 115200. Vài ký tự loạn CHỈ ngay lúc reset là bình thường (log bootloader chạy baud khác), sau đó phải sạch.
Serial.print có làm robot chạy khác đi không?
Có — đây là bẫy tinh vi: mỗi println tốn thời gian (và chặn khi buffer đầy), in dày làm loop chậm, PID đổi hành vi. Triệu chứng nhận biết: "cứ thêm dòng in để soi lỗi thì lỗi... đổi kiểu". Đối sách: in thưa (mỗi N vòng), dùng cấp độ log tắt được, và đo thời gian loop như kỹ thuật ở trên.
In số float bị cụt số lẻ?
Serial.println(3.14159) mặc định in 2 chữ số lẻ. Thêm tham số: Serial.println(x, 4) in 4 chữ số, hoặc printf với %.4f.
Không có lỗi biên dịch nghĩa là code đúng?
Biên dịch chỉ bắt lỗi cú pháp — "câu văn đúng ngữ pháp" vẫn có thể "nói điều vô nghĩa". Lỗi logic (nhầm dấu, nhầm chân, thứ tự điều kiện sai) chỉ lộ khi chạy, và Serial Monitor chính là kính hiển vi soi chúng. Đó là lý do kỹ năng bài này đứng số 1.
Tài nguyên tải về
Tải bản PDF của bài viết để in giáo án hoặc gửi trước cho học viên.



