Skip to content

root3315/unisat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

189 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

UniSat β€” universal modular satellite platform

Verify AX.25 C tests Python tests Latest release Stars Open issues Coverage ARM License Python STM32 Platforms

Version 1.5.1 β€” Universal Platform (CanSat + CubeSat 1U–12U + HAB + Rocket + Drone + Rover)
Professional open-source flight software for any small-satellite class

UniSat key capabilities


60-second tour

git clone https://github.com/root3315/unisat.git && cd unisat
./scripts/verify.sh                                # full green pipeline (Docker)
cp mission_templates/cubesat_3u.json mission_config.json
make target-cubesat_3u                             # β†’ firmware/build-arm-cubesat_3u/
cd ground-station && streamlit run app.py          # β†’ http://localhost:8501

Prefer CanSat? Replace cubesat_3u with cansat_standard. Going to a specific competition? Pick the preset that matches its rulebook β€” e.g. cansat_uzcansat.json for πŸ‡ΊπŸ‡Ώ UzCanSat 2026. The firmware, flight-software, and ground-station all reconfigure themselves from mission_config.json.

Full step-by-step: docs/guides/USAGE_GUIDE.md Β· per-profile playbooks: docs/ops/ Β· full docs index: docs/README.md Β· mission templates: mission_templates/.


Overview

UniSat is a complete, modular flight-software platform that targets the full spectrum of student and research vehicles in a single codebase:

  • CanSat β€” minimal / standard / advanced (≀350 g, ≀500 g)
  • CubeSat β€” 1U, 1.5U, 2U, 3U, 6U, 12U
  • Suborbital rockets, high-altitude balloons, drones and rovers

The same STM32 firmware, the same Python flight controller, and the same Streamlit ground station reconfigure themselves automatically from mission_config.json. A form-factor registry enforces mass/volume/power envelopes (CDS Rev. 14 for CubeSats, ESA CanSat regulations for CanSats), and a deterministic feature-flag resolver gates every optional subsystem so the build contains only what the mission actually needs.


ΠžΠ±Π·ΠΎΡ€ (Русский)

UniSat β€” ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Π°Ρ программная ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°, которая ΠΈΠ· ΠΎΠ΄Π½ΠΎΠ³ΠΎ рСпозитория запускаСт:

  • CanSat β€” minimal / standard / advanced (≀350 Π³ ΠΈ ≀500 Π³);
  • CubeSat β€” 1U, 1.5U, 2U, 3U, 6U, 12U;
  • ΡΡƒΠ±ΠΎΡ€Π±ΠΈΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π°ΠΊΠ΅Ρ‚Ρ‹, стратосфСрныС Π·ΠΎΠ½Π΄Ρ‹, Π‘ΠŸΠ›Π ΠΈ Ρ€ΠΎΠ²Π΅Ρ€Ρ‹.

Одна ΠΈ Ρ‚Π° ΠΆΠ΅ ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° STM32, ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΏΠΎΠ»Ρ‘Ρ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€ Π½Π° Python ΠΈ ΠΎΠ΄Π½Π° ΠΈ Ρ‚Π° ΠΆΠ΅ назСмная станция Π½Π° Streamlit сами ΠΏΠΎΠ΄ΡΡ‚Ρ€Π°ΠΈΠ²Π°ΡŽΡ‚ΡΡ ΠΏΠΎΠ΄ Π°ΠΊΡ‚ΠΈΠ²Π½ΡƒΡŽ миссию Ρ‡Π΅Ρ€Π΅Π· mission_config.json. РССстр Ρ„ΠΎΡ€ΠΌ-Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΎΠ² провСряСт массу/ΠΎΠ±ΡŠΡ‘ΠΌ/энСргСтику (CDS Rev. 14 для CubeSat, ΠΏΡ€Π°Π²ΠΈΠ»Π° ESA для CanSat), Π° Π΄Π΅Ρ‚Π΅Ρ€ΠΌΠΈΠ½ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Ρ€Π΅Π·ΠΎΠ»Π²Π΅Ρ€ Ρ„ΠΈΡ‡-Ρ„Π»Π°Π³ΠΎΠ² Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚Π΅ подсистСмы, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΡƒΠΆΠ½Ρ‹ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌΡƒ Π°ΠΏΠΏΠ°Ρ€Π°Ρ‚Ρƒ.


