PixelSat I Software Part 3: Onboard Computer<br>| Project Pixel OrbitalPixelSat I Software Part 3: Onboard Computer
by Ashwin Naren, Vinayak Vikram, and Aadish Verma<br>7/20/2026
Welcome to the third post in our series about the PixelSat I software stack.<br>Part 1 covered communications, and Part 2 covered attitude determination and control.<br>This post is about the microcontroller tying both together, and the software running on it.
Onboard computer
Every input and output eventually passes through the onboard computer (OBC).<br>It runs the flight firmware and coordinates the satellite’s electronic subsystems.<br>On a CubeSat, that usually means a low-power microcontroller that is hardened for space use.
Following a theme established by our comms and ADCS designs, the standard space-qualified answer is far outside our budget.<br>Open designs such as PyCubed would still require us to fabricate and qualify a board, while established products such as the GomSpace NanoMind are expensive and more capable than our mission needs.<br>We instead looked for a commercial microcontroller with the right peripherals, enough performance, and useful resilience features already on the chip.
Constraints
Ultimately, the OBC has two tasks: run our flight firmware and talk to everything around it.<br>It needs enough computational power for orbit propagation and the ADCS logic,<br>plus handling interrupts or periodically reading UART, I2C, SPI, ADCs, timers, and a healthy number of GPIO pins.<br>Just as importantly, it needs a mature Rust hardware abstraction layer and a concurrency model we can reason about.
A few less obvious requirements follow from the environment:
Fault tolerance: Hardware memory/flash protection and proper fault and error handling can stop some faults from becoming fatal.
Real-time clock: ADCS needs UTC to propagate the orbit and calculate reference vectors. Ground control sets the clock after launch, and the RTC maintains it across resets.
Watchdog: A watchdog is a timer the firmware must continually feed. If execution hangs, higher-priority work starves the feeder, or a fault places the processor somewhere unexpected, the internal watchdog expires and triggers a reset. An internal independent watchdog is especially useful because it runs separately from the main MCU while being well coupled to the reset pin.
ESP32
Early in the project, our “flight software” was a monolithic Python file launched by systemd on login to a Raspberry Pi 5.<br>It was a poor spacecraft architecture.
Linux brings in power draw, scheduling, unexpected tasks, and many other issues.<br>Additionally, we had already seen the Pi shut down unexpectedly on the bench, so putting it beyond physical reach did not seem likely to improve matters.
Our first major redesign came in February 2026, when we moved the main flight software to bare-metal Rust on a classic dual-core ESP32.<br>An Embassy async executor ran comms, ADCS, and the rest of the spacecraft tasks.<br>We kept the Pi as a payload computer over UART, responsible only for image processing and data from a planned protein-crystallization experiment.
Then the experiment was cut, and we found a camera that could encode JPEGs itself.<br>In doing so we put the RPI out of a job.<br>We briefly designed a dual-ESP32 system to replace the RPI, with one processor handling comms and ADCS while the other handled images and telemetry,<br>but the boundary created more failure modes and complication than it removed.
For example, handling esp1 (the camera ESP) failures with timeouts and choosing whe to reset it was an unneeded complication.
STM32
We finally consolidated the satellite around an STM32H753, a 32-bit ARM Cortex-M7.<br>The chip can run at up to 480 MHz; however our firmware uses a 300 MHz system clock and a 150 MHz HCLK to reduce heat generation and power consumption.<br>It gives us 1 MB of SRAM, 2 MB of internal flash, far more GPIO pins than we need, a real-time clock, an independent watchdog, hardware memory error correction, and cryptographic acceleration.
That headroom let one MCU replace the Pi and both proposed ESP32s.
It also yielded some nice quality of life improvements:
RAM and Flash ECC: No manual ECC implementations
Built in watchdog: No external watchdog needed, yet another part cut out.
More built in flash: No need for external flash
Better tooling support: The classic ESP32 runs on XTENSA, an architecture from Cadence. Rust does not natively support it, so switching to a more supported architecture was a relief.
RTIC
A fast processor is not very useful if multitasking is inefficient.<br>We use RTIC, a Rust concurrency framework built around hardware interrupts.<br>Tasks have fixed priorities which map directly onto interrupt priorities.<br>When two tasks are ready, the higher-priority one runs; if it becomes ready later, it preempts the lower-priority task immediately.<br>On ARM Cortex-M, RTIC turns the NVIC, the chip’s interrupt controller, into a compact real-time scheduler.
RTIC also supports async Rust. A...