Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions aleph/modules/msp-osd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ with lib; let
cols = ${toString cfg.osdCols}
refresh_rate_hz = ${toString cfg.refreshRateHz}
coordinate_frame = "${cfg.coordinateFrame}"
char_aspect_ratio = ${toString cfg.charAspectRatio}
pitch_scale = ${toString cfg.pitchScale}

[serial]
port = "${cfg.serialPort}"
baud = ${toString cfg.baudRate}
auto_record = ${boolToString cfg.autoRecord}

# Input mappings for extracting telemetry from Elodin-DB components
[inputs.position]
Expand Down Expand Up @@ -130,6 +133,40 @@ in {
'';
};

charAspectRatio = mkOption {
type = types.float;
default = 1.5;
description = ''
Character aspect ratio (height/width) for horizon line rendering.
HD OSD systems like Walksnail Avatar use ~12x18 pixel characters (ratio 1.5).
This compensates for non-square characters so the horizon tilt angle
matches the actual aircraft roll angle.

Common values:
- 1.5: Walksnail Avatar, DJI HD (default)
- 2.0: Standard SD analog OSD
- 1.0: Square characters (no compensation)
'';
};

pitchScale = mkOption {
type = types.float;
default = 5.0;
description = ''
Pitch scale in degrees per row for the artificial horizon.
Lower values = more sensitive pitch response (horizon moves more per degree).
Should be calibrated to match camera vertical FOV for accurate overlay.

Formula: pitch_scale ≈ camera_vertical_fov / osd_rows
Example: 90° VFOV / 18 rows ≈ 5° per row

Common values:
- 5.0: ~90° VFOV camera (default, good for Walksnail Avatar)
- 6.0: ~108° VFOV camera
- 4.0: ~72° VFOV camera (narrower FOV)
'';
};

serialPort = mkOption {
type = types.str;
default = "/dev/ttyTHS7";
Expand All @@ -142,6 +179,16 @@ in {
description = "Serial baud rate";
};

autoRecord = mkOption {
type = types.bool;
default = false;
description = ''
Automatically start DVR recording on the VTX when msp-osd starts.
Uses MSP2_COMMON_SET_RECORDING command (Walksnail Avatar compatible).
Only applies when running in serial mode.
'';
};

extraArgs = mkOption {
type = types.listOf types.str;
default = [];
Expand Down
14 changes: 13 additions & 1 deletion aleph/modules/udp-component-receive.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ in {
description = "Enable verbose logging";
};

timestampMode = mkOption {
type = types.enum ["sender" "local" "monotonic"];
default = "sender";
description = ''
Timestamp mode for received components:
- sender: Use timestamp from broadcaster (default)
- local: Use local wall-clock time
- monotonic: Use Linux monotonic clock
'';
};

extraArgs = mkOption {
type = types.listOf types.str;
default = [];
Expand All @@ -76,7 +87,8 @@ in {
ExecStart = let
filterArgs = concatMapStringsSep " " (f: "--filter ${f}") cfg.filter;
verboseArg = optionalString cfg.verbose "-v";
in "${cfg.package}/bin/udp-receive --db-addr ${cfg.dbAddr} --listen-port ${toString cfg.listenPort} ${filterArgs} ${verboseArg} ${concatStringsSep " " cfg.extraArgs}";
timestampArg = "--timestamp-mode ${cfg.timestampMode}";
in "${cfg.package}/bin/udp-receive --db-addr ${cfg.dbAddr} --listen-port ${toString cfg.listenPort} ${timestampArg} ${filterArgs} ${verboseArg} ${concatStringsSep " " cfg.extraArgs}";
Restart = "always";
RestartSec = 5;
StandardOutput = "journal";
Expand Down
12 changes: 10 additions & 2 deletions aleph/template/flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@
# refreshRateHz = 20.0;
# osdRows = 18;
# osdCols = 50;

# Horizon display calibration:
# charAspectRatio = 1.5; # Character height/width ratio (1.5 for Walksnail Avatar)
# pitchScale = 5.0; # Degrees per row (~camera_vfov / osd_rows)

# Auto-recording (Walksnail Avatar):
# autoRecord = true; # Start VTX recording when service starts
};

# UDP Component Broadcast service - broadcasts component data to other flight computers
Expand All @@ -145,10 +152,11 @@
# services.udp-component-receive = {
# enable = true;
# listenPort = 41235; # UDP port to listen on
# # autostart = true; # Set to false to configure but not auto-start
# # autostart = true; # Set to false to configure but not auto-start
# # filter = ["target.world_pos"]; # Only accept specific components (empty = all)
# # dbAddr = "127.0.0.1:2240"; # Elodin-DB address to write to
# # verbose = false; # Enable verbose logging
# # timestampMode = "sender"; # Timestamp mode: "sender", "local", or "monotonic"
# # verbose = false; # Enable verbose logging
# };
};
# sets up two different nixos systems default and installer
Expand Down
27 changes: 27 additions & 0 deletions fsw/msp-osd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ port = 2240
rows = 18
cols = 50
refresh_rate_hz = 20.0
char_aspect_ratio = 1.5 # Walksnail Avatar/DJI HD character aspect ratio
pitch_scale = 5.0 # Degrees per row (~90° VFOV camera)

[serial]
port = "/dev/ttyTHS7"
baud = 115200
auto_record = false # Set true to start VTX recording on service start

# Position from world_pos indices 4,5,6
[inputs.position]
Expand Down Expand Up @@ -155,6 +158,30 @@ For Walksnail Avatar connection on Aleph:
cargo run -- --mode serial --serial-port /dev/ttyTHS7
```

## Auto Recording

The msp-osd service can automatically start DVR recording on the Walksnail Avatar VTX when the service starts. This is useful for ensuring all flights are recorded without manual intervention.

To enable auto-recording, set `auto_record = true` in the `[serial]` section of your config:

```toml
[serial]
port = "/dev/ttyTHS7"
baud = 115200
auto_record = true
```

Or via NixOS module:

```nix
services.msp-osd = {
enable = true;
autoRecord = true;
};
```

This sends the `MSP2_COMMON_SET_RECORDING` command to the VTX during service initialization. The command is compatible with Walksnail Avatar VTX systems.

## Debugging on Aleph

When deployed via NixOS, the msp-osd service runs in serial mode by default. For debugging:
Expand Down
29 changes: 29 additions & 0 deletions fsw/msp-osd/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,39 @@ refresh_rate_hz = 20.0
# Use "ned" when connecting to real aviation hardware with standard conventions.
coordinate_frame = "enu"

# Character aspect ratio (height/width) for horizon line rendering.
# HD OSD systems like Walksnail Avatar use ~12x18 pixel characters (ratio 1.5).
# This compensates for non-square characters so the horizon tilt angle
# matches the actual aircraft roll angle.
#
# Common values:
# 1.5 - Walksnail Avatar, DJI HD (default)
# 2.0 - Standard SD analog OSD
# 1.0 - Square characters (no compensation)
char_aspect_ratio = 1.5

# Pitch scale in degrees per row for the artificial horizon.
# Lower values = more sensitive pitch response (horizon moves more per degree).
# Should be calibrated to match camera vertical FOV for accurate overlay.
#
# Formula: pitch_scale ≈ camera_vertical_fov / osd_rows
# Example: 90° VFOV / 18 rows ≈ 5° per row
#
# Common values:
# 5.0 - ~90° VFOV camera (default, good for Walksnail Avatar)
# 6.0 - ~108° VFOV camera
# 4.0 - ~72° VFOV camera (narrower FOV)
pitch_scale = 5.0

[serial]
port = "/dev/ttyTHS7"
baud = 115200

# Automatically start DVR recording on the VTX when msp-osd starts.
# Uses MSP2_COMMON_SET_RECORDING command (Walksnail Avatar compatible).
# Only applies when running in serial mode.
auto_record = false

# Input mappings define how to extract OSD telemetry from Elodin-DB components.
# Each mapping specifies a component name and the array indices for each value.

Expand Down
Loading