πŸ”’ What's new in v1.2.0 β€” TRL-5 hardening

Version 1.2.0 landed an eight-phase hardening sweep (75 commits on feat/trl5-hardening) that promotes UniSat from "competition- ready template" to TRL-5-capable software platform. Full details in CHANGELOG.md β€” summary:

Phase 1 β€” Real ARM target build

  • STM32F446RE LD script, startup.s, SystemInit/clock at 168 MHz
  • FreeRTOS kernel + CMSIS-RTOSv2 + HAL autodetect in CMake
  • make setup-all && make target produces a real .elf
  • Verified footprint: 31.6 KB flash (6 %) / 36.3 KB RAM (28 %)

Phase 2 β€” Security (T1 + T2 both closed)

  • T1 (injection): HMAC-SHA256 + constant-time verify
  • T2 (replay): 32-bit counter + 64-bit sliding-window bitmap
  • Persistent key store (A/B flash slots + CRC + monotonic gen)
  • Python CounterSender β€” thread-safe ground-side pair

Phase 3 β€” FDIR (NASA-style three-tier)

  • 12 fault IDs + 60s escalation window + 6-level severity ladder
  • Advisor (fdir.c) / commander (mode_manager.c) split (ADR-005)
  • Persistent fault log in .noinit SRAM β€” survives warm reboot

Phase 4 β€” Tboard + mission scenario

  • Live TMP117 reading in beacon bytes 14-15 (was zero-padded)
  • End-to-end mission lifecycle test (startup β†’ nominal β†’ safe β†’ recovery) + 48-hour soak harness

Phase 5 β€” Quality gates

  • make cppcheck (CI-blocking) + MISRA advisory
  • make coverage β€” 85.3 % C lines
  • make sanitizers β€” ASAN + UBSAN clean
  • cmake -DSTRICT=ON β€” -Werror -Wshadow -Wconversion clean

Phase 6 β€” Documentation (CDR-level)

  • SRS with 44 REQ + traceability CSV
  • 8 ADRs for architectural decisions
  • HIL test plan + characterization templates
  • Threat model v2 with T1+T2 closed

Phase 7 β€” Python + release plumbing

  • make coverage-py β€” 85.15 % Python lines (gate β‰₯ 80 % MUST)
  • make lint-py β€” mypy strict clean across 21 files
  • make sbom β€” auto-generated SPDX bill of materials
  • make pin-docker β€” release-engineering digest pin

Phase 8 β€” Final polish

  • ARM build fully verified end-to-end
  • Zero warnings in any build profile
  • Total tests: 27 C + 329 Python = 356 checks
  • Migrated MIT β†’ Apache 2.0 for patent-grant protection (Β§3)

Test + coverage progression

