drone-hud
:::warning [UNTESTED] — v0.5 paper-correct
Builds clean on native_sim/native/64 and cross-compiles to the AEN target. Real-silicon bring-up + airframe integration land later.
:::
A live attitude / GPS / battery HUD for a drone, rendered with LVGL on an ST7789 TFT.
Source: examples/display/drone-hud/.
Components
- LSM6DSO IMU — 6-axis sensor read via
<alp/chips/lsm6dso.h>. - u-blox NEO-M9N GNSS — UART NMEA via
<alp/chips/ublox_neo_m9n.h>. - INA236 battery monitor — voltage / current via
<alp/chips/ina236.h>. - ST7789 TFT — 240×320 SPI panel via
<alp/chips/st7789.h>. <alp/ahrs.h>— Madgwick fusion of IMU samples into attitude.- LVGL — composes the artificial horizon + GPS readout + battery telemetry + flight-mode selector.
Attitude fusion
Attitude comes from the portable <alp/ahrs.h> Madgwick filter, which owns the quaternion state and the Euler conversion — there is no hand-rolled fusion in the app:
static alp_ahrs_t s_ahrs; /* Madgwick orientation filter */
alp_ahrs_init(&s_ahrs, NULL); /* default gains */
/* ... per IMU sample: */
alp_ahrs_update_imu(&s_ahrs, gx, gy, gz, a.x, a.y, a.z, dt_s);
alp_ahrs_euler(&s_ahrs, &telem->roll_deg, &telem->pitch_deg, &telem->yaw_deg);
Fusing the accelerometer pins roll and pitch against gravity, so the HUD attitude no longer drifts without bound the way the earlier gyro-only integrator did.
Thread model
Three threads at independent rates:
- Render — 30 fps screen update
- IMU + AHRS — 100 Hz attitude fusion
- Slow telemetry — 5 Hz GPS + battery refresh
Display bring-up
The app owns the panel init sequence rather than letting LVGL auto-initialise it. It opens the display through <alp/display.h> and binds LVGL to it with <alp/gui.h>:
alp_display_config_t display_cfg = ALP_DISPLAY_CONFIG_DEFAULT(0);
alp_display_t *display = alp_display_open(&display_cfg);
if (display == NULL) { /* alp_last_error() */ }
lv_init();
lv_tick_set_cb(k_uptime_get_32);
alp_status_t attach_status = alp_gui_lvgl_attach(display);
This requires CONFIG_LV_Z_AUTO_INIT=n in prj.conf — see lvgl-widgets-demo for the full rationale.
board.yaml
libraries:
- name: lvgl
cores: [m55_hp]
- name: madgwick-ahrs
cores: [m55_hp]
som:
sku: E1M-AEN801
preset: e1m-evk
pins:
- { e1m: E1M_I2C0, macro: EVK_I2C_BUS_SENSORS, doc: "Shared sensor + IO-expander + INA236 bus" }
- { e1m: E1M_UART0, macro: EVK_UART_PORT_DEBUG, doc: "Console UART exposed on the JTAG/SWD-side debug header" }
- { e1m: E1M_SPI1, macro: EVK_SPI_BUS_ARDUINO, doc: "Arduino UNO header SPI" }
cores:
a32_cluster:
os: "off"
m55_hp:
app: ./src
peripherals:
- i2c # IMU + battery monitor.
- uart # GNSS NMEA.
- spi # Display.
- gpio # Display D/C# + reset.
chips:
- lsm6dso # 6-axis IMU.
- ublox_neo_m9n # Multi-constellation GNSS.
- ina236 # Battery V/I monitor.
- st7789 # 240x320 TFT.
diagnostics:
log_level: info
See also
<alp/ahrs.h>·<alp/display.h>·<alp/gui.h>drone-autopilot— flight-controller variant- Examples overview