356 lines
10 KiB
Markdown
356 lines
10 KiB
Markdown
# WAVE_ROVER Firmware
|
|
|
|
ESP32 firmware for the Waveshare `WAVE_ROVER` platform.
|
|
|
|
This repository tracks the `V1.0` source tree and is the main place for future versioning, fixes, and feature work.
|
|
|
|
## Current State
|
|
|
|
- Base firmware updated from the local `V0.9` source tree toward the observed `0.95` factory behavior
|
|
- Internal firmware version set to `1.00`
|
|
- IMU stack reworked for better stability
|
|
- Web UI updated
|
|
- Persistent magnetometer calibration added
|
|
|
|
## Main Changes In V1.0
|
|
|
|
- Fixed several IMU/AHRS bugs in the quaternion filter
|
|
- Hardened QMI8658 and AK09918 I2C reads
|
|
- Added proper IMU temperature reporting
|
|
- Added working IMU offset get/set commands
|
|
- Added runtime magnetometer calibration with flash persistence
|
|
- Added automatic reload of saved mag offsets on boot
|
|
- Added IMU calibration state flags to feedback JSON
|
|
|
|
## Repository Layout
|
|
|
|
- `WAVE_ROVER.ino`
|
|
Main Arduino sketch
|
|
- `IMU.cpp`, `IMU.h`, `IMU_ctrl.h`
|
|
IMU fusion, calibration, and command handling
|
|
- `QMI8658.cpp`, `QMI8658.h`
|
|
6-axis accelerometer/gyro driver
|
|
- `AK09918.cpp`, `AK09918.h`
|
|
Magnetometer driver
|
|
- `web_page.h`
|
|
Built-in web UI and JSON helper panel
|
|
- `data/`
|
|
Example LittleFS content such as `devConfig.json` and `wifiConfig.json`
|
|
|
|
## Build Requirements
|
|
|
|
Recommended setup:
|
|
|
|
- `Arduino IDE 2.x`
|
|
- `ESP32` board support by Espressif
|
|
- Board target: `ESP32 Dev Module`
|
|
|
|
ESP32 board manager URL:
|
|
|
|
- `https://espressif.github.io/arduino-esp32/package_esp32_index.json`
|
|
|
|
Libraries used by this project:
|
|
|
|
- `ArduinoJson`
|
|
- `SCServo`
|
|
- `Adafruit SSD1306`
|
|
- `INA219_WE`
|
|
- `ESP32Encoder`
|
|
- `PID_v2`
|
|
- `SimpleKalmanFilter`
|
|
- `Adafruit ICM20X`
|
|
- `Adafruit ICM20948`
|
|
- `Adafruit Unified Sensor`
|
|
|
|
Provided by the ESP32 core and normally not installed separately:
|
|
|
|
- `WiFi`
|
|
- `WebServer`
|
|
- `LittleFS`
|
|
- `esp_now`
|
|
- `nvs_flash`
|
|
- `esp_system`
|
|
|
|
## Build And Upload
|
|
|
|
### Arduino IDE
|
|
|
|
1. Install Arduino IDE 2.x.
|
|
2. Add the ESP32 board manager URL in Arduino IDE preferences.
|
|
3. Install `esp32` via Boards Manager.
|
|
4. Install the libraries listed above with Library Manager.
|
|
5. Open `WAVE_ROVER.ino`.
|
|
6. Select `ESP32 Dev Module`.
|
|
7. Select the correct serial port.
|
|
8. Upload the sketch.
|
|
|
|
### LittleFS
|
|
|
|
The firmware uses `LittleFS`.
|
|
|
|
- `imuConfig.json` is created automatically by the firmware when magnetometer offsets are saved
|
|
- `data/devConfig.json` and `data/wifiConfig.json` are example files in the repo
|
|
- If you want the `data/` folder flashed as a filesystem image, use your preferred ESP32 LittleFS upload workflow
|
|
|
|
The firmware also calls `LittleFS.begin(true)`, so an empty filesystem can be formatted automatically at boot if needed.
|
|
|
|
## IMU And Yaw Guide
|
|
|
|
### AK09918C Compass Investigation
|
|
|
|
This firmware contains a best-effort fix and diagnostic pass for the onboard
|
|
compass path. It is intentionally documented here so anyone finding this repo can
|
|
see what was tested instead of repeating the same blind firmware changes.
|
|
|
|
Waveshare documents the board as using `QMI8658C + AK09918/AK09918C` for the
|
|
onboard 9-axis IMU. The big marked QST chip on the PCB is the `QMI8658C`
|
|
accelerometer/gyro. The AK09918C compass is a much smaller AKM WLCSP part; AKM
|
|
lists the package as a 4-pin `0.76 mm x 0.76 mm x 0.5 mm` device, so it will not
|
|
look like a normal large labelled IC.
|
|
|
|
Relevant upstream references:
|
|
|
|
- Waveshare product page: <https://www.waveshare.com/General-Driver-for-Robots.htm>
|
|
- Waveshare wiki: <https://www.waveshare.com/wiki/General_Driver_for_Robots>
|
|
- Waveshare GitHub commit that disables/ignores the mag path: <https://github.com/waveshareteam/ugv_base_general/commit/b113287ffff7fee03998f998a4e24ae221dd96aa>
|
|
- AKM AK09918C product page: <https://www.akm.com/us/en/products/electronic-compass/lineup-electronic-compass/ak09918c/>
|
|
- AK09918C datasheet package/marking page: <https://www.alldatasheet.com/html-pdf/929214/AKM/AK09918C/1641/27/AK09918C.html>
|
|
- Linux AKM magnetometer driver listing `AK09918_DEVICE_ID 0x0C`: <https://codebrowser.dev/linux/linux/drivers/iio/magnetometer/ak8975.c.html>
|
|
|
|
Observed I2C bus on the tested board:
|
|
|
|
- `0x0C`: AKM-compatible compass address
|
|
- `0x3C`: SSD1306 OLED
|
|
- `0x42`: INA219 voltage/current monitor
|
|
- `0x6B`: QMI8658C accelerometer/gyro
|
|
|
|
The firmware now probes the compass more defensively:
|
|
|
|
- checks AKM-compatible identity on `0x0C`
|
|
- also probes `0x06` to catch confusion between 7-bit and 8-bit I2C address notation
|
|
- transitions through power-down before measurement modes
|
|
- tries continuous `100 Hz`, `50 Hz`, `20 Hz`, `10 Hz`, then single-measurement mode
|
|
- reads `ST1`, `CNTL2`, raw data, and `ST2` for every mode probe
|
|
- runs a bounded AK09918 self-test diagnostic instead of hanging forever
|
|
- scans the I2C bus at boot when the compass does not produce data
|
|
- keeps yaw from using fake `0/0/0` magnetometer samples
|
|
- exposes `magSrc`, `magStatus`, `magLive`, `magAddr`, `magWIA2`, and `magSamples`
|
|
|
|
Important diagnostic pattern from the tested board:
|
|
|
|
```text
|
|
I2C scan: 0x0C 0x3C 0x42 0x6B
|
|
AK09918 addr=0x0C ... WIA2=0x0C or 0x0D
|
|
CNTL2 writes/readbacks work, e.g. 0x08 for continuous-100Hz
|
|
ST1 remains 0x00
|
|
raw remains 0/0/0
|
|
self-test sets CNTL2=0x10 but times out with no DRDY
|
|
QMI8658 mag fallback also reports raw=0/0/0
|
|
```
|
|
|
|
Interpretation:
|
|
|
|
- I2C wiring and the digital register interface are alive because the chip ACKs,
|
|
identity registers can be read, reset works, and `CNTL2` mode writes stick.
|
|
- The magnetic measurement core is not producing `DRDY` or non-zero raw samples.
|
|
- This is not the same as bad calibration; calibration needs live changing mag
|
|
samples first.
|
|
- If the same pattern appears on another board, likely causes include a board
|
|
revision issue, AK09918C supply/decoupling/soldering problem, damaged compass
|
|
die, or an AKM-compatible variant/clone that does not behave like the public
|
|
AK09918C register model.
|
|
|
|
This does not prove every General Driver board has a hardware fault. It means
|
|
this firmware has exhausted the obvious software-side address, mode, transaction,
|
|
and calibration fixes for this observed failure mode.
|
|
|
|
### What Was Fixed
|
|
|
|
The original IMU path had multiple issues that could produce unstable or misleading `yaw`:
|
|
|
|
- filter integrator terms were not preserved correctly
|
|
- sample timing was effectively fixed instead of using real elapsed time
|
|
- quaternion integration used unsafe update ordering
|
|
- I2C reads for the IMU sensors were fragile
|
|
- magnetometer offsets were not handled in a reliable workflow
|
|
|
|
### Current Yaw Behavior
|
|
|
|
`yaw` now works in two stages:
|
|
|
|
- relative orientation from the gyro/fusion path
|
|
- absolute heading correction from the magnetometer when a valid mag calibration is available
|
|
|
|
Without a valid magnetometer calibration, `yaw` can still move, but absolute heading quality will be poor.
|
|
|
|
## Magnetometer Calibration
|
|
|
|
### Goal
|
|
|
|
Create a good heading calibration once, save it to flash, and automatically reload it on every boot.
|
|
|
|
### Start Calibration
|
|
|
|
Send:
|
|
|
|
```json
|
|
{"T":145}
|
|
```
|
|
|
|
This starts a magnetometer calibration session.
|
|
|
|
### During Calibration
|
|
|
|
For about 12 seconds:
|
|
|
|
- rotate the rover slowly through a full turn
|
|
- change orientation gently so the sensor sees different magnetic angles
|
|
- avoid fast shaking
|
|
- avoid strong magnets, steel tables, speakers, power bricks, or large metal objects nearby
|
|
|
|
### Check Progress
|
|
|
|
Send:
|
|
|
|
```json
|
|
{"T":126}
|
|
```
|
|
|
|
Important feedback fields:
|
|
|
|
- `magCal`
|
|
`1` means a valid heading calibration is active
|
|
- `magSaved`
|
|
`1` means offsets were saved to flash
|
|
- `magCalRunning`
|
|
`1` while calibration is still collecting data
|
|
- `magCalProgress`
|
|
progress from `0` to `100`
|
|
- `magSrc`
|
|
active compass source: `ak09918`, `qmi8658`, or `none`
|
|
- `magStatus`
|
|
compass health: `ok`, `no_drdy`, `lost`, or `not_found`
|
|
- `magLive`
|
|
`1` only after at least one real magnetometer sample was received
|
|
|
|
### Successful Result
|
|
|
|
After a successful run:
|
|
|
|
- offsets are written to `/imuConfig.json`
|
|
- saved offsets are loaded automatically at boot
|
|
- manual rotation on every startup is no longer required
|
|
|
|
### If Calibration Fails
|
|
|
|
If `magCal` stays `0`:
|
|
|
|
- run `{"T":145}` again
|
|
- rotate slower
|
|
- cover more angles
|
|
- move away from magnetic or metal interference
|
|
|
|
If `magStatus` is `no_drdy` and `magLive` is `0`, firmware can talk to the
|
|
AKM-compatible chip but the magnetic measurement core is not producing data.
|
|
That is different from a calibration problem: check the board revision, IMU
|
|
chip marking, AK09918C supply rails, and soldering around the IMU.
|
|
|
|
If `magSaved` is `0` after a good calibration:
|
|
|
|
- check that `LittleFS` mounted successfully
|
|
- reflash and retry
|
|
|
|
## IMU JSON Commands
|
|
|
|
### Read IMU Data
|
|
|
|
```json
|
|
{"T":126}
|
|
```
|
|
|
|
Returns roll, pitch, yaw, accel, gyro, mag, temperature, and calibration state flags.
|
|
It also returns `magSrc`, `magStatus`, `magLive`, `magAddr`, `magWIA2`, and
|
|
`magSamples` for compass diagnosis.
|
|
|
|
### Recalibrate Gyro/Accel Bias
|
|
|
|
Keep the rover still on a stable surface, then send:
|
|
|
|
```json
|
|
{"T":127}
|
|
```
|
|
|
|
This is not the same as a full magnetometer calibration.
|
|
|
|
### Get Current Magnetometer Offsets
|
|
|
|
```json
|
|
{"T":128}
|
|
```
|
|
|
|
### Set Magnetometer Offsets Manually
|
|
|
|
```json
|
|
{"T":129,"x":-12,"y":0,"z":0}
|
|
```
|
|
|
|
Manual offsets are also saved to flash automatically in `V1.0`.
|
|
|
|
### Start Magnetometer Calibration
|
|
|
|
```json
|
|
{"T":145}
|
|
```
|
|
|
|
## Base Feedback
|
|
|
|
Base feedback also exposes the IMU calibration state:
|
|
|
|
```json
|
|
{"T":130}
|
|
```
|
|
|
|
Useful fields:
|
|
|
|
- `r`
|
|
- `p`
|
|
- `y`
|
|
- `magCal`
|
|
- `magSaved`
|
|
- `magCalRunning`
|
|
- `magCalProgress`
|
|
- `magSrc`
|
|
- `magStatus`
|
|
- `magLive`
|
|
- `temp`
|
|
|
|
## Yaw Troubleshooting
|
|
|
|
If `yaw` still looks wrong:
|
|
|
|
1. Run `{"T":145}`.
|
|
2. Rotate the rover slowly until calibration completes.
|
|
3. Check `{"T":126}` and confirm:
|
|
- `magCal = 1`
|
|
- `magSaved = 1`
|
|
- `magCalRunning = 0`
|
|
- `magStatus = ok`
|
|
4. Reboot and verify the values are still loaded.
|
|
|
|
If `yaw` drifts while `magStatus` is not `ok`, the rover is running gyro/accel
|
|
AHRS without a live compass. Fix the magnetometer hardware path first.
|
|
|
|
If `yaw` is stable but mirrored or rotated by a fixed amount, the next thing to tune is axis convention or declination, not the calibration storage itself.
|
|
|
|
## Notes
|
|
|
|
- Build artifacts such as `build/`, `*.bin`, `*.elf`, and `*.map` are ignored in Git
|
|
- `imuConfig.json` is generated on-device and is not meant to be versioned in this repo
|
|
- This repo currently tracks source, not release binaries
|
|
|
|
## Official References
|
|
|
|
- Arduino IDE: <https://docs.arduino.cc/software/ide/>
|
|
- Arduino-ESP32 install guide: <https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html>
|
|
- esptool install guide: <https://docs.espressif.com/projects/esptool/en/latest/installation.html>
|