Before (v1.1.0) After (v1.2.0)
C test executables 16 27
Python tests 34 329
C line coverage not measured 85.3 %
Python line coverage not measured 85.15 %
ARM target .elf not verified 6 % flash / 28 % RAM
ADRs 2 8
Quality gates 1 9 (all green)
License MIT Apache 2.0

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    GROUND STATION (Python/Streamlit)         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚Dashboard β”‚ β”‚Telemetry β”‚ β”‚  Orbit   β”‚ β”‚Command Center β”‚  β”‚
β”‚  β”‚          β”‚ β”‚  Charts  β”‚ β”‚ Tracker  β”‚ β”‚  (HMAC-AUTH)  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚ UHF 437 MHz / S-band 2.4 GHz
                          β”‚ AX.25 / CCSDS Protocol
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      CUBESAT (1U-6U)                         β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚         FLIGHT CONTROLLER (Raspberry Pi Zero 2 W)     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚
β”‚  β”‚  β”‚Camera  β”‚ β”‚Orbit   β”‚ β”‚Health  β”‚ β”‚  Scheduler   β”‚  β”‚   β”‚
β”‚  β”‚  β”‚Handler β”‚ β”‚Predict β”‚ β”‚Monitor β”‚ β”‚  (asyncio)   β”‚  β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                         β”‚ UART                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              OBC FIRMWARE (STM32F4 + FreeRTOS)        β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚
β”‚  β”‚  β”‚ADCS  β”‚ β”‚EPS   β”‚ β”‚COMM  β”‚ β”‚GNSS  β”‚ β”‚Telemetry β”‚  β”‚   β”‚
β”‚  β”‚  β”‚B-dot β”‚ β”‚MPPT  β”‚ β”‚UHF   β”‚ β”‚u-bloxβ”‚ β”‚  CCSDS   β”‚  β”‚   β”‚
β”‚  β”‚  β”‚Sun   β”‚ β”‚BatMgrβ”‚ β”‚S-bandβ”‚ β”‚      β”‚ β”‚          β”‚  β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚   SOLAR PANELS     β”‚  β”‚      PAYLOAD (swappable)      β”‚  β”‚
β”‚  β”‚   GaAs 29.5% eff.  β”‚  β”‚  Radiation / Camera / IoT /   β”‚  β”‚
β”‚  β”‚   6 panels (3U)    β”‚  β”‚  Magnetometer / Spectrometer   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Features

Subsystem Description Technology
OBC Firmware Real-time task management, watchdog, safe mode STM32F4 + FreeRTOS (C)
ADCS B-dot detumbling, sun/nadir/target pointing Quaternion math, PID control
EPS MPPT solar charging, battery management Perturb & Observe algorithm
Communication UHF 9600 bps + S-band 256 kbps AX.25 v2.2 full (streaming decoder, bit-stuffing, CRC-16/X.25, Β§3.12 addresses) + CCSDS Space Packet + HMAC-SHA256
Flight Software Async mission control, imaging, orbit prediction Python 3.11+ asyncio
Ground Station 10-page dashboard with real-time telemetry Streamlit + Plotly
Simulation Orbit, power, thermal, link budget Python scientific stack
Configurator Web-based mission builder with validation Streamlit
Payloads 5 swappable payload modules Plugin architecture

Quick Start

1. Clone the repository

git clone https://github.com/root3315/unisat.git
cd unisat

2. Install dependencies

chmod +x scripts/setup.sh
./scripts/setup.sh

3. Run the ground station

cd ground-station
pip install -r requirements.txt
streamlit run app.py

4. Run simulation

cd simulation
pip install -r requirements.txt
python mission_analyzer.py

ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ΅ руководство: docs/guides/USAGE_GUIDE.md β€” ΠΎΡ‚ Π²Ρ‹Π±ΠΎΡ€Π° Ρ‚ΠΈΠΏΠ° миссии (CanSat / CubeSat / HAB / Rocket / Drone) Π΄ΠΎ ΠΏΠΎΠ΄Π°Ρ‡ΠΈ Π½Π° конкурс.

Π§Ρ‚ΠΎ Π΅Ρ‰Ρ‘ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ: docs/project/GAPS_AND_ROADMAP.md β€” чСстный статус, ΠΏΡ€ΠΈΠΎΡ€ΠΈΡ‚ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ список ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹Ρ… Π·Π°Π΄Π°Ρ‡.

5. End-to-end AX.25 SITL demo (one command)

# Requires Docker Desktop running. No local gcc/cmake/pytest needed.
./scripts/verify.sh

That script builds the unisat-ci Docker image once (~30 s), then runs the full green pipeline inside it: firmware host build β†’ ctest β†’ pytest β†’ end-to-end SITL beacon demo. Expected final line: βœ“ UniSat green. Ready to submit.

