JoshandClaude Sonnet 4.6 2180415f5c Fix quaternion-to-yaw formula: yaw now starts at 0° instead of 180°
The previous formula had both atan2 arguments negated relative to the
standard ZYX Euler extraction:
  wrong:   atan2(-2*q1*q2 - 2*q0*q3,  2*q2^2 + 2*q3^2 - 1)
  correct: atan2( 2*q1*q2 + 2*q0*q3,  1 - 2*q2^2 - 2*q3^2)

Since atan2(-y,-x) = atan2(y,x) ± 180°, the identity quaternion [1,0,0,0]
produced atan2(0,-1) = 180° instead of atan2(0,1) = 0°.

This bug caused yaw to always initialise at 180° when no magnetometer
calibration is available. Roll and pitch formulas are unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 22:30:41 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 19:38:19 +02:00
2026-04-23 17:52:46 +02:00
2026-04-23 17:52:46 +02:00

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

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:

{"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:

{"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

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 magSaved is 0 after a good calibration:

  • check that LittleFS mounted successfully
  • reflash and retry

IMU JSON Commands

Read IMU Data

{"T":126}

Returns roll, pitch, yaw, accel, gyro, mag, temperature, and calibration state flags.

Recalibrate Gyro/Accel Bias

Keep the rover still on a stable surface, then send:

{"T":127}

This is not the same as a full magnetometer calibration.

Get Current Magnetometer Offsets

{"T":128}

Set Magnetometer Offsets Manually

{"T":129,"x":-12,"y":0,"z":0}

Manual offsets are also saved to flash automatically in V1.0.

Start Magnetometer Calibration

{"T":145}

Base Feedback

Base feedback also exposes the IMU calibration state:

{"T":130}

Useful fields:

  • r
  • p
  • y
  • magCal
  • magSaved
  • magCalRunning
  • magCalProgress
  • 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
  4. Reboot and verify the values are still loaded.

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

S
Description
No description provided
Readme
227 KiB
Languages
C 74.3%
C++ 25.7%