Xe robot mài nền

17/09/2026
xe-robot-mai-nen

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:

  1. Đọ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°.

  1. 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ỗ.

  1. 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ơ.

  1. 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°.
  2. 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ánh Yaw hiện tại với Yaw 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.27V

rấ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_SHIFT L1/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 + TargetDiff tí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ùng TotalDiff.
  • 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ước 0.01V
  • Bù bên phải: -3.00 → +3.00 V, bước 0.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 = 0 thì 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ạn phả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:
Bình luận
Nội dung này chưa có bình luận, hãy gửi bình luận đầu tiên của bạn.
VIẾT BÌNH LUẬN CỦA BẠN