For more granular control:

  • make all β€” build + tests
  • make ci β€” same, inside Docker
  • make demo β€” just the SITL beacon path
  • make test-c / make test-py β€” split suites
  • make help β€” list all targets

Project Status

TRL-5 hardening: all 6 phases on feat/trl5-hardening closed.

Check Status
Firmware host build (all subsystems) βœ… clean (unisat_core)
Firmware target build (STM32F446RE .elf/.bin/.hex) βœ… verified: 31.6 KB flash (6%) / 36.3 KB RAM (28%) under 90% budget
C unit tests (ctest) βœ… 28 / 28 passing (100+ sub-tests)
Python tests (pytest, full suite) βœ… 420 passing β€” 262 flight-software + 82 ground-station + 57 simulation + 19 configurator
Python coverage (MUST gate) βœ… 85.15 % (make coverage-py, β‰₯ 80 % enforced)
Streamlit page import smoke βœ… 12/13 passing (1 skipped β€” streamlit not installed)
Universal platform (v1.3.1) βœ… 14 form factors: CanSat min/std/adv + CubeSat 1U/1.5U/2U/3U/6U/12U + rocket/HAB/drone/rover/custom
SBOM (SPDX) βœ… make sbom generates docs/sbom/sbom-summary.md
FreeRTOS autodetect in CMake βœ… make setup-freertos + make setup-all
AX.25 golden vectors cross-validation βœ… 28/28 byte-identical C ↔ Python
SHA-256 FIPS 180-4 oracle βœ… "abc" + "" canonical digests
HMAC-SHA256 RFC 4231 vectors βœ… Β§4.2 + Β§4.3 on both C and Python
End-to-end SITL demo βœ… C encoder β†’ TCP β†’ Python decoder
E2E mission scenario (startup β†’ nominal β†’ safe) βœ… flight-software/tests/test_mission_e2e.py
Long-soak harness (48 h gated via UNISAT_SOAK_SECONDS) βœ… test_long_soak.py
Driver reality audit βœ… all 9 drivers verified real (incl. BoardTemp)
Threat T1 (command injection) βœ… HMAC dispatcher
Threat T2 (replay) βœ… 32-bit counter + 64-bit sliding window
Persistent key store (A/B + CRC + rotation) βœ… 10/10 tests
Boot-time key_store β†’ dispatcher wiring in main.c βœ… 4/4 integration tests
Python counter-aware HMAC frame builder (CounterSender) βœ… 22/22 pytest
FDIR fault advisor + watchdog integration βœ… 9/9 tests, 12 fault IDs
FDIR mode supervisor (SAFE/DEGRADED/REBOOT wiring) βœ… 9/9 tests
Persistent fault log (.noinit, survives warm reboot) βœ… 6/6 tests
Tboard (TMP117) facade in beacon bytes 14–15 βœ… 6/6 tests
cppcheck static-analysis gate βœ… clean (make cppcheck)
Line coverage (C) βœ… 85.3 % / functions 84.0 % (make coverage)
ASAN + UBSAN under ctest βœ… 28/28 clean (make sanitizers)
STRICT mode (-Werror -Wshadow -Wconversion) βœ… 28/28 clean (cmake -DSTRICT=ON)
ADRs for architectural decisions βœ… 8 ADRs under docs/adr/
Full SRS + traceability CSV βœ… docs/requirements/SRS.md
HIL test plan + characterization templates βœ… docs/testing + docs/characterization
Requirement traceability (AX.25 subset) βœ… auto-generated (docs/verification/ax25_trace_matrix.md)

Deferred (not TRL-5 blockers) β€” see docs/project/GAPS_AND_ROADMAP.md: Streamlit↔AX.25 live bridge, CC1125 radio config doc, MISRA backlog cleanup (~1000 Rule 8.7/10.x style deviations).

6. Build firmware manually (optional)

If you don't want to use Docker:

cd firmware
cmake -B build -S .
cmake --build build
ctest --test-dir build --output-on-failure

