A complete, portable satellite flight software stack built from first principles, together with the simulation and ground tooling needed to actually fly it. Written to be read: every design decision that matters is explained in the file where it is made, including the ones that were rejected and why.
Status: Phase 1 of 7. The telemetry, tracking and command chain works end to end — real CCSDS Space Packets, real ECSS PUS services, a real ground station. Attitude determination and control, power, mode management and fault handling are scheduled and scaffolded, not yet implemented. The roadmap in docs/ROADMAP.md says exactly what exists and what does not.
┌──────────────────────────────────────┐
OpenC3 COSMOS │ │ telemetry screens,
or pyground ──▶│ CCSDS Space Packets over TCP │◀── limits, command
│ ECSS-E-ST-70-41C PUS services │ scripting
└───────────────────┬──────────────────┘
│
┌───────────────────▼──────────────────┐
│ FLIGHT SOFTWARE (C++17, no heap, │
│ no exceptions, no OS dependency) │
│ │
│ TT&C · ADCS · EPS · modes · FDIR │
│ ───────────────────────────────── │
│ software bus · rate-group scheduler │
│ parameters · events · time │
│ ───────────────────────────────── │
│ HAL ports: clock, link, storage, │
│ watchdog │
└───────────────────┬──────────────────┘
│
┌───────────────────▼──────────────────┐
│ PLATFORM (the only OS-aware code) │
│ POSIX today · FreeRTOS/bare metal │
│ is a directory, not a rewrite │
└──────────────────────────────────────┘
learn/ is an eighteen-lesson course built around this
spacecraft — from "what even is a satellite" to estimating attitude from noisy
sensors and recovering from a failed reaction wheel.
It is graduated. Lessons 1–9 need no programming at all: you launch the spacecraft, send it real CCSDS commands, read its replies and break things on purpose. Lessons 10–11 open up the flight software. Lessons 12–18 are the physics and control theory, with runnable experiments.
| 🚀 Explorer | around 10 and up | Run it, watch it, break it |
| 🔧 Builder | some code | Read the real files, change them |
| 🎓 Engineer | studying or working here | The standards, the maths, the trade-offs |
python3 learn/toolbox/crc_playground.py # watch a checksum catch a cosmic ray
python3 learn/toolbox/orbit_sandbox.py # why a satellite doesn't fall down
python3 learn/toolbox/spin_sandbox.py # stop a tumbling satellite with a magnetEverything is real: the packets in Lesson 5 are byte-for-byte what a mission
sends, and every number printed by the toolbox was checked against the analytic
answer. learn/GLOSSARY.md translates every acronym.
make build # configure, compile, run 72 unit tests
make run # the spacecraft boots and waits for a ground stationThen, in a second terminal:
make demo # a scripted pass: connection test, parameter changes,
# a deliberately illegal command, a corrupted packetYou will see verification reports, housekeeping, events and failure codes come back — the real protocol, not a simulation of one.
=== connection test =========================================
t= 6.044 apid=0x001 seq= 8 VERIF_ACCEPT_OK tc(apid=0x00A, seq=0)
t= 6.044 apid=0x001 seq= 9 TEST_REPORT
t= 6.044 apid=0x001 seq= 10 VERIF_COMPLETE_OK tc(apid=0x00A, seq=0)
t= 6.525 apid=0x001 seq= 11 SYS_HK uptime_s=6 tick_count=326 mode=BOOT
Other useful entry points:
make test # unit tests (fast, no network, no spacecraft)
make sil # software-in-the-loop: starts the real binary, talks to it
make gen # regenerate everything from dictionary/mission.yaml
make params # read every on-board parameter back from the spacecraft
make help # everything elseEvery telemetry point, telecommand, event and parameter is declared once,
in dictionary/mission.yaml. A generator projects
that single declaration into the C++ structures and serialisers, the OpenC3
COSMOS command and telemetry definitions, the Python ground client's tables,
and the interface control document.
Adding a telemetry field is a one-line diff, and the ground system knows about
it on the next make gen. Nothing can drift out of sync, because there is only
one place for it to drift from. This is the decision the rest of the repository
is built around, and it is the one most worth copying into your own work.
| Area | State |
|---|---|
| CCSDS 133.0-B Space Packet Protocol | Working, unit tested against the standard's bit layout |
| PUS ST[01] request verification | Working — acceptance and completion, success and failure |
| PUS ST[03] housekeeping | Working — periodic reports, enable/disable per structure |
| PUS ST[05] event reporting | Working — severity-coded, with a bounded on-board history |
| PUS ST[17] connection test | Working |
| PUS ST[20] parameter management | Working — range-checked, CRC-protected, survives a restart |
| Rate-group scheduler | Working — deterministic, deadline-monitored, single-threaded |
| Software bus | Working — synchronous pub/sub, statically bounded |
| Parameter store | Working — range checks, CRC on non-volatile storage, safe fallback |
| Ground segment | Working — Python client and CLI; OpenC3 COSMOS config generated |
| ADCS, EPS, mode manager, FDIR | Not yet. Phases 2–6. Scaffolded and documented |
| Orbit and attitude simulator | Not yet. Phase 2 |
| TM/TC transfer frames, Reed-Solomon | Not yet. Phase 4 |
Every directory has a README.md explaining what belongs in it and why.
docs/PATHS.md is the complete annotated map.
| Path | What lives there |
|---|---|
dictionary/ |
The single source of truth. Start reading here |
tools/ |
The generator that projects the dictionary everywhere |
fsw/core/ |
Portable flight core: scheduler, bus, parameters, events, time |
fsw/hal/ |
The ports. Four small interfaces that make this portable |
fsw/platform/ |
The adapters. The only OS-aware code in the tree |
fsw/apps/ |
The applications. TT&C today; ADCS, EPS, FDIR to come |
fsw/generated/ |
Generated C++. Never edit by hand |
gnd/pyground/ |
Dependency-free Python ground station and test driver |
gnd/openc3/ |
OpenC3 COSMOS plugin: screens, limits, command definitions |
sim/ |
The orbit and attitude simulator. Phase 2 |
tests/unit/ |
Fast, hermetic tests of the flight core |
tests/sil/ |
Software-in-the-loop: the real binary over the real protocol |
docs/ |
Architecture, roadmap, and the generated interface control document |
learn/ |
The eighteen-lesson course, and the runnable toolbox |
These are enforced, not aspirational. fsw_core and fsw_apps are compiled
with -fno-exceptions -fno-rtti and the full warning set as errors, so a
violation fails the build rather than being caught in review.
- No allocation after initialisation. Every container is bounded at compile time. Worst-case memory is a property of the type, visible in the source.
- No exceptions on the flight path. Everything that can fail returns a status.
- One thread. Rate groups, fixed order, deterministic. The same inputs give the same outputs on every run and every machine.
- The core never calls the OS. It calls a port. Porting is writing a new
directory under
platform/, not editing the core. - Untrusted input is validated in one place, in a fixed order: integrity, then structure, then meaning. A packet that fails its CRC is never interpreted at all.
learn/— if any of this is new, start here insteaddictionary/mission.yaml— what this spacecraft says and acceptsdocs/ARCHITECTURE.md— why it is shaped this wayfsw/core/scheduler.hpp— the heartbeat, and why it is not threadedfsw/apps/ttc/pus.hpp— the standards, explainedfsw/main.cpp— the whole spacecraft, wired together in one filedocs/ICD.md— the generated interface control document
- CCSDS 133.0-B Space Packet Protocol
- ECSS-E-ST-70-41C Packet Utilisation Standard (PUS-C)
- CCSDS CRC-16 packet error control (polynomial
0x1021, seed0xFFFF)
CMake 3.20+, a C++17 compiler, Python 3.10+. make gen additionally needs
PyYAML; make venv will set that up. OpenC3 COSMOS is optional and runs in
Docker — the Python ground station needs none of it.
Apache 2.0. See LICENSE.