Skip to content

feat: HUD polish — annunciators, adaptive numpad, STATUSTEXT ticker#75

Merged
mrpollo merged 2 commits intoPX4:mainfrom
MikePehel:feat/hud-polish
Apr 10, 2026
Merged

feat: HUD polish — annunciators, adaptive numpad, STATUSTEXT ticker#75
mrpollo merged 2 commits intoPX4:mainfrom
MikePehel:feat/hud-polish

Conversation

@MikePehel
Copy link
Copy Markdown
Contributor

@MikePehel MikePehel commented Apr 5, 2026

Summary

Bundle of HUD visual improvements: event-driven micro-animations, ULog warning message parsing, responsive layout, and quality-of-life fixes.

  • STATUSTEXT parsing: ULog logging messages ('L' type) parsed into per-drone ring buffer, exposed via data_source.playback.statustext
  • Notification ticker (N key toggle): severity-colored warnings from drone palette colors, gradient-faded edges. Console: ticker zone above bar. Tactical: bottom-right panel. Entries persist until pushed out.
  • Adaptive numpad: 3x3 (≤9 drones), 3x4 (10-12), 4x4 (13-16) with smaller font for two-digit numbers
  • Font scaling floors: minimum readable sizes at small windows, label alpha reduced for better contrast
  • Interpolation toast: I key shows toast instead of printf
  • Multi-drone trail default: trail_mode defaults to ID trails (mode 3) when multiple logs loaded. T key still cycles all modes.
  • Correlation line colors: ortho and radar correlation lines now use the pinned drone's color instead of a blended midpoint
  • Removed multi_drone marker color override: markers use velocity/directional colors again in all trail modes
  • Annunciator system (hud_annunciators.c/h):
    • Console tab fade: per-drone left color bar double-pulses on marker crossing
    • Gimbal ring bounce: pinned drone cell bounces on marker crossing (tactical)
    • Radar droplet wave: two expanding rings from drone blip on marker crossing (tactical)
    • Ticker warning flash: background brightens + text inverts on STATUSTEXT arrival
    • Ring shake: gimbal cell oscillates horizontally on STATUSTEXT warning (tactical)

Blocked by

Test plan

  • All 7 existing tests pass
  • Adaptive numpad: 3x4 with 7 drones, 4x4 with 16
  • Font scaling: readable at small window sizes
  • I key shows interpolation toast
  • N key toggles notifications on/off with toast
  • STATUSTEXT warnings render in console ticker zone with gradient edges
  • STATUSTEXT warnings render in tactical bottom-right panel
  • Tab fade: color bar pulses on marker crossing (console)
  • Gimbal ring bounce on marker crossing (tactical, pinned drones)
  • Radar droplet wave on marker crossing (tactical)
  • Ticker flash on STATUSTEXT arrival
  • Ring shake on STATUSTEXT warning (tactical, pinned drones)
  • Tested with fixture 1040ff85 (694 logging messages, emergency battery + preflight fails)
  • Multi-drone trail defaults to ID trails (mode 3), T key cycles normally
  • Correlation lines in ortho/radar use pinned drone's color
  • Marker colors use velocity/directional coloring (not drone ID) in non-ID trail modes

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR bundles HUD visual/UX improvements for both Console and Tactical modes, including STATUSTEXT-driven notifications, adaptive layouts, and new micro-animations (“annunciators”) tied to replay events.

Changes:

  • Added STATUSTEXT capture from ULog L messages, exposed via playback state and rendered as a severity-colored ticker/notification panel.
  • Introduced Tactical HUD rendering (new module) plus ortho inset drawing helper and updated correlation line coloring.
  • Improved multi-drone replay UX: adaptive numpad sizing, multi-drone marker/timeline rendering, global marker cycling, and trail/marker coloring updates.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
