This exercise addresses the QMI8658 six-axis inertial sensor.

## Executive Summary

The QMI8658 is a [6-DoF IMU](#six-degrees-of-freedom-6-dof-imu): a three-axis accelerometer plus a three-axis gyroscope.

The outputs from this sensor are:

- Acceleration on X, Y, and Z in [`g`](#g)
- Angular rotation on X, Y, and Z in [`dps`](#dps-degrees-per-second)
- Temperature in degrees C
- Derived motion events such as wake-on-motion and pedometer counts
- Derived orientation estimates such as [`roll`](#roll-pitch-yaw), [`pitch`](#roll-pitch-yaw), and [`yaw`](#roll-pitch-yaw) when paired with a fusion filter such as [Madgwick](#madgwick)

In practical terms, this sensor is useful for:

- Detecting tilt, orientation change, vibration, and shock
- Measuring how fast the device is rotating
- Detecting movement versus stillness for low-power wakeup
- Building a step counter or simple activity detector
- Driving a real-time attitude display, cursor, or gesture interface
- Logging motion history with FIFO buffering when the CPU cannot sample every reading immediately

The manufacturer examples staged in `/usr/local/src/LilyGo-LoRa-Series/examples/Sensor` show three main usage patterns:

- `QMI8658_GetDataExample`: simple polling of raw accel, gyro, timestamp, and temperature
- `QMI8658_InterruptExample`: use the data-ready interrupt instead of polling constantly
- `QMI8658_ReadFromFifoExample`: burst-read buffered samples from the sensor FIFO
- `QMI8658_MadgwickAHRS`: fuse accel + gyro into roll/pitch/yaw
- `QMI8658_BlockExample` and `QMI8658_InterruptBlockExample`: turn orientation into a live visual block position
- `QMI8658_WakeOnMotion`: low-power motion-triggered wakeup
- `QMI8658_PedometerExample`: use the chip's built-in step-detection logic
- `QMI8658_LockingMechanismExample`: callback-based handling for synchronized data reads

## What The Settings Mean

The examples expose four major tuning knobs.

### 1. Full-scale range

Accelerometer range:

- `ACC_RANGE_2G`
- `ACC_RANGE_4G`
- `ACC_RANGE_8G`
- `ACC_RANGE_16G`

Gyroscope range:

- `GYR_RANGE_16DPS`
- `GYR_RANGE_32DPS`
- `GYR_RANGE_64DPS`
- `GYR_RANGE_128DPS`
- `GYR_RANGE_256DPS`
- `GYR_RANGE_512DPS`
- `GYR_RANGE_1024DPS`

Tradeoff:

- Lower range gives finer measurement resolution but clips sooner.
- Higher range survives stronger motion but each ADC count represents a larger real-world change.

From the driver, the scale is computed as full-scale divided by `32768`, so approximate per-count resolution is:

- Accelerometer `2g`: `2 / 32768 = 0.000061 g/count`
- Accelerometer `4g`: `4 / 32768 = 0.000122 g/count`
- Accelerometer `8g`: `8 / 32768 = 0.000244 g/count`
- Accelerometer `16g`: `16 / 32768 = 0.000488 g/count`
- Gyro `64 dps`: `64 / 32768 = 0.00195 dps/count`
- Gyro `256 dps`: `256 / 32768 = 0.00781 dps/count`
- Gyro `1024 dps`: `1024 / 32768 = 0.03125 dps/count`

For this exercise, lower accel ranges such as `2g` or `4g` are usually best unless you expect impacts. A gyro range around `256 dps` is a good middle ground for hand motion.

### 2. Output data rate ([`Hz`](#hz-hertz))

Accelerometer ODR options seen in the examples:

- `1000`, `500`, `250`, `125`, `62.5`, `31.25 Hz`
- Low-power accel-only modes: `128`, `21`, `11`, `3 Hz`

Gyroscope ODR options seen in the examples:

- `7174.4`, `3587.2`, `1793.6`, `896.8`, `448.4`, `224.2`, `112.1`, `56.05`, `28.025 Hz`

What this achieves:

- Higher `Hz` means more frequent samples and better tracking of fast motion.
- Lower `Hz` reduces data volume, CPU work, and power usage.
- If both accel and gyro are enabled in 6-DoF mode, the library notes that the effective accel timing is derived from the gyro timing.

Practical guidance:

- `25-100 Hz`: human motion, UI demos, tilt displays, step counting
- `100-250 Hz`: responsive motion display with moderate load
- `500-1000 Hz`: aggressive sampling for fast dynamics, usually more than needed for a serial console demo
- Very high gyro ODR values are useful only if the rest of the system can keep up

### 3. Low-pass filter (`LPF_MODE_*`)

The examples show:

- `LPF_MODE_0`: `2.66%` of ODR
- `LPF_MODE_1`: `3.63%` of ODR
- `LPF_MODE_2`: `5.39%` of ODR
- `LPF_MODE_3`: `13.37%` of ODR
- `LPF_OFF`

This is a smoothing filter.

- Narrower bandwidth reduces noise but makes the signal slower and softer.
- Wider bandwidth responds faster but passes more jitter.

Example:

- At `1000 Hz` accel ODR, `LPF_MODE_0` is about `26.6 Hz` bandwidth.
- At `896.8 Hz` gyro ODR, `LPF_MODE_3` is about `120 Hz` bandwidth.

That explains why the examples often use:

- accel `LPF_MODE_0` for a steadier gravity vector
- gyro `LPF_MODE_3` for quicker rotational response

### 4. FIFO depth and watermark

The FIFO example uses:

- FIFO sizes of `16`, `32`, `64`, or `128` samples
- `FIFO_MODE_FIFO`: stop accepting new data when full
- `FIFO_MODE_STREAM`: overwrite oldest data when full
- A watermark interrupt level in samples

What this achieves:

- Lets the sensor accumulate data while the MCU is busy
- Reduces interrupt rate by reading batches
- Helps avoid losing data when serial output is slower than sensor sampling

Important detail from the driver:

- One enabled sensor stream uses `6 bytes/sample`
- Accel + gyro together use `12 bytes/sample`

So a `16`-sample FIFO with both sensors enabled holds `192 bytes` of motion data.

## What Madgwick Does

[Madgwick](#madgwick) is a sensor-fusion algorithm. It combines the raw accelerometer and gyroscope readings into a more useful estimate of device orientation.

Instead of only showing:

- accel X/Y/Z
- gyro X/Y/Z

it can estimate:

- roll
- pitch
- yaw

Why this helps:

- The gyroscope reacts quickly to motion, but it drifts over time.
- The accelerometer provides a gravity reference, but it is noisy and is disturbed by real movement.
- Madgwick blends the fast gyro response with the gravity reference from the accelerometer to produce a smoother and more stable attitude estimate.

In the staged examples:

- `QMI8658_MadgwickAHRS` prints orientation values derived from the raw IMU data
- `QMI8658_BlockExample` and `QMI8658_InterruptBlockExample` use that orientation estimate to move a block on the display

Important limitation:

- With only accelerometer + gyroscope, roll and pitch can be stabilized reasonably well.
- Yaw is relative and will drift over time because there is no magnetometer to provide an absolute heading reference.

For this exercise, Madgwick is useful because it converts the six raw motion channels into something easier to understand in real time while the board is tilted and rotated by hand.

## What The Sensor Is Best For In This Exercise

For a teaching exercise with live console output, the best first goal is not pedometer or wake-on-motion. It is a clean real-time observer that shows:

- raw accel X/Y/Z
- raw gyro X/Y/Z
- computed roll/pitch
- sampling rate or inter-sample timing

That will let a student immediately see:

- gravity moving across axes as the device tilts
- gyro spikes during rotation
- the effect of changing range and ODR
- the effect of LPF smoothing

## Recommended Direction For The Next Design Step

A strong Exercise 21 design would be:

- Start from `QMI8658_GetDataExample`
- Add a fixed-rate output loop at `25-50 Hz` for readability over serial
- Print accel, gyro, and temperature every cycle
- Add an optional Madgwick roll/pitch output mode
- Add one compile-time or menu-controlled profile for "slow and smooth" and one for "fast and responsive"

Suggested initial profiles:

- `Smooth console demo`: accel `4g @ 125 Hz`, gyro `256 dps @ 112.1 Hz`, moderate LPF
- `Fast motion demo`: accel `4g @ 250 Hz`, gyro `256 dps @ 224.2 Hz`, lighter filtering

This exercise requires being connected via a console and real-time output is generated as the unit is moved in 3 dimensions so one can observe how quickly the sensors respond.

## Glossary

### Six Degrees Of Freedom (6-DoF) IMU

An inertial measurement unit with six motion channels: three accelerometer axes and three gyroscope axes.

### g

The accelerometer unit for acceleration. `1 g` is approximately Earth gravity.

### dps (Degrees Per Second)

The gyroscope unit for angular velocity. It reports how fast the device is rotating around an axis.

### mg

Milli-g. One thousandth of a `g`. This is commonly used for motion thresholds such as wake-on-motion and pedometer sensitivity.

### Hz (Hertz)

Samples per second. Higher `Hz` means the sensor reports data more frequently.  Example: 1 Hz = 1 sample per second.  10 Hz = 1 sample per 100 milliseocnds.

### Roll, Pitch, Yaw

Common orientation angles.

- Roll: rotation around the front-to-back axis
- Pitch: rotation around the side-to-side axis
- Yaw: rotation around the vertical axis

### Madgwick

A sensor-fusion algorithm that combines accelerometer and gyroscope data to estimate orientation more cleanly than raw sensor values alone.