Cross-compile for STM32F446 (requires arm-none-eabi-gcc):

cd firmware
cmake -B build-arm -S . -DCMAKE_TOOLCHAIN_FILE=arm.cmake
cmake --build build-arm
# Output: build-arm/unisat_firmware.{elf,bin,hex}

Supported Form Factors

UniSat supported form factors

UniSat's form-factor registry is the single source of truth for every supported class. Every envelope in the tables below is enforced at runtime; each row also ships a mission template, a hardware BOM, a compile-time firmware profile, and a dedicated ops guide.

Form factor Max mass Dimensions (mm) ADCS tiers Typical radios BOM Ops guide
CanSat minimal 350 g Ø66 Γ— 115 cyl. none ISM 433/868/915, LoRa cansat_minimal.csv cansat_minimal.md
CanSat standard 500 g Ø68 Γ— 80 cyl. none ISM, LoRa cansat_standard.csv cansat_standard.md
CanSat advanced 500 g Ø68 Γ— 115 cyl. passive-spin ISM, UHF amateur cansat_advanced.csv cansat_advanced.md
CubeSat 1U 2.0 kg 100 Γ— 100 Γ— 113.5 passive-magnetic VHF/UHF amateur cubesat_1u.csv cubesat_1u.md
CubeSat 1.5U 3.0 kg 100 Γ— 100 Γ— 170.25 magnetorquer UHF amateur cubesat_1_5u.csv cubesat_1_5u.md
CubeSat 2U 4.0 kg 100 Γ— 100 Γ— 227.0 magnetorquer + sensors UHF + optional S-band cubesat_2u.csv cubesat_2u.md
CubeSat 3U ← TRL-5 ref 6.0 kg 100 Γ— 100 Γ— 340.5 reaction wheels 3-axis UHF + S-band + X-band cubesat_3u.csv cubesat_3u.md
CubeSat 6U 12.0 kg 226.3 Γ— 100 Γ— 366 star tracker fine-pointing UHF + S + X + Ka cubesat_6u.csv cubesat_6u.md
CubeSat 12U 24.0 kg 226.3 Γ— 226.3 Γ— 366 star tracker + propulsion UHF + S + X + Ka + optical cubesat_12u.csv cubesat_12u.md
Rocket payload 10 kg Ø100 Γ— 300 cyl. none / passive-spin ISM, UHF, S-band β€” rocket_avionics.md
HAB payload 4 kg 150 Γ— 150 Γ— 150 none ISM, APRS, UHF amateur β€” hab_payload.md
Small drone (UAS) 5 kg 500 Γ— 500 Γ— 200 IMU attitude control ISM 2.4 GHz β€” drone.md

Mission templates live in mission_templates/ β€” copy the one you want into mission_config.json and the flight controller, firmware, and ground station all follow along. Profile-selection flowchart + trade-offs in docs/ops/README.md.

Picking a profile

# 1. Choose a template (CanSat, CubeSat 1U … 12U, rocket, HAB, drone).
cp mission_templates/cubesat_3u.json mission_config.json

# 2. Build the matching firmware image.
make target-cubesat-3u       # β†’ firmware/build-arm-cubesat-3u/

# 3. Launch the flight controller and ground station β€” they read
#    mission_config.json and configure themselves automatically.
cd flight-software && python3 flight_controller.py
cd ground-station && streamlit run app.py

Build every profile at once with make target-all-profiles (produces nine separate build-arm-<profile>/ trees).

Feature flags

mission_config.json accepts a top-level features block whose keys are defined in flight-software/core/feature_flags.py. The resolver combines explicit overrides with platform / form-factor / ADCS-tier / radio-band gates so the final enabled set is deterministic and logged. Examples:

"features": {
    "orbit_predictor": true,         // CubeSat-only β†’ disabled for CanSat
    "reaction_wheels": true,         // requires 2U+ and an RW tier
    "star_tracker":   false,         // explicit disable always wins
    "descent_controller": true,      // CanSat / rocket / HAB only
    "parachute_pyro": true,
    "s_band_radio":   true           // requires s_band radio configured
}