CMakeLists.txt Builds new Tactical HUD + annunciator modules.
src/main.c Integrates HUD mode cycling, STATUSTEXT feeding, marker sync/cycling, multi-drone trail defaults.
src/hud.h Adds HUD modes, STATUSTEXT ticker storage, notification toggle, annunciator state, multi-drone marker inputs.
src/hud.c Implements STATUSTEXT ticker rendering/feeding, adaptive numpad, annunciator-driven effects, font scaling floors.
src/hud_transport.h Extends transport API to accept per-drone marker arrays.
src/hud_transport.c Renders multi-drone markers on timeline, uses ID-trails color override via drone color.
src/hud_telemetry.h Passes selected index for (future) telemetry annunciators.
src/hud_telemetry.c Telemetry rendering refactors in support of upcoming peak-scale behavior.
src/hud_annunciators.h New annunciator API/types for HUD micro-animations.
src/hud_annunciators.c Implements annunciator timers, triggers, and query helpers.
src/tactical_hud.h Declares Tactical HUD draw entrypoint.
src/tactical_hud.c New Tactical HUD renderer: radar, gimbal rings, insets, ticker/notifications, reticle, stacks.
src/ortho_panel.h Adds ortho_panel_draw_single() for tactical insets.
src/ortho_panel.c Updates correlation line coloring + adds inset ortho drawing implementation.
src/vehicle.h Extends marker drawing/color APIs with drone_color parameter for ID trails.
src/vehicle.c Implements ID-trails marker coloring and passes drone_color through marker draw paths.
src/replay_markers.h Adds global marker cycle API.
src/replay_markers.c Implements global marker cycling across drones + chase camera restore behavior.
src/replay_trail.c Adjusts sys-marker resolution to playback-time space using offsets.
src/ui_marker_input.h Tracks drone index for label input targeting in multi-drone replays.
src/ulog_parser.h Adds logging-message struct + callback API for L messages.
src/ulog_parser.c Invokes logging callback when parsing ULog logging messages.
src/ulog_replay.h Adds STATUSTEXT ring buffer types and per-replay storage.
src/ulog_replay.c Hooks logging callback into replay init to capture STATUSTEXT.
src/data_source.h Exposes STATUSTEXT ring pointer via playback_state_t.
src/data_source_ulog.c Wires replay STATUSTEXT ring into playback state.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ulog_replay.c Outdated
Comment thread src/ortho_panel.c Outdated
Comment thread src/hud_annunciators.c Outdated
Comment on lines +131 to +136
// Peak scale: returns font scale factor (1.0 normal, 1.05 at peak)
float annunc_peak_scale_factor(const hud_annunciators_t *a, int drone_idx, int channel) {
if (drone_idx < 0 || drone_idx >= ANNUNC_MAX_VEHICLES) return 1.0f;
if (channel < 0 || channel >= ANNUNC_PEAK_CHANNELS) return 1.0f;
return a->peak_scale.at_peak[drone_idx][channel] ? 1.10f : 1.0f;
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

annunc_peak_scale_factor() returns 1.10f when at peak, but the comment says “1.05 at peak”. Please align the implementation and the documented behavior (either change the factor or update the comment) to avoid confusion when tuning HUD animation.

Copilot uses AI. Check for mistakes.
Comment thread src/hud_telemetry.c
Comment on lines +30 to +31
int sel = lay->selected;

Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sel is assigned from lay->selected but never used, which will trigger an unused-variable warning under typical warning levels. Either use it (e.g., when applying peak-scale per selected drone) or remove the variable / mark it unused.

Suggested change
int sel = lay->selected;

Copilot uses AI. Check for mistakes.
Comment thread src/hud.c
Comment on lines +380 to +398
// Center solid, edges fade to transparent
float bg_x = tx - bg_pad;
float bg_w = total_w + bg_pad * 2;
float bg_h = msg_w.y + 4 * s;
float edge = bg_pad;
// Left fade
for (int px = 0; px < (int)edge; px++) {
float a = (float)px / edge;
Color fc = {bg_c.r, bg_c.g, bg_c.b, (unsigned char)(bg_c.a * a)};
DrawRectangle((int)(bg_x + px), (int)ty, 1, (int)bg_h, fc);
}
// Center solid
DrawRectangle((int)(bg_x + edge), (int)ty, (int)(bg_w - edge * 2), (int)bg_h, bg_c);
// Right fade
for (int px = 0; px < (int)edge; px++) {
float a = 1.0f - (float)px / edge;
Color fc = {bg_c.r, bg_c.g, bg_c.b, (unsigned char)(bg_c.a * a)};
DrawRectangle((int)(bg_x + bg_w - edge + px), (int)ty, 1, (int)bg_h, fc);
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ticker background rendering uses two per-pixel loops (for (px=0; px<edge; px++)) for every ticker line, every frame. On large windows (high s) this becomes a noticeable CPU cost. Consider replacing the per-pixel fades with a small precomputed gradient texture, DrawRectangleGradientEx, or a fixed small number of wider quads.

Suggested change
// Center solid, edges fade to transparent
float bg_x = tx - bg_pad;
float bg_w = total_w + bg_pad * 2;
float bg_h = msg_w.y + 4 * s;
float edge = bg_pad;
// Left fade
for (int px = 0; px < (int)edge; px++) {
float a = (float)px / edge;
Color fc = {bg_c.r, bg_c.g, bg_c.b, (unsigned char)(bg_c.a * a)};
DrawRectangle((int)(bg_x + px), (int)ty, 1, (int)bg_h, fc);
}
// Center solid
DrawRectangle((int)(bg_x + edge), (int)ty, (int)(bg_w - edge * 2), (int)bg_h, bg_c);
// Right fade
for (int px = 0; px < (int)edge; px++) {
float a = 1.0f - (float)px / edge;
Color fc = {bg_c.r, bg_c.g, bg_c.b, (unsigned char)(bg_c.a * a)};
DrawRectangle((int)(bg_x + bg_w - edge + px), (int)ty, 1, (int)bg_h, fc);
}
Color bg_transparent = (Color){sc.r, sc.g, sc.b, 0};
// Center solid, edges fade to transparent
float bg_x = tx - bg_pad;
float bg_w = total_w + bg_pad * 2;
float bg_h = msg_w.y + 4 * s;
float edge = bg_pad;
// Left fade
DrawRectangleGradientEx(
(Rectangle){bg_x, ty, edge, bg_h},
bg_transparent, bg_c, bg_c, bg_transparent
);
// Center solid
DrawRectangle((int)(bg_x + edge), (int)ty, (int)(bg_w - edge * 2), (int)bg_h, bg_c);
// Right fade
DrawRectangleGradientEx(
(Rectangle){bg_x + bg_w - edge, ty, edge, bg_h},
bg_c, bg_transparent, bg_transparent, bg_c
);

Copilot uses AI. Check for mistakes.
Comment thread src/hud.c Outdated
Comment thread src/vehicle.h Outdated
Comment thread src/ulog_parser.c
Comment on lines +346 to +353
if ((char)msg_type == ULOG_MSG_LOGGING && p->logging_cb && msg_size >= 9) {
ulog_logging_msg_t lmsg;
lmsg.log_level = p->read_buf[0];
memcpy(&lmsg.timestamp, p->read_buf + 1, 8);
lmsg.text = (const char *)(p->read_buf + 9);
lmsg.text_len = msg_size - 9;
p->logging_cb(&lmsg, p->logging_userdata);
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New logging-message callback path in ulog_parser_next() isn’t covered by existing tests (current suite exercises open/seek/iterate but never sets ulog_parser_set_logging_callback() and asserts callbacks fire / text is handled correctly). Please add a unit test using a fixture known to contain ULOG_MSG_LOGGING messages (e.g., the 1040ff85...ulg fixture in tests/fixtures) to validate severity/timestamp/text parsing and callback invocation order.

Copilot uses AI. Check for mistakes.
- Parse ULog logging messages ('L' type) into per-drone ring buffer
- Color-coded STATUSTEXT ticker (N key toggle): severity colors from
  theme drone palette, gradient-faded edges, persists until pushed out
- Console: warnings take over ticker zone above HUD bar
- Tactical: warnings show in bottom-right notification panel
- Adaptive numpad: 3x3 (≤9), 3x4 (10-12), 4x4 (13-16) with smaller
  font for two-digit numbers
- Font scaling floors: minimum readable sizes at small windows,
  label alpha reduced for better contrast
- Interpolation toast: I key now shows toast instead of printf
- Annunciator system (hud_annunciators.c/h):
  - Console tab fade: per-drone color bar double-pulses on marker crossing
  - Gimbal ring bounce: pinned drone cell bounces on marker (tactical)
  - Radar droplet wave: two expanding rings from drone blip (tactical)
  - Ticker warning flash: background brightens, text inverts on arrival
  - Ring shake: gimbal cell oscillates on STATUSTEXT warning (tactical)
- ulog_replay: move STATUSTEXT logging callback registration to after
  pre-scan rewind so the ring only fills with messages encountered
  during playback, not during the full-file pre-scan pass.
- vehicle.h: drop stale "or multi-drone mode" from vehicle_marker_color
  docstring (multi_drone parameter was removed earlier in this PR).
- hud_annunciators: remove unused peak_scale annunciator — struct,
  init loop, annunc_peak_update, annunc_peak_scale_factor, the PEAK_*
  channel defines, and the two call sites in main.c. Feature was
  abandoned; code was dead (factor function never called).
- hud: bound severity ASCII→numeric conversion to '0'-'7' to avoid
  mis-handling corrupt or out-of-range severity bytes.
- ortho_panel_draw_single: use pinned drone's color for correlation
  line instead of blended midpoint, matching ortho_panel_draw and
  ortho_draw_fullscreen_2d (the other two 2D ortho draw functions).
@mrpollo mrpollo merged commit 5e84235 into PX4:main Apr 10, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants