The Artemis Launch Simulator is a dual-microcontroller embedded system that simulates a rocket launch sequence and deployment. It consists of two main stations communicating in real-time: a launch Pad (which monitors structural vibrations) and a control station (featuring an OLED telemetry display and countdown timers). The climax of the system is the release of a miniature spring-loaded rocket. Inside the rocket, an ultra-lightweight ESP32 uses a barometric altimeter to detect its highest point in the air.
The primary purpose is to demonstrate a fault-tolerant, highly interactive embedded system. It showcases how multiple hardware communication protocols (I2C, SPI, PWM, ADC) and software concepts (interrupts, non-blocking timers, and TinyML) must work together to execute a complex physical operation. It serves as a proof-of-concept for handling sensor data, user inputs, and physical actuation simultaneously without system failure.
The project was deeply inspired by NASA's Artemis missions and the immense engineering complexity behind modern spaceflight. At the same time, I wanted to create a project that's interactive and fun to repeatedly play around with.
This project acts as an engaging, highly interactive educational showcase. By allowing users to interact with a physical console, to press buttons or to watch the telemetry react to the rocket reaching higher altitudes, it explains complex aerospace engineering concepts with simple components.
The launch will proceed as follows: Once the arming switch is toggled, a button can be pressed that will begin the countdown to launch. Until reaching 0, the vibration motor will simulate the starting of the engines and, if the accelerometer detects anomalous vibrations (such as vibrations that are too strong), the launching will be terminated. When the countdown reaches 0, the servo motor releases a tightly-packed spring that launches the rocket. At this moment, the ESP32-C3 receives a signal from the main ESP32 to begin measuring its altitude, and this data is sent back and displayed at the platform.
Components:
| Component Name | Qty | Role | Datasheet |
|---|---|---|---|
| ESP32 Development Board | 1 | Base station microcontroller | https://roboeq.ir/files/id/4034/name/ESP32%20MODULE.pdf/ |
| MPU6050 | 1 | Structural vibration anomaly sensor | https://cdn-reichelt.de/documents/datenblatt/A300/ME024.pdf |
| ESP32-C3 SuperMini Development Board | 1 | Lightweight rocket payload controller | https://dl.artronshop.co.th/ESP32-C3%20SuperMini%20datasheet.pdf |
| Vibration Motor Module | 1 | Haptic launch vibration feedback | |
| Passive Buzzer Module | 1 | Audio alarm and countdown tones | |
| SG90 Servo Motor | 1 | Physical launch release actuator | http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf |
| BMP280 | 1 | Apogee detecting barometric altimeter | https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf |
| LR44 | 3 | Rocket payload power supply | |
| 1.3 inch TFT Module 240×240 ST7789 GMT130-V1.0 | 1 | Telemetry and countdown display | https://www.lcdwiki.com/res/MSP1308/TFT1301-SPEC.pdf |
The firmware for both the Base Station (Launch Controller) and the Rocket Payload (Flight Computer) is developed using PlatformIO running on the Arduino framework. This environment was chosen because it easily manages cross-architecture compilation. PlatformIO’s platformio.ini configuration files allow for strict library dependency tracking and custom build flags (such as enabling hardware USB CDC on the C3 chip) without manual makefiles.
To ensure high-performance hardware interfacing and non-blocking execution, the following libraries are utilized:
Wire.h).
The mission logic is governed by a synchronized FSM distributed across both microcontrollers. The Base Station operates in strictly defined states: SCANNING (-1), HOLD (0), COUNTDOWN (1), FLIGHT (2), and ABORT (3). The loop() function routes CPU execution strictly based on the current state, ensuring graphical LCD updates or servo actuations only occur exactly when physics dictate they should.
To prevent the vibration of the haptic motor (eccentric rotating mass) from accidentally triggering a launch pad abort, the MPU6050 data is passed through an EMA filter.
smoothedForce = (EMA_ALPHA * rawForce) + ((1.0 - EMA_ALPHA) * smoothedForce)This Infinite Impulse Response (IIR) filter ignores high-frequency motor jitter while remaining highly sensitive to massive, low-frequency forces (e.g., the launch pad being tipped over).
Because barometric pressure changes with local weather, the payload cannot use a static sea-level baseline.
launchPadPressure float variable with the current ambient pressure. The exact millisecond the “ARM” command is received via BLE, this variable is locked. The BMP280 uses this locked baseline to calculate and transmit true AGL (Above Ground Level) relative altitude.
To avoid blocking the main execution loop with delay() or active waiting, the radio stack relies on hardware interrupts. When the Payload calculates a new altitude, it pushes a 4-byte float array. On the Base Station, a notifyCallback instantly decodes this byte array back into a float and updates the screen asynchronously, resulting in zero telemetry lag.
Below are the core functions that drive the hardware and the mission logic:
| Function Signature | Role & Description |
|---|---|
void setup() | Initializes the I2C/SPI buses, allocates hardware timers for the haptic motor and piezo buzzer via ledcSetup(), and initializes the BLE radio stack (either as a Server or a scanning Client). |
void loop() | Contains the non-blocking state machine logic. Uses millis() mathematics to throttle countdown visuals, motor intensities, and altitude transmission rates without freezing the CPU. |
bool connectToServer() | Invoked dynamically when the Base Station discovers the “KINDER_ROCKET” BLE beacon. Extracts the specific Service UUIDs and binds the Telemetry and Command Characteristic pointers to memory. |
void onResult(BLEAdvertisedDevice) | An asynchronous callback that scans the 2.4GHz spectrum. Upon detecting the payload's MAC address and signature, it halts the active scan to save power and initiates the pairing handshake. |
void notifyCallback(…) | A remote characteristic interrupt on the Base Station. Receives the raw byte payload from the rocket, maps it via memcpy to the currentFlightAltitude float, and triggers an LCD refresh if the delta is significant. |
void onWrite(…) | A characteristic interrupt on the Payload. Listens for the 1-byte command (1 for ARM, 2 for SLEEP) sent by the Base Station and modifies the internal payload FSM state accordingly. |
void fatalError(int flashes) | A hardware-level diagnostic trap on the payload. If the I2C bus drops the BMP280 or the BLE radio crashes on boot, the system halts and uses the onboard LED to flash specific error codes. |
The development of the Dual-ESP32 Telemetry and Launch System resulted in a highly robust electronic and software architecture. While the project faced significant challenges regarding cross-architecture RF compatibility and mechanical physics, the core objective of building a real-time, bidirectional aerospace tether was successfully achieved.
Initially, the system was designed around the ESP-NOW protocol. However, extensive bare-metal hardware testing revealed a physical incompatibility and transmit amplifier limitation on the ESP32-C3 Supermini's architecture when communicating with the base station. By pivoting to a Bluetooth Low Energy client-server architecture, the system achieved a tethered connection. The Base Station successfully scans the 2.4GHz spectrum, automatically pairs with the “KINDER_ROCKET” payload upon power-up, and maintains a stable connection capable of receiving continuous 4-byte float altitude updates without dropping packets.
The severe size and weight constraints of the Kinder egg capsule required a custom power delivery solution. Standard coin cells failed to deliver the 300mA burst current required by the BLE radio, triggering the ESP32's brownout detector. This was overcome by engineering a custom stacked LR44 alkaline battery pack wrapped under high vinyl tension. This solution successfully maintained a stable 4.5V supply to the payload's voltage regulator, ensuring the BMP280 barometric sensor and BLE transmitter remained powered even during high-frequency data transmission.
The Base Station's Finite State Machine (FSM) executed perfectly during testing.
SCANNING, HOLD, T-Minus, and FLIGHT states based on both BLE connection status and physical switch inputs.ABORT state when the launch pad experienced genuine, heavy physical disruption.Due to timeline constraints and the physical phenomenon of spring buckling, the mechanical spring-loaded silo was not finalized in time for a kinetic launch. The extreme compression required for the payload caused the spring to deflect laterally against the curved base of the Kinder capsule.
However, the complete software and telemetry stack was successfully validated. By arming the Base Station and manually launching the Kinder egg payload by hand (throwing it vertically to simulate the flight profile), the laucnh sequence was executed flawlessly.
The electronic architecture, RF communication, and mission software are 100% flight-ready, laying a robust foundation for future mechanical launcher iterations.
This GitHub issue was particularly revealing that most ESP32-C3 Superminis suffer from poor antenna construction, potentially the reason why ESP-NOW did not behave as expected.