Competition Adaptation

Ready-to-submit adaptations for aerospace competitions. Detailed per-profile guides live in docs/ops/ (one file per form factor) + short form in USAGE_GUIDE.md Β§7.

Competition Template Highlights Ops guide Prep time
CanSat (beginner) cansat_minimal.json RP2040, ISM 433 MHz, ≀350 g cansat_minimal.md 1 evening
πŸ‡ΊπŸ‡Ώ UzCanSat 2026 (cmspace.uz) cansat_uzcansat.json 1 Hz telemetry, buzzer locator, camera 640Γ—480 @ 30 fps β€” preset full compliant with cmspace.uz rulebook UZCANSAT_COMPLIANCE.md 2–3 days
ESERO / national CanSat cansat_standard.json Parachute, IMU, Ø68 Γ— 80 mm, ≀500 g cansat_standard.md 2–3 days
NASA CanSat cansat_advanced.json Pyro deploy, camera, guided descent cansat_advanced.md 1 week
CubeSat Design cubesat_3u.json 3U LEO, CDR docs, HMAC auth cubesat_3u.md 1 week
CubeSat 6U/12U research cubesat_6u.json / cubesat_12u.json X/Ka-band, propulsion slot cubesat_6u.md 2–3 weeks
NASA Space Apps Any CubeSat + NDVI Earth observation cubesat_6u.md 48 h
IREC / SA Cup rocket rocket_competition.json Dual-deploy, HMAC telemetry rocket_avionics.md 2–3 days
HAB flight hab_standard.json GNSS + camera hab_payload.md 1 day
UAV survey drone_survey.json Mission planner drone.md 1–2 days

Also: COMPETITION_GUIDE.md (short form), docs/ops/README.md (profile-selection flowchart).


Project Structure

unisat/
β”œβ”€β”€ firmware/             # STM32F446 firmware (C11 + FreeRTOS)
β”‚   β”œβ”€β”€ stm32/Core/       #   OBC, COMM, GNSS, CCSDS, telemetry,
β”‚   β”‚                     #   command_dispatcher (HMAC-auth)
β”‚   β”œβ”€β”€ stm32/Drivers/    #   9 sensor drivers + AX25 + Crypto +
β”‚   β”‚                     #   VirtualUART (SITL TCP shim)
β”‚   β”œβ”€β”€ stm32/ADCS/       #   B-dot, quaternion, sun/target pointing
β”‚   β”œβ”€β”€ stm32/EPS/        #   MPPT, battery manager
β”‚   └── tests/            #   28 Unity test targets
β”œβ”€β”€ flight-software/      # Python async flight controller (RPi Zero 2 W)
β”‚   β”œβ”€β”€ core/             #   form_factors.py, feature_flags.py, mission_types.py
β”‚   └── tests/            #   262 pytest incl. e2e + soak + hypothesis
β”œβ”€β”€ ground-station/       # Streamlit UI + AX.25 CLI + HMAC tooling
β”‚   β”œβ”€β”€ utils/ax25.py     #   AX.25 v2.2 Python mirror
β”‚   β”œβ”€β”€ utils/hmac_auth.py#   HMAC-SHA256 mirror (RFC 4231)
β”‚   β”œβ”€β”€ utils/profile_gate.py #  hides orbit/image/ADCS pages by profile
β”‚   β”œβ”€β”€ cli/              #   ax25_listen / ax25_send TCP tools
β”‚   └── tests/            #   82 pytest incl. hypothesis + fuzz
β”œβ”€β”€ simulation/           # 10 simulators (orbit, power, thermal, link) β€” 57 tests
β”œβ”€β”€ configurator/         # Web-based mission configurator + BOM gen β€” 19 tests
β”œβ”€β”€ hardware/
β”‚   β”œβ”€β”€ bom/by_form_factor/  # 7 per-class BOMs with real masses
β”‚   └── kicad/              # 4 KiCad boards (OBC, EPS, Comm, Sensor)
β”œβ”€β”€ payloads/             # 5 swappable payload templates
β”œβ”€β”€ mission_templates/    # 8 ready-to-use presets (CanSat min/std/adv + CubeSat 1U-12U)
β”œβ”€β”€ tests/golden/         # Shared AX.25 test vectors (C + Python)
β”œβ”€β”€ docs/                 # 25+ md docs (USAGE_GUIDE, TECHNICAL_DOC,
β”‚                         # ADRs, threat model, tutorials, verification)
β”œβ”€β”€ docker/Dockerfile.ci  # Reusable CI image (cmake + pytest baked)
β”œβ”€β”€ scripts/verify.sh     # One-command reproducibility
β”œβ”€β”€ Makefile              # make all / test / demo / ci / help
β”œβ”€β”€ CHANGELOG.md          # Semantic-versioned history
└── README.md             # This file

Documentation

Full index: docs/README.md β€” every doc in the repo, grouped by purpose.

Start here

Per-profile operations guides (docs/ops/)

One file per form factor covering setup β†’ build β†’ bench test β†’ flight β†’ post-flight:

Design & architecture (docs/design/)

Quantitative budgets (docs/budgets/, 3U reference)

Per-profile envelopes (mass / volume / power) are in flight-software/core/form_factors.py; per-class BOMs are under hardware/bom/by_form_factor/.

Reference (docs/reference/)

Architecture decisions (docs/adr/ β€” 8 ADRs)

Hardware (docs/hardware/)

Verification, testing, reliability

Project state & regulatory (docs/project/)

Tutorials, operations, SBOM, diagrams

Contributing & security


Testing

One command:

./scripts/verify.sh   # Docker-based, no local toolchain needed

Via Makefile:

make all              # build + test (C + Python)
make test-c           # ctest only (28 targets, 100+ sub-tests)
make test-py          # pytest only (420 tests across all 4 Python packages)
make demo             # end-to-end SITL AX.25 beacon demo
make help             # list all targets

Quality gates:

# C firmware
make cppcheck         # static-analysis gate (zero issues)
make cppcheck-strict  # + MISRA-C:2012 advisory report
make coverage         # lcov html report (85.3 % lines)
make sanitizers       # ASAN + UBSAN under ctest

# Python
make coverage-py      # pytest + coverage (β‰₯ 50 % MUST gate, 80 % SHOULD)
make lint-py          # mypy type check on flight-software

# supply-chain
make sbom             # SPDX bill-of-materials under docs/sbom/

STM32 target (Phase 1):

make setup-all        # fetch STM32Cube HAL + FreeRTOS kernel (one-time)
make target           # cross-compile .elf / .bin / .hex
make size             # per-section flash / RAM usage
make flash            # st-flash to Nucleo-F446RE

Manual:

cd firmware && cmake -B build -S . && cmake --build build
ctest --test-dir build --output-on-failure
cd ../ground-station && python -m pytest tests/test_ax25.py -v

Contributing

See CONTRIBUTING.md for guidelines on how to contribute to UniSat.


License

This project is licensed under the Apache License, Version 2.0 β€” see LICENSE and NOTICE for the full terms and the third-party attribution summary.

License history: the project was initially published under MIT (2026-02-15 β€” 2026-04-18) and migrated to Apache-2.0 on 2026-04-18 for its patent-grant clause (Β§3) and the defensive-termination language (retaliation against a patent suit terminates the aggressor's patent licence). Copies obtained during the MIT window stay MIT-licensed; new releases from 2026-04-18 onward are Apache-2.0 only.


Acknowledgments

  • CCSDS (Consultative Committee for Space Data Systems) for protocol standards
  • FreeRTOS for the real-time operating system
  • SGP4 algorithm authors for orbit prediction
  • CubeSat Design Specification (CalPoly) for mechanical standards