-
-
-
Tổng tiền thanh toán:
-
Xe robot mài nền
17/09/2026
Xe robot mài nền
![]()
![]()
Tôi đề xuất giao diện điện thoại chia thành 2 khung như sau:
thu nhỏ logo khoảng 100×100 px, sau đó nhúng vào main.cpp. Trên web chỉ hiển thị khoảng 55×55 px ở góc trái trên cùng.
Vì logo GPC hiện đã nhúng trong main.cpp, logo WHP cũng nên làm tương tự. Tôi có thể tạo lại nguyên main.cpp hoàn chỉnh có cả 2 logo, bố cục:
┌──────────────────────────────────────┐
│ ┌──────┐ ┌──────┐│
│ │ GPC │ ROBOT CONTROL │ WHP ││
│ └──────┘ └──────┘│
│ │
│ ▲ │
│ TIẾN │
│ │
│ ◀ TRÁI STOP PHẢI ▶ │
│ │
│ ▼ │
│ LÙI │
│ │
│ MANU AUTO │
└──────────────────────────────────────┘
┌───────────────────────────────────┐
│ SETUP │
│ │
│ Chạy lệch trái [ 0 ] │
│ Chạy lệch phải [ 0 ] │
│ Khoảng cách max [ 0 ] │
│ Thời gian làm việc max[ 0 ] │
│ Quay góc trái [ 90 ] │
│ Quay góc phải [ 90 ] │
│ Khoảng cách L1 [ 0 ] │
│ Khoảng cách L2 [ 0 ] │
│ Khoảng cách cảnh báo [ 0 ] │
│ │
│ [ SAVE ] │
└───────────────────────────────────┘
Với chạy lệch trái/phải, tôi đề nghị sau này dùng giá trị % hiệu chỉnh tốc độ 2 bánh. Ví dụ đặt chạy lệch trái = 3 thì khi xe có xu hướng lệch trái, thuật toán có thể bù khoảng 3% cho bên phù hợp. Phần này khi có động cơ thực tế chúng ta sẽ hiệu chỉnh.
Các khoảng cách nên thống nhất cm, góc dùng độ, thời gian làm việc dùng phút. Trên giao diện sẽ ghi rõ đơn vị để không nhầm:
Chạy lệch trái [%]
Chạy lệch phải [%]
Khoảng cách di chuyển [cm]
Thời gian làm việc [phút]
Quay góc trái [°]
Quay góc phải [°]
Khoảng cách L1 [cm]
Khoảng cách L2 [cm]
Khoảng cách cảnh báo [cm]
Tôi cũng sẽ thiết kế ngay từ đầu để MANU cho phép dùng 5 nút Tiến/Lùi/Trái/Phải/STOP; còn AUTO khóa các lệnh chạy tay để tránh xung đột.
Nếu đang nói về robot 2 bánh chạy các đường thẳng song song kiểu máy lau/mài nền của bạn, thì không phải chọn 1 trong 3. Ba loại cảm biến làm ba nhiệm vụ khác nhau, và tốt nhất là phối hợp.
| Cảm biến | Nhiệm vụ chính | Với robot của bạn |
|---|---|---|
| BNO086 | Đo hướng/góc quay của robot | Giữ robot chạy thẳng, quay chính xác 90°/180° |
| Hall/Encoder bánh xe | Đo số vòng bánh → quãng đường, tốc độ | Biết đã chạy 1 m, 5 m, 10 m; điều khiển hai bánh cân nhau |
| LiDAR | Đo khoảng cách tới tường/vật thể, có thể định vị/map | Giữ đường chạy song song, phát hiện vật cản, hiệu chỉnh sai số vị trí |
BNO086 không đo quãng đường bánh xe chính xác; encoder/Hall lại bị sai khi bánh trượt; LiDAR cung cấp thông tin môi trường để hiệu chỉnh vị trí. Vì vậy hệ robot di động chính xác thường fusion nhiều cảm biến, thay vì dựa vào một cảm biến duy nhất.
Với máy của bạn, tôi khuyên dùng cả 3
Kiến trúc sẽ như này:
ROBOT
│
┌────────┼────────┐
↓ ↓ ↓
BNO086 Encoder LiDAR
│ │ │
↓ ↓ ↓
GÓC QUÃNG KHOẢNG CÁCH
HƯỚNG ĐƯỜNG / VỊ TRÍ
│ │ │
└────────┼────────┘
↓
ESP32
↓
Điều khiển 2 motor
Ví dụ robot cần chạy 10 m → dịch ngang 50 cm → quay đầu → chạy ngược lại 10 m:
Encoder/Hall xác định robot đã đi được bao nhiêu mét. BNO086 giữ heading, chẳng hạn đường đi đầu tiên là 0°; nếu lệch thành +1°, ESP32 giảm/tăng tốc hai bánh để kéo về 0°. Đến cuối đường, BNO086 kiểm soát quá trình quay 90° → dịch ngang → quay tiếp 90°. LiDAR đo tường/biên môi trường để kiểm tra robot có thực sự đang chạy song song và hiệu chỉnh sai số tích lũy. Encoder bánh xe vốn có sai số do trượt bánh và sai số kích thước bánh, nên kết hợp IMU và LiDAR sẽ đáng tin cậy hơn.
Nếu muốn làm bản đơn giản trước, tôi sẽ chọn BNO086 + 2 encoder/Hall ở hai bánh. Chưa cần LiDAR. Khi robot đã chạy thẳng và quay đầu ổn định, thêm LiDAR để nâng độ chính xác.
Và lưu ý: Hall ở đây nên hiểu là Hall encoder gắn bánh/motor, chứ không phải một cảm biến Hall đơn lẻ chỉ để phát hiện nam châm.
Với yêu cầu trước đây của bạn là chạy các đường song song cách nhau khoảng 1 thân xe, cấu hình tôi ưu tiên là:
2 encoder bánh + BNO086 + 1 LiDAR phía trước/bên hông.
Nếu bạn cho tôi biết LiDAR bạn định dùng loại 1 điểm (VL53L0X/VL53L1X) hay LiDAR quét 360°, tôi có thể thiết kế luôn thuật toán chạy zíc-zắc phù hợp.
So với các con chúng ta vừa xem
| LiDAR | Công nghệ | Ngoài trời | ESP32 | Nhận xét cho máy của bạn |
|---|---|---|---|---|
| YDLIDAR X2 | Triangulation | ⚠️ | ✅ | Giá rẻ |
| LDROBOT LD14 | Triangulation | ⚠️ | ✅ | Dùng được |
| LDROBOT LD19 | dToF | ✅ khá | ✅ | Rất đáng chọn |
| STL-06NBJ | TOF | ✅ được quảng bá indoor/outdoor | ✅ Serial | Rất đáng xem |
MANU: chỉ khi bấm MANU thì 5 nút TIẾN – LÙI – TRÁI – PHẢI – STOP mới điều khiển robot. Code hiện tại đã gần đúng vì khi autoMode=true, các lệnh điều khiển tay đang bị chặn; riêng STOP vẫn hoạt động.
AUTO: khi bấm AUTO, robot sẽ tự chạy theo các thông số trong SETUP.
chu trình AUTO của robot như sau:
ĐƯỜNG 1
Robot ───────────────────────────────►
│
gặp cuối đường/vật cản
│
quay PHẢI 90°
↓
đi L1
↓
quay PHẢI 90°
│
◄────────────────────────────────────┘
ĐƯỜNG 2
gặp cuối đường/vật cản
│
↓
quay TRÁI 90°
│
đi L2
│
quay TRÁI 90°
│
└────────────────────────────────────►
ĐƯỜNG 3
→ tiếp tục lặp xen kẽ
PHẢI → PHẢI → TRÁI → TRÁI → PHẢI → PHẢI...
MANU: 5 nút TIẾN / LÙI / TRÁI / PHẢI / STOP hoạt động.
AUTO: 4 nút di chuyển tay bị khóa. Robot tự chạy theo chu trình trên. STOP vẫn hoạt động bất kỳ lúc nào và khi STOP sẽ ga = 0 → đóng phanh → thoát AUTO.
Phần SETUP hiện tại có turnAngleLeft, turnAngleRight, distanceL1, distanceL2, warningDistance, maxDistance, maxWorkTime, nên có thể tận dụng trực tiếp.
Để AUTO chạy thực tế chứ không chỉ chạy theo thời gian, tôi sẽ dùng:
Hall motor → xác định đã đi đủ L1/L2 và quãng đường thẳng.
BNO086 → xác định đã quay đúng ±90° và giữ hướng khi chạy thẳng.
LiDAR 360° → xác định cuối đường/vật cản theo warningDistance.
Một điểm rất hay của cách bạn đặt L1/L2 riêng: nếu robot rộng 50 cm nhưng thực tế đường mài chồng mép 5 cm, ta có thể đặt chẳng hạn L1 = L2 = 45 cm, không phải sửa chương trình.
Tôi đã ghép tiếp vào file hiện tại theo đúng phần cứng bạn xác nhận:
- BNO086: I2C
SDA=21,SCL=22. BNO086 hỗ trợ I²C và SparkFun dùng mặc định địa chỉ0x4B; Rotation Vector phù hợp để lấy hướng quay/yaw. - Hall trái: GPIO34.
- Hall phải: GPIO35.
- LDROBOT LD14: TX của LD14 → GPIO16 ESP32, UART 115200, 8N1. LD14 truyền một chiều và tự gửi dữ liệu sau khi hoạt động ổn định.
- Phanh relay: GPIO27 như trước.
- Tay ga trái/phải: GPIO25/26.
- Reverse trái/phải: GPIO32/33.
thêm 2 nút điều khiển để bật máy mài kích dương và máy hút ở 2 góc trái/phải cùng hàng với nút lùi. 2 nút này cũng dùng manu/auto đều điều khiển được. Khi bấm nút stop thì 2 nút này cũng off. Chạy auto sẽ luôn bật 2 nút này.
Đã thêm đúng yêu cầu vào code đang chạy ổn:
- GPIO18 → MÁY MÀI, kích dương
HIGH = ON. - GPIO19 → MÁY HÚT, kích dương
HIGH = ON. - Hai nút nằm cùng hàng với nút LÙI:
MÁY MÀI | LÙI | MÁY HÚT. - Ở MANU: bật/tắt độc lập hai thiết bị.
- Ở AUTO: khi bắt đầu AUTO, máy mài + máy hút tự động ON. Hai nút vẫn có thể điều khiển.
- Bấm STOP ở MANU hoặc AUTO → xe dừng/phanh và MÁY MÀI + MÁY HÚT đều OFF.
- Khi khởi động ESP32, cả hai đầu ra mặc định LOW/OFF.
Khoảng cách di chuyển max: đi thẳng đến tối đa khoảng cách đó thì quay đầu. Thời gian làm việc Max: máy hoạt động đến từng đó thời gian thì stop, chỉ áp dụng khi chạy auto, Hiển thị thời gian làm việc đếm lùi dưới dòng tốc độ.
Đã sửa theo đúng logic bạn yêu cầu:
- Khoảng cách di chuyển MAX: chỉ áp dụng khi AUTO đang chạy thẳng. Ví dụ đặt
1000 cm, xe đi thẳng đủ 10 m thì coi như đến cuối đường và thực hiện chu trình quay đầu giống khi LiDAR phát hiện cuối đường. Sang đường mới, bộ đếm khoảng cách được tính lại từ 0. - Thời gian làm việc MAX: chỉ tính từ lúc bấm AUTO. Hết thời gian → xe STOP + phanh + máy mài OFF + máy hút OFF. MANU không bị giới hạn bởi thời gian này.
- Ngay dưới dòng TỐC ĐỘ đã thêm:
THỜI GIAN LÀM VIỆC: 29:59
và đếm lùi liên tục. Khi không chạy AUTO hiển thị--:--.
chưa lắp cảm biến và bánh xe, khi bấm auto thì thời gian chưa đếm lùi
Đúng. Trường hợp này khả năng cao AUTO thực tế chưa được ESP32 chấp nhận, vì code hiện tại chỉ startAuto() khi bnoReady == true. Bạn chưa lắp BNO086 nên nhấn AUTO bị trả về "BNO086 chưa sẵn sàng", do đó autoStartMs chưa bắt đầu và đồng hồ vẫn --:--.
Tôi sẽ sửa logic để giai đoạn test chưa lắp cảm biến vẫn bấm AUTO và đồng hồ đếm lùi bình thường. Khi lắp cảm biến sau, ta bật lại điều kiện an toàn BNO/Hall.
trong code đã có, chức năng BNO086 đã làm được gì
Trong code hiện tại, BNO086 đã được dùng chủ yếu để đo góc quay của robot, đặc biệt phục vụ việc quay trái/phải chính xác khi chạy AUTO.
Cụ thể nó đang làm các việc sau:
- Đọc góc hướng Yaw của robot liên tục:
bno086.serviceBus();
float yawRad = bno086.getYaw();
currentYawDeg = yawRad * 180.0f / PI;
Ví dụ robot đang hướng 20°, sau khi quay thành 110° → code xác định robot đã quay khoảng 90°.
- Khi AUTO đến cuối đường, code lưu góc hiện tại:
autoTurnStartYaw = currentYawDeg;
Sau đó cho hai bánh quay ngược chiều nhau để robot quay tại chỗ.
- Trong lúc quay, BNO086 liên tục kiểm tra:
fabsf(angleDiff(currentYawDeg, autoTurnStartYaw))
Khi đạt turnAngleRight hoặc turnAngleLeft, ví dụ 90°, code dừng quay. Vì vậy giá trị trong SETUP:
Quay góc trái = 90°Quay góc phải = 90°
được thực hiện dựa vào BNO086, chứ không dựa vào thời gian quay động cơ.
- Nó được dùng cho cả hai lần quay trong một chu kỳ chuyển làn:
quay phải 90° → chạy L1 → quay phải 90°, rồi lần sau quay trái 90° → chạy L2 → quay trái 90°. -
thêm cho chức năng giữ hướng khi chạy thẳng:
Bắt đầu đường → ghi
Yaw mục tiêu→ trong khi chạy liên tục so sánhYaw hiện tạivớiYaw mục tiêu→ lệch trái thì chỉnh tốc độ hai bánh → lệch phải thì chỉnh ngược lại.
Như vậy BNO086 sẽ đảm nhiệm 2 nhiệm vụ: quay đúng góc 90° + giữ đường chạy thẳng, còn Hall đảm nhiệm đo quãng đường MAX/L1/L2, và LD14 đảm nhiệm phát hiện vật cản/cuối đường.
chưa lắp cảm biến và bánh xe, khi bấm auto thì thời gian chưa đếm lùi
Đúng. Trường hợp này khả năng cao AUTO thực tế chưa được ESP32 chấp nhận, vì code hiện tại chỉ startAuto() khi bnoReady == true. Bạn chưa lắp BNO086 nên nhấn AUTO bị trả về "BNO086 chưa sẵn sàng", do đó autoStartMs chưa bắt đầu và đồng hồ vẫn --:--.
Tôi sẽ sửa logic để giai đoạn test chưa lắp cảm biến vẫn bấm AUTO và đồng hồ đếm lùi bình thường. Khi lắp cảm biến sau, ta bật lại điều kiện an toàn BNO/Hall.
Tôi sẽ thêm ngay dưới chữ SETUP hai ô:
SETUP
┌──────────────┐ ┌──────────────┐
│ HALL TRÁI │ │ HALL PHẢI │
│ 0 │ │ 0 │
└──────────────┘ └──────────────┘
Hai giá trị này sẽ được ESP32 đọc liên tục và web tự cập nhật, hoàn toàn độc lập với MANU/AUTO/STOP. Vì vậy kể cả xe dừng, bạn quay bánh bằng tay thì số Hall vẫn thay đổi.
Tuy nhiên cần xác định “số Hall” bạn muốn hiển thị là gì, vì động cơ BLDC Hall thường có 3 dây tín hiệu HA/HB/HC. Có hai cách:
- Bộ đếm xung Hall: hiện tổng số xung của bánh trái và bánh phải. Quay bánh → số tăng liên tục, kể cả quay bằng tay.
- Tốc độ từ Hall: hiện RPM hoặc số xung/giây; khi dừng sẽ về 0.
Sau khi nạp code
Web sẽ hoạt động độc lập như sau:
Hall trái
GPIO34
│
└── RISING
│
▼
hallLeftCount
│
▼
/hall
│
Wi-Fi
│
▼
Điện thoại
│
▼
HALL TRÁI
1256
Hall phải
GPIO35
│
└── RISING
│
▼
hallRightCount
│
▼
/hall
│
▼
HALL PHẢI
1249
Sau đó mới nối Hall qua chia áp:
Hall 4.8V
│
4.7k
│
├──── GPIO25/26
│
10k
│
GND
Như vậy tín hiệu 4,8 V được hạ xuống khoảng 3,27 V.
Bánh còn lại giống hệt với GPIO14:
Thêm tụ 104 chạy ổn luôn nhưng phải lắp chân tụ sát với esp32 xuống GND
Tín hiệu Hall
│
4.7k
│
├──────────── GPIO14
│ │
10k 100nF
│ │
GND GND
Nếu tín hiệu Hall HIGH khoảng 4,8 V, cặp 4.7k + 10k còn có tác dụng chia xuống khoảng:
4.8×104.7+10≈3.27V4.8\times\frac{10}{4.7+10}\approx3.27Vrất phù hợp cho ESP32.
Trường hợp này dùng chế độ WIFI_AP_STA: ESP32 vừa phát Wi-Fi riêng để điện thoại kết nối trực tiếp, vừa kết nối router. Hai cách đều truy cập cùng một giao diện điều khiển robot.
Kết quả sẽ là:
ESP32 ROBOT
/ \
/ \
WiFi AP trực tiếp WiFi Router
ROBOT_ESP32 │
│ │
Điện thoại Điện thoại
│ │
192.168.4.1 192.168.x.xxx
Cách 1 – đứng gần xe, không cần router: điện thoại kết nối:
WiFi: ROBOT_ESP32
Pass: 12345678
rồi mở:
http://192.168.4.1
Cách 2 – qua router: ESP32 và điện thoại cùng kết nối router. Serial Monitor sẽ báo ví dụ:
===== WIFI ROUTER =====
Da ket noi Router!
STA IP: 192.168.0.115
thì điện thoại mở:
http://192.168.0.115
Cả 192.168.4.1 và 192.168.0.115 đều vào cùng một WebServer server(80), nên các chức năng TIẾN/LÙI/TRÁI/PHẢI/STOP, AUTO/MANU, Hall, BNO086, LiDAR... không cần viết lại.
==========================
ESP32 ROBOT
==========================
BNO086: NOT FOUND
LD14: UART 115200 STARTED
===== WIFI AP =====
SSID: ROBOT_ESP32
AP IP: 192.168.4.1
Dang ket noi Router: linhkiendientu
..
===== WIFI ROUTER =====
Da ket noi Router!
STA IP: 192.168.0.123
RSSI: -45 dBm
WEB SERVER STARTED
Nếu mục tiêu là biết bánh đang quay tiến hay lùi, thì mỗi bánh chỉ cần 2 tín hiệu Hall là đủ. Không bắt buộc dùng cả 3 Hall A/B/C của động cơ BLDC.
Và vì bạn vừa phát hiện nhiễu, tôi khuyên mỗi đường Hall đưa vào ESP32 đều gắn tụ 104 (100 nF) như đường hiện tại đã chạy ổn định, đồng thời bảo đảm điện áp HIGH không vượt mức an toàn của GPIO ESP32.
Các GPIO thường dùng tốt cho interrupt gồm GPIO 4, 5, 13, 14, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33, 34, 35, 36, 39.
Với ESP32 DevKit V1:
| GPIO | Dùng Hall | Ghi chú |
|---|---|---|
| 25 | ✅ Rất tốt | Ưu tiên |
| 26 | ✅ Rất tốt | Ưu tiên |
| 27 | ✅ | Dùng được |
| 14 | ✅ | Dùng được nếu đang trống |
| 13 | ✅ | Dùng được |
| 4 | ✅ | Có thể dùng nhưng là chân boot-strapping |
| 16 | ✅ | Dùng được |
| 17 | ✅ | Dùng được- nhiễu |
| 34 | ⚠️ | Chân hiện tại, đang nghi lỗi |
| 35 | ✅ | Dùng được |
| 36 | ⚠️ | Input-only, không pull-down |
| 39 | ⚠️ | Input-only, không pull-down |
4 Hall 13/14/34/35 → quãng đường → STOP lưu vị trí → vẫn tương thích AUTO + BNO086 + web hiện tại.
tạo thêm 4 ô cùng kiểu với HALL TRÁI/HALL PHẢI:
- QUÃNG ĐƯỜNG — cm hoặc m đã di chuyển.
- THỜI GIAN AUTO — thời gian đã hoạt động kể từ lúc bấm AUTO.
- VẬT PHÍA TRƯỚC — khoảng cách từ LiDAR LD14.
- GÓC HƯỚNG — góc từ BNO086.
Như vậy SETUP sẽ thành bố cục:
┌───────────────┐ ┌───────────────┐ │ HALL TRÁI │ │ HALL PHẢI │ │ 125 │ │ 127 │ └───────────────┘ └───────────────┘ ┌───────────────┐ ┌───────────────┐ │ QUÃNG ĐƯỜNG │ │ THỜI GIAN AUTO│ │ 325.4 │ │ 12:35 │ │ cm │ │ đã hoạt động │ └───────────────┘ └───────────────┘ ┌───────────────┐ ┌───────────────┐ │VẬT PHÍA TRƯỚC │ │GÓC HƯỚNG│ │ 86.5 │ │ 2.4° │ │ cm │ │ BNO086 │ └───────────────┘ └───────────────┘
“GÓC HƯỚNG” và dùng Yaw của BNO086.
Quy ước cho robot:
Khởi động / bắt đầu AUTO = 0°
Quay PHẢI = + góc
Quay TRÁI = - góc
0°
↑
│
-90° ← XE → +90°
±180°
↓
Giá trị luôn giới hạn:
-180° ... 0° ... +180°
sửa thêm cho tôi khi chạy thẳng hay lùi thì điều khiển để 2 hall luôn bằng nhau
Quan trọng với AUTO + BNO086
Code của bạn đã có BNO086 giữ hướng khi AUTO chạy thẳng. Không nên để BNO và Hall cùng tự do chỉnh hai motor theo hai thuật toán độc lập, vì chúng có thể “đánh nhau”.
ư
Tôi sẽ tổ chức theo kiểu:
Tốc độ cơ sở
↓
CÂN HALL
giữ 2 bánh đi gần bằng quãng đường
↓
BNO086
hiệu chỉnh nhỏ để robot giữ đúng hướng
↓
Motor trái / Motor phải
Hall đảm nhiệm đồng bộ hai bánh, còn BNO086 đảm nhiệm giữ hướng thực tế.
Với Hall hiện tại chỉ đếm tăng, cách này dùng được cho cả TIẾN và LÙI, vì khi chạy lùi số xung Hall vẫn tăng. Không cần Hall xác định chiều; code đã biết robot đang được lệnh tiến hay lùi.
hướng nhìn của robot:
PHÍA TRƯỚC
180°
↑
TRÁI GIỮA PHẢI
190°-220° 170°-190° 150°-140°
Giữ GIỮA 170°–190°, chỉ mở rộng hai bên thành:
- PHẢI: 140°–170°
- GIỮA: 170°–190°
- TRÁI: 190°–220°
tổng vùng quan sát phía trước là 80°, từ 140° → 220°, tâm vẫn là 180°:
180°
↑
HƯỚNG ROBOT
TRÁI GIỮA PHẢI
190-220 170-190 140-170
30° 20° 30°
Khoảng cách cảnh báo là khoảng cách stop hoạt động của xe đi tiến trong manu và auto. các chức năng đi lùi, rẽ trái, phải vẫn hoạt động được.
Đúng. Ta sửa logic để “Khoảng cách cảnh báo” chỉ khóa chuyển động TIẾN khi LiDAR phát hiện vật cản trong vùng phía trước.
Cụ thể:
TIẾN MANU → gặp vật cản → STOP
TIẾN AUTO → gặp vật cản → STOP / xử lý tránh vật theo AUTO
LÙI → vẫn được phép
RẼ TRÁI → vẫn được phép
RẼ PHẢI → vẫn được phép
STOP → luôn được phép
Thứ tự này là đúng:
LD14
↓
updateLD14()
↓
updateObstacleSafety()
↓
phát hiện <= Khoảng cách cảnh báo
↓
throttleStop()
brakeOn()
-------------------------------------------------
hiện tại mỗi lần chạy, bên phải lệch so với bên trái 4 xung, vài lần chạy thành lệch nhiều, trong setup có ô Chạy lệch trái và Chạy lệch phải , hãy thêm chức năng chạy tiến và lùi được công thêm số xung này trước khi tiến / lùi
Nếu muốn đúng yêu cầu mới, đổi ý nghĩa hai ô thành:
BÙ HALL TRÁI (xung)
BÙ HALL PHẢI (xung)
và giá trị:
Trái = 0
Phải = 4
Trường hợp thực tế của bạn
Nếu sau mỗi lần chạy:
Hall trái tăng: 100
Hall phải tăng: 96
tức bánh phải thường thiếu 4 xung, thì đặt:
BÙ HALL TRÁI = 0
BÙ HALL PHẢI = 4
Hall Sync sẽ nhìn thành:
Trái thực tế: 100 + 0 = 100
Phải thực tế: 96 + 4 = 100
Nhưng có một điểm quan trọng: nếu mục tiêu của bạn là bánh phải thực sự phải chạy thêm 4 xung trước khi kết thúc mỗi đoạn, thì cách cộng vào phép so sánh ở trên lại làm bộ điều khiển coi 96 + 4 = 100 và không bắt bánh phải chạy thêm.
tôi sẽ sửa theo hướng thứ hai: khi bắt đầu TIẾN/LÙI, bánh bị thiếu sẽ được chạy bù 4 xung trước, sau đó mới cho hai bánh chạy đồng thời và Hall Sync từ 0–0. Cách đó phù hợp hơn với hiện tượng lệch tích lũy bạn đang gặp
Sửa motorForward()
Trình tự mới:
Bấm TIẾN
↓
bánh phải chạy trước 4 xung
↓
dừng bánh phải
↓
reset Hall Sync = 0 : 0
↓
2 bánh cùng TIẾN
↓
Hall Sync giữ 2 bánh bằng nhau
-----------------------------------------------
đường kính bánh xe 16cm, 30 xung = 1 vòng, tính khoảng cách cho tôi theo cm
Với bánh xe đường kính 16 cm, 30 xung Hall = 1 vòng:
Chu vi bánh xe:
C=πD=3.1416×16≈50.27 cmC = \pi D = 3.1416 \times 16 \approx 50.27\text{ cm}Vậy 1 xung tương ứng:
50.27/30≈1.676 cm50.27 / 30 \approx \mathbf{1.676\text{ cm}}Công thức tính khoảng cách:
Khoảng caˊch (cm)=Soˆˊ xung×1.676\boxed{\text{Khoảng cách (cm)} = \text{Số xung} \times 1.676}Ví dụ: 30 xung = 50.27 cm, 100 xung ≈ 167.55 cm, 2000 xung ≈ 3351 cm = 33.51 m.
------------------------------------------------
AUTO đang chạy theo kiểu ziczac/lawn-mower, với chu trình như sau.
BẤM AUTO
↓
Bật máy mài + máy hút
↓
TIẾN THẲNG
↓
BNO086 giữ hướng
↓
┌─────────────────────────────┐
│ Có vật cản trong khoảng │
│ cảnh báo LiDAR │
│ HOẶC │
│ đạt Khoảng cách MAX │
└──────────────┬──────────────┘
↓
STOP
↓ 400 ms
QUAY PHẢI 90°
↓
TIẾN L1
↓
QUAY PHẢI 90°
↓
TIẾN THẲNG
↓
gặp cuối đường
↓
QUAY TRÁI 90°
↓
TIẾN L2
↓
QUAY TRÁI 90°
↓
TIẾN THẲNG
↓
lặp PHAI ↔ TRÁI
1. Khi bấm AUTO
startAuto() thực hiện:
autoMode = true;
autoState = AUTO_FORWARD;
autoTurnRight = true;
Sau đó lấy hướng hiện tại của BNO086 làm 0°, reset quãng đường, bật:
accessoriesOn(); // máy mài + máy hút
rồi gọi:
motorForward();
captureAutoHeading();
Nghĩa là lần đầu AUTO luôn bắt đầu bằng đi thẳng, và lần quay đầu tiên là bên phải.
2. Khi chạy thẳng
Ở trạng thái:
AUTO_FORWARD
AUTO liên tục kiểm tra hai điều kiện:
frontObstacle()
hoặc:
roadCm >= maxDistance
Chỉ cần một trong hai xảy ra → xe STOP và chuẩn bị quay.
LiDAR hiện kiểm tra cả 3 vùng TRÁI + GIỮA + PHẢI. Chỉ cần một vùng có vật ở khoảng cách nhỏ hơn:
warningDistance
là được coi là gặp vật cản.
3. BNO086 đang giữ hướng
Trong AUTO_FORWARD và AUTO_SHIFT, code gọi:
updateAutoHeadingHold();
khoảng 25 lần/giây.
Nó so sánh:
currentYawDeg
với:
autoHeadingTargetDeg
rồi tăng/giảm điện áp hai bánh:
leftV = baseV - correction;
rightV = baseV + correction;
Thông số hiện tại:
HEADING_KP = 0.018
HEADING_DEADBAND = 0.8°
HEADING_MAX_CORR_V = 0.45V
Tức BNO086 đang thực sự tham gia chỉnh lệch trái/phải khi chạy thẳng.
4. Khi gặp cuối đường
AUTO STOP trước:
motorStop();
đợi:
400 ms
sau đó quay tại chỗ bằng BNO086.
Lần đầu:
Quay PHẢI → turnAngleRight
mặc định hiện tại là:
turnAngleRight = 90;
Nó không quay theo thời gian mà đo góc BNO:
fabs(angleDiff(...)) >= target
đủ 90° mới dừng.
5. Sau đó chạy L1
Sau lần quay phải thứ nhất:
→ chạy thẳng L1
Mặc định:
distanceL1 = 100 cm
Khoảng cách này được tính bằng Hall:
getShiftDistanceCm()
Khi đạt L1 → STOP → lại quay phải 90°.
Sau đó bắt đầu đường thẳng tiếp theo.
6. Cuối đường tiếp theo đổi sang trái
Sau khi hoàn thành một lượt phải, code:
autoTurnRight = !autoTurnRight;
nên lượt tiếp theo:
Quay TRÁI
→ đi L2
→ quay TRÁI
→ đi thẳng
Sau đó lại đổi thành phải.
Vì vậy đường đi là:
↑ ↑ ↑
│ │ │
│ └─┐
│ │
└─┐ │
│ │
đúng kiểu quét ziczac mặt nền.
7. Thời gian AUTO
Code cũng kiểm tra:
maxWorkTime
mặc định hiện tại:
30 phút
Khi hết thời gian:
stopAuto();
→ dừng xe + tắt máy mài + máy hút.
Trong code hiện tại, nút AUTO bị khóa nếu BNO086 chưa sẵn sàng.
Trong handleMode() đang có:
if(mode=="auto"){
if(!bnoReady){
server.send(503,"text/plain; charset=utf-8","BNO086 chưa sẵn sàng");
return;
}
startAuto();
Serial.println("MODE = AUTO");
}else{
Vì bạn đã tháo/comment BNO nên:
bnoReady = false;
→ chương trình return ngay → startAuto() không chạy → máy mài/hút vẫn OFF → MODE vẫn MANU.
Sửa ngay chỗ này
Thay toàn bộ handleMode() bằng:
void handleMode()
{
String mode = server.arg("mode");
if(mode == "auto")
{
// TAM THOI KHONG KIEM TRA BNO086
// if(!bnoReady){
// server.send(503,"text/plain; charset=utf-8","BNO086 chưa sẵn sàng");
// return;
// }
startAuto();
Serial.println("MODE = AUTO");
}
else
{
stopAuto();
Serial.println("MODE = MANU");
}
server.send(200,"text/plain","OK");
}
Sau sửa, bấm AUTO thì ít nhất Serial phải xuất hiện:
MAY MAI: ON
MAY HUT: ON
AUTO: FORWARD
MODE = AUTO
và web phải chuyển:
MODE = AUTO
MAY MAI: ON
MAY HUT: ON
Nhưng còn một vấn đề tiếp theo
Trong startAuto() vẫn có:
motorForward();
captureAutoHeading();
Tạm thời comment BNO:
motorForward();
// TAM TAT BNO086
// captureAutoHeading();
Serial.println("AUTO: FORWARD");
Và trong updateAuto() còn phần quay 90° dựa vào currentYawDeg. Nếu chỉ sửa handleMode() thì AUTO sẽ bắt đầu chạy được, nhưng đến cuối đường lúc cần quay 90° sẽ không hoạt động đúng vì không có BNO.
---------------------------------------------------
trong setup, Thêm 2 ô nhập đặt dưới Thời gian làm việc MAX, Khoảng cách di chuyển: 15cm và ô Thời gian dừng: 5 giây, Khi bấm auto thì xe tiến 15cm và dừng 5 giây, cứ lặp lại như vậy, các nội dung khác giữ nguyên
Với yêu cầu này, tôi khuyên không sửa cấu trúc AUTO hiện tại, chỉ thêm một cơ chế “tiến ngắt quãng” vào trạng thái chạy thẳng:
AUTO
→ tiến 15 cm
→ STOP 5 giây
→ tiến tiếp 15 cm
→ STOP 5 giây
→ lặp lại...
LiDAR, Hall Sync, khoảng cách MAX, thời gian MAX, L1/L2, máy mài/hút và các chức năng AUTO khác vẫn giữ nguyên.
Thay Cảm biến BNO086 bằng Mpu6050, thay LiDAR bằng cảm biến siêu âm JSN-SR04T
Có thể thay thành:
- BNO086 → MPU6050 để lấy góc hướng/yaw tương đối.
- LD14 → JSN-SR04T để đo một khoảng cách phía trước.
- Giữ nguyên Hall, AUTO ngắt quãng, Web, máy mài/hút.
- Vì JSN-SR04T chỉ đo phía trước, giao diện LiDAR 3 vùng nên đổi thành “CẢM BIẾN TRƯỚC” một giá trị.
Tuy nhiên có một điểm quan trọng: MPU6050 không có từ kế, nên yaw sẽ bị trôi theo thời gian, không ổn định tuyệt đối như BNO086. Với robot của bạn, Hall vẫn nên giữ nhiệm vụ cân hai bánh khi chạy thẳng; MPU6050 chủ yếu dùng để đo góc quay tương đối 90° trong thời gian ngắn.
Đặc biệt không nên để MPU6050 và Hall cùng liên tục sửa DAC khi xe chạy thẳng, vì hai bộ điều khiển có thể “đánh nhau”. Chạy thẳng hiện tại nên để Hall Sync làm chính; MPU6050 dùng cho góc quay.
Tôi có thể sửa trực tiếp toàn bộ file 2745 dòng bạn vừa gửi thành bản MPU6050 + JSN-SR04T, đồng thời đổi giao diện Web từ LiDAR TRÁI/GIỮA/PHẢI thành CẢM BIẾN TRƯỚC, giữ nguyên các phần còn lại
Lưu ý ECHO của JSN-SR04T thường là mức 5 V. Không đưa trực tiếp vào ESP32. Dùng chia áp, ví dụ:
JSN ECHO
|
4.7k
|
+-------- GPIO17 ESP32
|
10k
|
GND
TRIG từ GPIO16 → TRIG JSN có thể điều khiển trực tiếp.
JSN-SR04T ko chạy, tôi thay bằng HC-SR04, sửa lại code cho tôi, có thêm lọc 3–5 lần đo HC-SR04 để robot không STOP nhầm do một giá trị nhiễu đơn lẻ. Tôi khuyên dùng lọc 3 mẫu liên tiếp trước, vì robot cần phản ứng nhanh với vật cản. Với chu kỳ đo 60 ms, 3 mẫu chỉ tạo thêm khoảng 120 ms để xác nhận; 5 mẫu sẽ chậm hơn. Tôi cũng sẽ giữ giá trị khoảng cách HC-SR04 cập nhật bình thường trên Web; chỉ việc quyết định vật cản/STOP mới yêu cầu 3 lần liên tiếp. Cách này phù hợp hơn lấy trung bình 3–5 mẫu, vì lấy trung bình có thể làm vật cản gần bị giá trị xa trước đó kéo lên.
Bản mới:
- HC-SR04 đo mỗi 60 ms.
- Chỉ xác nhận vật cản khi có 3 lần đo liên tiếp nhỏ hơn hoặc bằng
warningDistance. - Một lần đo nhiễu đơn lẻ sẽ không STOP.
- Nếu có một mẫu hợp lệ trở lại vùng an toàn → bộ đếm về
0. - Giá trị khoảng cách trên Web vẫn cập nhật theo từng lần đo.
Tôi sẽ dùng chính code V3.1 trong file anh vừa gửi làm code nền để sửa tiếp. Tôi đã kiểm tra: code đang dùng MPU6050 0x68, SDA GPIO21, SCL GPIO22, I2C 100 kHz Markdown đã dán (1), có calibration ban đầu, lọc gyro, nhận biết STILL, adaptive bias và tính Yaw
Tôi sẽ chuyển thành logic:
ROBOT STOP
↓
bánh thực sự dừng
↓
đợi ổn định
↓
Adaptive Bias = ON
CHẠY THẲNG
↓
Adaptive Bias = OFF
↓
targetYaw cố định
↓
MPU6050 sửa lệch trái/phải
QUAY 90°
↓
Adaptive Bias = OFF
↓
dùng Yaw đo góc quay
QUAY XONG
↓
STOP
↓
Adaptive Bias = ON
↓
ổn định offset
↓
lấy targetYaw mới
Như vậy sẽ giữ được kết quả bù drift rất tốt mà anh vừa test, nhưng tránh trường hợp robot đang quay chậm mà MPU6050 tưởng là đứng yên rồi học mất chuyển động quay.
Anh có thể coi file code vừa gửi là bản MPU6050 chuẩn hiện tại; các bước sửa robot tiếp theo tôi sẽ dựa trực tiếp trên bản này.
Tôi sẽ sửa đúng phần tính Yaw theo hướng:
Gyro Z RAW
↓
trừ Offset
↓
Yaw ← tích phân trực tiếp
│
└── Low-pass → chỉ dùng nhận biết STILL
↓
Adaptive Bias khi đứng yên
Như vậy sẽ tránh việc chuyển động quay chậm bị bộ lọc/deadband làm mất góc. Các phần Web, Hall, AUTO, HC-SR04, BLDC, máy mài, máy hút giữ nguyên.
----------------------------------------
Trong code hiện tại, khi robot chạy thẳng, tôi khuyên phân vai như sau:
Hall = điều khiển chính để 2 bánh chạy đều, còn MPU6050 = giám sát và hiệu chỉnh hướng tổng thể. Hai cái bổ sung cho nhau chứ không thay thế nhau.
Ví dụ robot bắt đầu chạy thẳng tại:
Yaw bắt đầu = 12.0°
Hall trái = 100
Hall phải = 100
Robot ghi lại 12.0° làm hướng mục tiêu. Khi chạy:
Hall trái/phải
↓
cân tốc độ/quãng đường 2 bánh
↓
Robot chạy tương đối thẳng
↓
MPU6050 kiểm tra góc thực tế
↓
Yaw lệch khỏi hướng ban đầu?
↓
hiệu chỉnh nhẹ bánh trái/phải
Hall xử lý sai lệch hai bánh
Code hiện tại đã có Hall Sync. Ví dụ:
Hall trái = 150
Hall phải = 146
→ bánh trái đã đi nhiều hơn → giảm nhẹ bánh trái hoặc tăng bánh phải.
Cái này xử lý rất tốt các nguyên nhân như hai động cơ khác tốc độ, đường kính bánh khác nhau, tải hai bên khác nhau.
Nhưng có trường hợp:
Hall trái = 150
Hall phải = 150
mà robot vẫn lệch hướng, chẳng hạn bánh trượt hoặc mặt nền làm robot xoay. Hall sẽ tưởng robot đang chạy hoàn toàn đúng.
Lúc này MPU6050 phát hiện được.
MPU6050 giữ hướng
Ngay khi bắt đầu chạy thẳng:
-------------------------------
Chế độ manu;
Đã sửa file tổng thể theo đúng logic mới:
- STOP: ga trái/phải = 0 →
REVERSE_LEFT = LOW,REVERSE_RIGHT = LOW→ đóng phanh. - Bấm LÙI: 2 kênh Reverse cùng HIGH, sau đó bấm lùi lần 2 nhả phanh và 2 bánh chạy lùi ngay.
- Bấm TIẾN: 2 kênh Reverse về LOW rồi chạy tiến.
- AUTO vẫn giữ nguyên nguyên lý đã test.
-
sửa ; Bấm PHẢI:
LEFT=HIGH,RIGHT=LOW→ phanh, Bấm PHẢI: → chạy 2 giây → cắt ga → phanh → vẫn giữHIGH/LOW. - TRÁI:
LEFT=LOW,RIGHT=HIGH→ phanh, Bấm TRÁI→ chạy 2 giây → cắt ga → phanh → vẫn giữLOW/HIGH. (trái phải phải bấm 2 lần, lần 1 vào chế độ, lần 2 mới chạy, lần 3 nếu đang trong chế độ thì chạy tiếp, giống chế độ lùi) - Bấm lần tiếp theo sẽ chạy tiếp 2 giây theo chiều đó.
- Bỏ hoàn toàn cơ chế nhấn giữ TRÁI/PHẢI.
- TIẾN, LÙI, STOP và AUTO không thay đổi.
Trong file vừa sửa, thời gian quay 2 giây
const unsigned long TURN_RUN_TIME_MS = 2000;
nằm trong hai hàm motorLeft() và motorRight() ở dòng:
delay(TURN_RUN_TIME_MS);
tôi khuyên tạo một biến ở đầu chương trình:
const unsigned long TURN_RUN_TIME_MS = 2000;
Như vậy sau này muốn đổi thời gian quay chỉ cần sửa một chỗ, ví dụ 1500 = 1,5 giây.
--------------
bổ sung giữ hướng cho cả MANU, nhưng chỉ khi TIẾN hoặc LÙI. Khi người dùng bấm trái/phải thì phải tắt Heading Hold để robot được phép quay tự do
Ví dụ hướng ban đầu 0°, MPU phát hiện +2° thì điều chỉnh nhẹ hai bánh để kéo robot trở về 0°.
Khi STOP → tắt Heading Hold. Khi bấm TIẾN lại → lấy góc hiện tại làm hướng mới. Cách này rất phù hợp cho MANU vì người điều khiển vẫn có toàn quyền chọn hướng, MPU chỉ giúp giữ đường thẳng sau khi đã chọn hướng.
sửa bản code hiện tại để MANU TIẾN/LÙI = Hall Sync + MPU giữ hướng, còn TRÁI/PHẢI = MPU không can thiệp
Tôi kiểm tra code hiện tại thì bảng tốc độ thực tế là:
const float speedVoltage[6] = {
1.20, 1.50, 1.80, 2.10, 2.50, 3.00
};
Ở MANU bây giờ:
- TIẾN/LÙI: Hall Sync + MPU6050 giữ hướng cùng hoạt động.
- Khi bắt đầu TIẾN/LÙI, MPU chốt góc hiện tại làm
manualHeadingTargetDeg. - MPU deadband ±0.5°, hệ số
0.015 V/°, giới hạn hiệu chỉnh ±0.15 V. - TRÁI/PHẢI/STOP: MPU giữ hướng lập tức bị tắt.
- Nếu có chạy bù Hall trước, MPU chỉ chốt hướng sau khi bù Hall xong và cả hai bánh bắt đầu chạy.
- Hall và MPU được cộng thành một correction duy nhất trước khi xuất DAC, tránh hai bộ điều khiển ghi đè lên nhau.
Tôi đã kiểm tra file có 2971 dòng, dấu { } cân bằng.
Khi test MANU, bấm TIẾN bạn sẽ thấy Serial:
MANU HEADING TARGET = xx.xx deg (TIEN)
Sau đó thử tác động nhẹ làm robot lệch trái/phải. MPU phải kéo robot trở lại hướng lúc bắt đầu bấm TIẾN. Nếu thấy nó càng sửa càng lệch, báo tôi ngay; khi đó chỉ cần đảo dấu phần MPU correction, không phải sửa Hall.
Serial sẽ in 4 lần/giây khi MANU TIẾN/LÙI, dạng:
DBG MANU | TIEN | Target=0.00 | Yaw=-3.10 | YawErr=-3.10 |
Hall L=120 R=120 Err=0 |
HallCorr=+0.000V | MPUCorr=-0.047V |
Total=-0.047V | Out L=2.147V R=2.053V
Log này đã chỉ ra khá rõ nguyên nhân: MPU có hoạt động, nhưng Hall Sync đang triệt gần hết tác động của MPU.
Ví dụ tại Yaw = -5.31°:
HallCorr = +0.125 V
MPUCorr = -0.080 V
-------------------
Total = +0.045 V
MPU muốn sửa theo một hướng -0.080 V, nhưng Hall thấy hai bánh lệch 5 xung nên lập tức tạo +0.125 V theo hướng ngược lại. Kết quả MPU không đủ quyền làm hai bánh lệch tốc độ cần thiết để xoay robot trở về 0°.
Đây chính là vấn đề của việc yêu cầu đồng thời:
Cách tôi sẽ sửa
Khi góc gần đúng Hall hoạt động bình thường:
Nhưng khi MPU phát hiện:
YawError = -5.31°
MPU sẽ tạo một Hall offset mục tiêu
nó có thể yêu cầu: L - R = -N xung
để robot thực sự cong trở lại hướng 0°.
Khi: Yaw → 0°
offset này tự giảm về 0 và Hall lại giữ hai bánh cân nhau.
DEBUG theo kiểu MPU đặt mục tiêu chênh lệch Hall, đây là phương án tôi chọn cho robot này.
Nguyên nhân là TargetDiff hiện đang được hiểu như chênh lệch Hall cố định tính từ đầu đoạn chạy. MPU cần một cơ chế tiếp tục tạo độ cong cho đến khi Yaw thực sự quay về mục tiêu, chứ không phải đạt 4 xung rồi hai bánh lại bằng nhau.
sửa TargetDiff thành mục tiêu Hall tích lũy theo sai số góc rồi test lại, cộng dồn đến khi nào Yaw → 0° thì mới dừng
→ bánh phải chạy nhiều hơn bánh trái → robot quay theo chiều ngược lại so với hiện tại.
Quan trọng là chỉ đảo dấu TargetDiff, không đảo HallCorr, không đổi dây Hall, không đổi chiều motor và chưa thay KI.
Chưa chỉnh KI=0.80 và giới hạn 30 xung lúc này. Cho robot chạy thực tế trước. Gửi tôi khoảng 15–30 dòng DBG INTEGRAL từ lúc robot bắt đầu lệch cho tới lúc nó sửa hướng; khi đó tôi sẽ chỉnh KI, deadband và giới hạn TargetDiff để robot sửa hướng êm, không zíc-zắc.
Chạy đã chuẩn
------------------------------
Chạy Auto;
Luồng AUTO hiện tại về cơ bản là:
Bấm AUTO
↓
Lấy góc hiện tại làm hướng gốc
↓
Bật máy mài + máy hút
↓
TIẾN
↓
15 cm → DỪNG 5 giây → TIẾN 15 cm → DỪNG 5 giây → ...
↓
Đến khoảng cách MAX hoặc gặp vật cản
↓
DỪNG
↓
QUAY PHẢI theo góc cài đặt (~90°)
↓
TIẾN L1
↓
QUAY PHẢI ~90°
↓
TIẾN theo đường kế tiếp
↓
Đến cuối đường
↓
QUAY TRÁI ~90°
↓
TIẾN L2
↓
QUAY TRÁI ~90°
↓
Lặp PHẢI → TRÁI → PHẢI → TRÁI...
Code hiện có state AUTO_FORWARD, dừng trước khi quay, AUTO_TURN_1, AUTO_SHIFT, AUTO_TURN_2; sau mỗi đường nó đảo autoTurnRight để lần tiếp theo chuyển từ phải sang trái hoặc ngược lại. Góc quay được xác định bằng MPU6050 theo chênh lệch yaw tương đối. Văn bản đã dán (1)
Có thêm hai giới hạn AUTO trên giao diện: Khoảng cách di chuyển MAX và Thời gian làm việc MAX; cùng các tham số góc trái/phải, L1/L2, khoảng cách mỗi bước và thời gian dừng. Khi hết thời gian làm việc, AUTO gọi stopAuto(), dừng motor và tắt phụ tải.
Nhưng có một điểm cần sửa trước khi test AUTO
Phần giữ hướng MPU + Hall tích lũy mà chúng ta vừa làm chuẩn hiện chỉ áp dụng cho MANU. Bản logic trước có điều kiện kiểu:
if(!autoMode && manualHeadingActive && mpuReady)
nên khi chuyển sang:
AUTO
cơ chế mới vừa test thành công không tự động được sử dụng cho đoạn AUTO_FORWARD.
Tôi đề nghị bước tiếp theo không thay đổi đường đi AUTO. Chỉ đưa bộ điều khiển vừa test chuẩn:
MPU6050
↓
Yaw error
↓
TargetDiff tích lũy
↓
Hall Sync
↓
L/R
vào cả các đoạn AUTO chạy thẳng.
Còn lúc AUTO_TURN_1 và AUTO_TURN_2 thì tắt giữ hướng thẳng, MPU chỉ dùng để đo góc quay. Sau khi quay xong và bắt đầu đoạn thẳng mới, lấy góc MPU lúc đó làm TargetYaw mới rồi kích hoạt lại MPU + Hall giữ hướng.
đưa bộ điều khiển vừa test chuẩn vào cả các đoạn AUTO chạy thẳng , Còn lúc AUTO_TURN_1 và AUTO_TURN_2 thì tắt giữ hướng thẳng, MPU chỉ dùng để đo góc quay. Sau khi quay xong và bắt đầu đoạn thẳng mới, lấy góc MPU lúc đó làm TargetYaw mới rồi kích hoạt lại MPU + Hall giữ hướng.
Đã sửa xong bản AUTO theo đúng yêu cầu và giữ nguyên bộ điều khiển MANU vừa test chuẩn.
Trong bản này:
AUTO_FORWARD: dùng MPU → TargetDiff tích lũy → Hall Sync.- Sau mỗi lần dừng 5 giây, khi chạy tiếp sẽ chốt Yaw hiện tại làm TargetYaw mới.
AUTO_TURN_1: tắt giữ hướng thẳng; MPU chỉ đo góc quay.- Sau TURN1, khi chạy
AUTO_SHIFTL1/L2: chốt Yaw mới và bật lại giữ hướng. - Trước
AUTO_TURN_2: lại tắt giữ hướng. - Sau TURN2: chạy đường mới → chốt Yaw mới và bật lại giữ hướng.
- Nếu có chạy bù Hall trước, TargetYaw chỉ được chốt sau khi bù xong và cả hai bánh bắt đầu chạy.
- Không dùng lại thuật toán
updateAutoHeadingHold()cũ.
DEBUG giờ phân biệt rõ:
File đã kiểm tra 3042 dòng, ngoặc {} cân bằng 230/230.
Khi test AUTO lần đầu, tôi khuyên theo dõi Serial ở đoạn chạy thẳng → TURN1 → L1/L2 → TURN2 → chạy thẳng mới. Nếu gửi log đó cho tôi, tôi sẽ kiểm tra toàn bộ chu trình AUTO và góc quay 90° cho bạn.
----------------------sửa auto chạy thẳng
Vì MANU hiện đã chạy chuẩn, phương án an toàn nhất là tôi sửa AUTO_FORWARD và AUTO_SHIFT dùng chính xác bộ điều khiển chạy thẳng của MANU, nhưng bỏ Hall pre-compensation riêng trong AUTO. Phần quay AUTO, 5 cm/dừng 5 giây, STOP, TIẾN/LÙI, TRÁI/PHẢI giữ nguyên.
Trong code gốc, motorForward() có cơ chế gọi startHallCompensation(false), tức có thể cho một bánh chạy bù trước rồi mới cho hai bánh chạy chung. Đây chính là phần chúng ta cần loại khỏi AUTO. Văn bản đã dán (1)
Tôi sửa thành:
- AUTO_FORWARD: bỏ Hall pre-compensation một bánh.
- AUTO_SHIFT L1/L2: cũng bỏ Hall pre-compensation.
- Mỗi lần AUTO chạy lại sau 5 giây: cũng bỏ pre-compensation.
- Hai bánh bắt đầu chạy cùng lúc → MPU +
TargetDifftích lũy + Hall Sync cân hai bánh. - MANU giữ nguyên cơ chế hiện tại.
- LÙI, STOP, TRÁI/PHẢI, quay AUTO và các chức năng khác không sửa.
- Dấu hiệu chỉnh góc vừa sửa ở phiên bản trước vẫn được giữ.
Tôi đã kiểm tra có 4 vị trí motorForward() thuộc AUTO được chuyển sang chế độ bỏ pre-compensation. Ngoặc code cân bằng 232/232.
Khi test lại, quan trọng nhất là log sau mỗi lần bắt đầu AUTO. Hai Hall không nhất thiết bằng tuyệt đối, nhưng không được còn tình trạng kiểu L +0 / R +33 do chạy bù một bánh trước.
Cách mới hoạt động như sau:
Bước 5 cm đầu:
1.800V / 1.800V
→ phát hiện bánh phải nhanh
→ Hall Sync cân lại
→ ghi nhớ mức bù
Dừng 5 giây
Bước 5 cm tiếp:
áp dụng mức bù đã học NGAY khi khởi động
→ bánh trái được tăng
→ bánh phải được giảm
→ Hall Sync tiếp tục tinh chỉnh
→ cập nhật mức bù cho bước sau
Hướng xử lý
LẦN N
Dừng
↓
Khởi động CẢ 2 bánh bằng dòng/điện áp đủ lớn
↓
Chạy 5 cm
↓
Đo:
- Hall trái
- Hall phải
- Góc MPU thay đổi
↓
Dừng 5 giây
↓
Tính mức bù cho LẦN N+1
↓
LẦN N+1 khởi động ngay với mức bù mới
Tôi còn đề nghị một thay đổi quan trọng: không capture lại TargetYaw sau mỗi lần dừng 5 giây. Giữ nguyên góc chuẩn của cả đường thẳng. Nếu không, MPU sẽ coi góc lệch mới là góc chuẩn và không thể sửa sai số tích lũy.
Chu trình mới:
LẦN N
↓
Khởi động bằng tốc độ đang chọn trên Web
↓
Chạy 5 cm
↓
Đo:
Hall trái
Hall phải
Góc MPU so với TargetYaw
↓
Tính sai Hall
↓
Dừng 5 giây
↓
Tích lũy mức bù Hall
↓
LẦN N+1
khởi động NGAY với:
L = tốc độ Web - HallNext
R = tốc độ Web + HallNext
Nguyên lý mới là:
Bước N chạy
↓
Đo dL, dR
↓
StepDiff → cân tốc độ 2 bánh
+
TotalDiff → kéo vị trí tích lũy về 0
↓
Nếu |TotalDiff| > 10
→ bắt đầu can thiệp sớm
Nếu |TotalDiff| > 20
→ tăng mạnh mức kéo về
↓
Giới hạn mỗi lần chỉnh ±0.20V
↓
Bước N+1 áp dụng ngay
Tôi đề xuất bảng bù startup như sau:
|StepDiff| thay đổi bù cho lượt sau
0–1 Hall 0.00V
2–3 Hall 0.02V
4–5 Hall 0.04V
6–8 Hall 0.08V
9–12 Hall 0.15V
13–20 Hall 0.25V
>20 Hall 0.40V MAX
Vì lực khởi động của 2 bánh ko bằng nhau, khoảng thời gian quá ngắn đề chạy bù nên dù 1 cái 2.9 và 1 cái 1.2 vẫn ko bù nổi.
Đã sửa theo phương án vừa thống nhất:
Bản này:
- AUTO lần đầu: trái 2.90V – phải 1.20V.
- Dải AUTO: 1.20–2.90V.
- Chỉ cần mỗi bánh ≥ 5 Hall để kết thúc lượt học.
- Lượt sau học theo
StepDiff = dL-dR, không dùngTotalDiff. - Lệch lớn bù nhanh tối đa 0.40V/lượt, gần cân giảm xuống
0.15 → 0.08 → 0.04 → 0.02V. - Hall Sync tức thời vẫn hoạt động trong lúc chạy.
- Dừng 5 giây vẫn giữ nguyên.
khởi động 2.26V trái / 1.34V phải luôn cho tôi
Với AUTO mới, tôi sẽ đổi logic như sau:
- Bù bên trái trên Web: đổi từ số xung Hall → điện áp cộng thêm cho động cơ trái, nhập 1 chữ số thập phân, ví dụ
0.5 V. - Bù bên phải: tương tự, cộng điện áp cho động cơ phải.
- Điện áp AUTO:
V_trái = tốc độ Web + Bù trái
vàV_phải = tốc độ Web + Bù phải. - Khoảng cách di chuyển: mỗi lần AUTO tiến đúng số cm nhập trong ô Khoảng cách di chuyển trên Web, không cố định 10 cm nữa.
- Thời gian dừng: dừng đúng số giây nhập trong ô Thời gian dừng trên Web, không cố định 5 giây nữa.
- Lặp
tiến → dừng → tiến → dừng...cho đến khi tổng quãng đường đạt Khoảng cách di chuyển MAX. - AUTO không dùng hai ô bù này để bù Hall nữa. MANU và các chức năng khác giữ nguyên.
- Hai ô Bù bên trái / Bù bên phải sẽ cho phép nhập từ -3.0V đến +3.0V, bước
0.1V -
Điện áp trái = Tốc độ Web + Bù bên trái Điện áp phải = Tốc độ Web + Bù bên phải Bù trái/phải: -3.0V → +3.0V Bước điều chỉnh: 0.1V
Đã sửa đúng 2 ô:
- Bù bên trái:
-3.00 → +3.00 V, bước0.01V - Bù bên phải:
-3.00 → +3.00 V, bước0.01V
Ví dụ có thể nhập +0.35V, -0.12V, +1.27V.
Quy trình AUTO mới là:
Tiến theo khoảng cách Web → STOP → kiểm tra góc MPU → nếu lệch ≤ ±0.5° thì bỏ qua; nếu lệch > ±0.5° thì hai bánh quay ngược chiều để cân về góc ban đầu → khi đạt ±0.5° mới bắt đầu đếm thời gian dừng Web → hết thời gian → chạy đoạn tiếp theo.
Góc chuẩn lúc bấm AUTO = 12.30°
Sau khi chạy:
12.65° → lệch +0.35° → bỏ qua
13.10° → lệch +0.80° → cân lại
11.50° → lệch -0.80° → cân lại
Khi cân, mục tiêu luôn là trở về:
12.30° ± 0.5°
chứ không lấy lại góc mới sau mỗi lần chạy.
Tôi thấy cách này phù hợp với mục tiêu giữ robot đi thẳng theo một hướng cố định ban đầu. Nếu robot chạy 100 chu kỳ thì cả 100 chu kỳ đều tham chiếu cùng một góc lúc bấm AUTO.
Đã sửa trực tiếp trên bản hiện tại và giữ nguyên AUTO cân góc, bù điện áp, MANU và các chức năng khác.
Bản mới có 2 HC-SR04 đặt cùng một hàng trên Web: bên trái dùng TRIG GPIO16 / ECHO GPIO17, bên phải dùng TRIG GPIO4 / ECHO GPIO5. Hai cảm biến được đọc xen kẽ để hạn chế nhiễu chéo. Chỉ cần một trong hai phát hiện vật cản nhỏ hơn hoặc bằng Khoảng cách cảnh báo đủ 3 lần liên tiếp thì chức năng an toàn sẽ STOP xe khi đang tiến.
Nút SAVE SETUP đã được đưa lên ngay phía trên dòng Bù bên trái. Khi SAVE, toàn bộ thông số Setup được lưu vào NVS/Preferences của ESP32, nên reset hoặc mất nguồn rồi bật lại vẫn giữ: Bù trái/phải, khoảng cách MAX, thời gian MAX, khoảng cách mỗi lần chạy, thời gian dừng, góc quay trái/phải, L1/L2 và khoảng cách cảnh báo.
Lưu ý chân ECHO của cả hai HC-SR04 là 5V, vẫn cần chia áp xuống khoảng 3.3V trước khi vào ESP32.
Thêm ô độ nghiêng và lấy giá trị cao nhất của Roll, Pitch vào chung 1 ô, đặt bên cạnh ô góc hướng, thêm dưới Khoảng cách cảnh báo là Độ nghiêng cảnh báo tính theo độ. Nếu độ nghiêng trên độ nghiêng cảnh báo thì stop tất cả
Đã giữ nguyên bản đang chạy ổn và bổ sung đúng phần độ nghiêng:
- Thêm ô ĐỘ NGHIÊNG ngay bên cạnh GÓC HƯỚNG.
- Giá trị hiển thị là
MAX(|Roll|, |Pitch|). - Thêm Độ nghiêng cảnh báo (độ) ngay dưới Khoảng cách cảnh báo.
- Giá trị này được SAVE vào NVS, reset/mất điện không mất.
- Nếu độ nghiêng vượt ngưỡng: STOP động cơ + dừng AUTO + tắt máy mài + máy hút.
- Có hysteresis
0.5°để tránh trạng thái cảnh báo rung liên tục quanh ngưỡng. - Đặt
Độ nghiêng cảnh báo = 0thì chức năng này được tắt.
Ví dụ Roll 4.2°, Pitch 7.5° → Web hiển thị Độ nghiêng = 7.5°. Nếu cảnh báo đặt 6° → STOP tất cả.
-------------------------------------------------
Điện áp kích động cơ đang có các trường hợp sau:
| Chế độ | Điện áp cơ sở | Điều chỉnh | Min thực tế | Max thực tế |
|---|---|---|---|---|
| MANU TIẾN | Theo tốc độ Web: 1.2–3.0V | Hall + MPU, tối đa ±0.40V | 0V | 3.3V |
| MANU LÙI | Theo tốc độ Web: 1.2–3.0V | Hall + MPU, tối đa ±0.40V | 0V | 3.3V |
| AUTO chạy thẳng | Theo tốc độ Web: 1.2–3.0V | Bù trái / Bù phải | 0V | 3.3V |
| AUTO cân lại góc | Tăng dần từ 0V đến tốc độ Web | Bù trái / Bù phải | 0V | 3.3V |
MANU TIẾN và LÙI
Mức tốc độ Web:
const float speedVoltage[6] =
{
1.20,
1.50,
1.80,
2.10,
2.50,
3.00
};
MANU TIẾN và LÙI Hall/MPU có thể hiệu chỉnh tối đa: HALL_SYNC_MAX_CORR = 0.40V; theo cơ chế như nào
hiện tại MPU phát hiện robot lệch hướng thì yêu cầu cộng dồn dần hall lên (bản 6)
4. ±0.40V được đưa vào hai bánh như thế nào?
Code hiện tại:
leftVoltage = baseVoltage - hallCorrection;
rightVoltage = baseVoltage + hallCorrection;
Ví dụ tốc độ đang đặt:
Base = 1.50V
Nếu:
HallCorr = +0.20V
thì:
TRÁI = 1.50 - 0.20 = 1.30V
PHẢI = 1.50 + 0.20 = 1.70V
Nếu đạt giới hạn tối đa +0.40V:
TRÁI = 1.10V
PHẢI = 1.90V
Nếu HallCorr = -0.40V:
TRÁI = 1.90V
PHẢI = 1.10V
Như vậy ±0.40V là mức hiệu chỉnh mỗi bánh, nên chênh lệch điện áp giữa hai bánh có thể lên tới:
0.40 + 0.40 = 0.80V.
Chuỗi điều khiển hiện tại
MPU6050
│
▼
Sai góc Yaw
│
▼
Tạo TargetDiff Hall
│
▼
Hall trái ─── Hall phải
│
▼
ActualDiff - TargetDiff
│
▼
× 0.025 V/xung
│
▼
giới hạn ±0.40V
│
┌────┴────┐
▼ ▼
Trái -Corr Phải +Corr
Điểm quan trọng là 0.40V chỉ là trần. Bình thường xe lệch ít thì có thể chỉ sửa 0.025V, 0.05V, 0.10V... Chỉ khi sai Hall đủ lớn mới chạm ±0.40V.
Với hiện tượng anh nói MANU lùi lâu thì lệch nhiều, tôi nghi cần xem chính phần MPU → TargetDiff khi LÙI, chứ chưa nên tăng 0.40V. Vì nếu dấu bù hoặc tốc độ tích lũy chưa đúng thì tăng lên 0.6–0.8V còn có thể làm lệch nhanh hơn.
const float MANUAL_HALL_DIFF_MAX_PULSE = 100.0f; // anti-windup: gioi han target tich luy
Cơ chế mới của MANU TIẾN/LÙI:
Base trái = Tốc độ Web + Bù bên trái
Base phải = Tốc độ Web + Bù bên phải
↓
MPU → TargetDiff
↓
Hall Correction
↓
Out trái = Base trái - HallCorrection
Out phải = Base phải + HallCorrection
Đã sửa theo đúng yêu cầu:
Tilt > giới hạnphải liên tục đủ 500 ms mới STOP.- Nếu Tilt tụt xuống dưới giới hạn trước 500 ms → bộ đếm hủy và tính lại từ đầu.
- Khi TILT STOP xảy ra, chương trình lưu lại chính giá trị Tilt gây STOP.
- Trên Web, dưới ĐỘ NGHIÊNG sẽ có thêm:
TILT gây STOP: xx.x° - Giá trị này được giữ lại kể cả sau khi MPU trở về góc bình thường.
- Serial sẽ báo dạng: