diff --git a/.github/workflows/build-deb.yml b/.github/workflows/build-deb.yml index d2bb905..71a38ac 100644 --- a/.github/workflows/build-deb.yml +++ b/.github/workflows/build-deb.yml @@ -39,6 +39,15 @@ jobs: runner: ubuntu-22.04-arm container: "debian:trixie" extra_deps: "" + # Modalix eLxr 12 (aria) is Debian 12 / Python 3.11 class. No public eLxr + # container on GH runners yet — build in debian:bookworm and name the + # package ark-os-modalix-bookworm for install testing; prefer a native + # aarch64 eLxr 12 host for ark-os-modalix-aria release builds. + - platform: modalix + codename: bookworm + runner: ubuntu-22.04-arm + container: "debian:bookworm" + extra_deps: "" # Build each platform on a host whose OS matches the target so the bundled venv # and natively-compiled binaries are ABI-compatible. The venv is created with # `python3 -m venv --copies`, which ships the interpreter but resolves the stdlib @@ -47,6 +56,7 @@ jobs: # - jetson: ubuntu-22.04-arm natively (Jammy / Python 3.10 = JetPack 6 rootfs) # - pi: a debian:bookworm container (Debian 12 / Python 3.11 = Raspberry Pi OS Bookworm) # - pi: a debian:trixie container (Debian 13 / Python 3.13 = Raspberry Pi OS Trixie) + # - modalix: debian:bookworm container (Python 3.11 ≈ eLxr 12 / aria) # The container runs on the same arm64 host. Each leg's `codename` (the host's OS # release) is part of the package name (ark-os--); supporting a # new release is one more leg here plus an entry in build.sh's BASELINES table. diff --git a/README.md b/README.md index 80bfd21..eaf2f3c 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,10 @@ ARK-OS is a collection of software services and tools for drones. These services provide essential features such as mavlink routing, video streaming, automatic flight log upload, flight controller firmware updating, network RTK corrections, and more. #### Supported targets -- **ARK Jetson PAB Carrier / PAB Carrier V3**
https://arkelectron.com/product/ark-jetson-pab-carrier/ -- **ARK Just a Jetson**
https://arkelectron.com/product/ark-just-a-jetson/ +- **ARK Jetson PAB Carrier / PAB Carrier V3** (Jetson Orin NX/Nano)
https://arkelectron.com/product/ark-jetson-pab-carrier/ +- **ARK Jetson PAB Carrier V3 + SiMa Modalix SoM** (eLxr) — platform `modalix` (see `platform/modalix/README.md`) +- **ARK Just a Jetson** (Jetson Orin NX/Nano)
https://arkelectron.com/product/ark-just-a-jetson/ +- **ARK Just a Jetson + SiMa Modalix SoM** (eLxr) — platform `modalix` - **ARK Pi6X Flow**
https://arkelectron.com/product/ark-pi6x-flow/ - **ARK Just a Pi**
https://arkelectron.com/product/ark-just-a-pi/ @@ -17,6 +19,7 @@ ssh @.local |--------|----------|----------| | jetson | jetson | jetson | | pi | pi | pi6x | +| sima | edgeai | modalix (SiMa eLxr / JAJ+Modalix) | Connect to your WiFi network using Network Manager ``` @@ -58,6 +61,19 @@ sudo apt install ./ark-os-jetson-jammy__arm64.deb sudo apt install -y python3-pip && sudo pip3 install "jetson-stats==" ``` +#### Modalix (SiMa eLxr 12 / JAJ or PAB V3 + Modalix) +Flash the SiMa eLxr base image first (see meta-ark-simaai bring-up), then install the +`modalix` package as user **`sima`**. No jetson-stats. DDS defaults to **UDP Ethernet +:8888** (not Telem2 UART); change it from the Services tab. Build on arm64 Debian 12 +or eLxr 12: + +``` +./packaging/build.sh modalix --version=X.Y.Z +sudo ./packaging/install_ark_os.sh --platform=modalix ./ark-os-modalix-bookworm_X.Y.Z_arm64.deb +``` + +Details: [`platform/modalix/README.md`](platform/modalix/README.md). + #### Raspberry Pi Identical, replacing `ark-os-jetson-jammy` with `ark-os-pi-trixie` for Raspberry Pi OS Trixie (Debian 13) — use `ark-os-pi-bookworm` on Debian 12. No jetson-stats step: ``` @@ -128,7 +144,7 @@ The package installs the services below as system-level [systemd services](https This service enables mavlink-router to route mavlink packets from the flight controller USB port to user defined UDP endpoints. You can add and remove endpoints using the service configuration editor in the UI. **dds-agent.service**
-The dds-agent service bridges the PX4 uORB and ROS2 topics. The bridged topics are defined in PX4 Firmware and can be [found here](https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/uxrce_dds_client/dds_topics.yaml). The **dds-agent** runs the [micro-xrce-dds-agent](https://github.com/eProsima/Micro-XRCE-DDS-Agent) over the high speed serial connection between flight controller and Companion. +The dds-agent service bridges the PX4 uORB and ROS2 topics. The bridged topics are defined in PX4 Firmware and can be [found here](https://github.com/PX4/PX4-Autopilot/blob/main/src/modules/uxrce_dds_client/dds_topics.yaml). The **dds-agent** runs the [micro-xrce-dds-agent](https://github.com/eProsima/Micro-XRCE-DDS-Agent). Transport is configured from the Services tab (`dds-agent.toml`): **serial** (device + baud rate) or **ethernet** / **tcp** (port + companion IP). Defaults are serial Telem2 on Jetson (`/dev/ttyTHS1`, 3 Mbaud) and Pi (`/dev/ttyAMA4`), and UDP Ethernet port **8888** on Modalix (UART1/Telem2 is not usable on that SoM). **logloader.service**
This service downloads log files from the SD card of the flight controller via MAVLink and optionally uploads them to [PX4 Flight Review](https://review.px4.io/). Driven from the web UI's **Logs** page. diff --git a/frontend/src/pages/SystemPage.vue b/frontend/src/pages/SystemPage.vue index 0b80266..1f72154 100644 --- a/frontend/src/pages/SystemPage.vue +++ b/frontend/src/pages/SystemPage.vue @@ -33,8 +33,9 @@ :data="platformData" /> - + -
+
- {{ formatDiskSize(diskTotal) }} Total - {{ formatDiskSize(diskAvailable) }} Available + {{ formatDiskSize(disk.total) }} Total + + {{ formatDiskSize(disk.available) }} Available + + Not mounted
@@ -145,17 +153,34 @@ export default { 'Unknown'; }, + deviceType() { + return this.systemInfo?.device_type || 'generic'; + }, + + isJetson() { + return this.deviceType === 'jetson'; + }, + + showLibrariesCard() { + // NVIDIA CUDA stack is Jetson-only; hide empty "Not available" wall on Modalix/Pi + return this.isJetson; + }, + hardwareData() { const hw = this.systemInfo?.hardware; if (!hw) return { 'Status': 'Data unavailable' }; - return { + const data = { 'Model': hw.model || 'Not available', 'Module': hw.module || 'Not available', - 'Serial': hw.serial_number || 'Not available', - 'L4T': hw.l4t || 'Not available', - 'JetPack': hw.jetpack || 'Not available' + 'Serial': hw.serial_number || 'Not available' }; + // L4T / JetPack only on real Jetson + if (this.isJetson) { + data['L4T'] = hw.l4t || 'Not available'; + data['JetPack'] = hw.jetpack || 'Not available'; + } + return data; }, platformData() { @@ -173,8 +198,9 @@ export default { librariesData() { const libs = this.systemInfo?.libraries; - - // Always show these fields, even if not available + if (!this.isJetson) { + return {}; + } return { 'CUDA': libs?.cuda || 'Not available', 'OpenCV': libs?.opencv || 'Not available', @@ -190,19 +216,32 @@ export default { const data = {}; const power = this.systemInfo?.power; - // Power information (primarily for Jetson) - data['Power Mode'] = power?.nvpmodel || 'Not available'; - data['Jetson Clocks'] = power?.jetson_clocks || 'Not available'; - data['Power Draw'] = power?.total ? `${(power.total / 1000).toFixed(2)} W` : 'Not available'; - - // Primary temperatures - const temps = this.systemInfo?.temperature || power?.temperature; - if (temps) { + if (this.isJetson) { + data['Power Mode'] = power?.nvpmodel || 'Not available'; + data['Jetson Clocks'] = power?.jetson_clocks || 'Not available'; + } + // Rail voltage / current when provided (Modalix INA238) + if (power?.voltage != null && Number(power.voltage) > 0) { + data['Voltage'] = `${Number(power.voltage).toFixed(2)} V`; + } + if (power?.current != null && Number.isFinite(Number(power.current))) { + data['Current'] = `${Number(power.current).toFixed(3)} A`; + } + // Jetson jtop and Modalix INA238 both use power.total in milliwatts + data['Power Draw'] = + power?.total && power.total > 0 + ? `${(power.total / 1000).toFixed(2)} W` + : 'Not available'; + + // Primary temperatures (Jetson has cpu/gpu; Modalix may have ina238 die temp) + const temps = this.systemInfo?.temperature || power?.temperature || {}; + if (this.isJetson) { data['CPU Temp'] = temps.cpu ? `${temps.cpu.toFixed(1)}°C` : 'Not available'; data['GPU Temp'] = temps.gpu ? `${temps.gpu.toFixed(1)}°C` : 'Not available'; - } else { - data['CPU Temp'] = 'Not available'; - data['GPU Temp'] = 'Not available'; + } else if (temps.ina238 != null) { + data['PMIC Temp'] = `${Number(temps.ina238).toFixed(1)}°C`; + } else if (temps.cpu != null) { + data['CPU Temp'] = `${Number(temps.cpu).toFixed(1)}°C`; } return data; @@ -301,6 +340,28 @@ export default { diskAvailable() { const disk = this.systemInfo?.resources?.disk || this.systemInfo?.disk; return disk?.available || 0; + }, + + /** All physical disks (eMMC + NVMe etc.); fall back to root-only disk field. */ + diskVolumes() { + const disks = this.systemInfo?.resources?.disks; + if (Array.isArray(disks) && disks.length > 0) { + return disks; + } + const disk = this.systemInfo?.resources?.disk || this.systemInfo?.disk; + if (!disk) return []; + return [ + { + name: 'Disk', + device: '/', + mountpoint: '/', + total: disk.total || 0, + used: disk.used || 0, + available: disk.available || 0, + percent: disk.percent || 0, + model: '' + } + ]; } }, @@ -406,7 +467,16 @@ export default { formatDiskSize(sizeInGB) { if (!sizeInGB) return '0 GB'; + if (sizeInGB >= 100) return `${sizeInGB.toFixed(0)} GB`; return `${sizeInGB.toFixed(1)} GB`; + }, + + diskLabel(disk) { + if (!disk) return 'Disk'; + const name = disk.name || disk.device || 'Disk'; + if (disk.mountpoint === '/') return `${name} (/)`; + if (disk.mountpoint) return `${name} (${disk.mountpoint})`; + return name; } } } @@ -522,6 +592,11 @@ export default { font-weight: 500; } +.disk-unmounted { + font-style: italic; + color: #999; +} + .temp-scroll-container { max-height: 120px; overflow-y: auto; diff --git a/frontend/src/pages/components/TomlEditor.vue b/frontend/src/pages/components/TomlEditor.vue index 4d1bcd7..3474bfa 100644 --- a/frontend/src/pages/components/TomlEditor.vue +++ b/frontend/src/pages/components/TomlEditor.vue @@ -33,6 +33,7 @@ +

{{ fieldHelpText(key) }}