# hello_spirit_level Digital spirit level (inclinometer) for the CUBE32 board. The LSM6DSO accelerometer gives roll and pitch, shown as a bubble on an LVGL canvas that moves opposite to the tilt, like a real bubble level. ## Features - **Bubble display**: a circular bubble drawn on a 180x180 LVGL canvas, moving opposite to the tilt (4 px per degree) - **Reference rings** at 1°, 5° and 10° - **Adapts to the screen size**: the level is centered and scaled at start-up (the log shows `Screen WxH, canvas SxS`): 180×180 on 240×240, 260×260 on 320×320. Rings, bubble and sensitivity scale with it, so the full range stays about ±21° - **Numeric readout**: `Roll` and `Pitch` in degrees - **Colour feedback**: the ring, bubble and status text follow the total tilt | Total tilt | Colour | Status | |------------|--------|--------| | ≤ 1° | green | `LEVEL` | | 1° – 5° | yellow | `SLIGHT TILT` | | 5° – 10° | orange | `TILTED` | | > 10° | red | `STEEP` | - **Smooth motion**: a low-pass filter (`FILTER_ALPHA = 0.35`) removes jitter from the accelerometer data - **Console fallback**: the tilt is also printed twice a second, and it is the only output when LVGL is disabled Roll is the rotation about the X axis (sideways tilt); pitch is the rotation about the Y axis (forward/backward tilt). Both are computed from the accelerometer only, so the board has to be still while measuring. ## Hardware - CUBE32 board (ESP32-S3) with a supported display (auto-detected at boot) - LSM6DSO IMU (on the board) ## Configuration `sdkconfig.defaults` of the release example already has what the demo needs: | Setting | Why | |---------|-----| | `CONFIG_CUBE32_LVGL_ENABLED=y` | LVGL display driver | | `CONFIG_CUBE32_TOUCH_ENABLED=y` | Touch input (standard LVGL setup of the examples) | | `CONFIG_CUBE32_IMU_ENABLED=y` | Accelerometer data | | `CONFIG_LV_USE_CANVAS=y` | The bubble face is drawn on a canvas | | `CONFIG_LV_FONT_MONTSERRAT_18=y` | Title label | | `CONFIG_LV_FONT_MONTSERRAT_10/20/24=y` | Required by the BLE OTA UI whenever LVGL is on | In the BSP dev project select the demo with `idf.py menuconfig` → `CUBE32 Application Selection` → `Hello Spirit Level Example` (it is only listed when LVGL and the IMU are enabled). ## Build and run ```bash idf.py set-target esp32s3 idf.py build idf.py -p <port> flash monitor ``` Run `idf.py set-target esp32s3` again after deleting `sdkconfig`; otherwise the target falls back to `esp32`. ## Usage 1. Put the board flat on the surface to check and flash the example. 2. The bubble sits in the centre, the ring is green and the status reads `LEVEL` when the surface is level. 3. Tilt the board: the bubble moves away from the direction of the tilt and the colour changes from green to yellow, orange and red. 4. Read the exact angles from `Roll` / `Pitch`. If the IMU is not initialised, the bubble stays in the centre and the console prints `IMU: Not initialized`. ## Console output ``` I (xxxx) spirit_level: ======================================== I (xxxx) spirit_level: CUBE32 Spirit Level / Inclinometer I (xxxx) spirit_level: ======================================== I (xxxx) spirit_level: IMU: LSM6DSO ready I (xxxx) spirit_level: UI created I (xxxx) spirit_level: Spirit level running — tilt the board to see the bubble move Roll: +0.3° Pitch: -0.2° Total: 0.4° [LEVEL] Roll: +4.8° Pitch: -1.1° Total: 4.9° [SLIGHT TILT] ```
To create a project from this example, run:
idf.py create-project-from-example "cube32esp/cube32_bsp=0.0.17:hello_spirit_level"