This project implements a wireless telemetry system for a model rocket using ESP32 microcontrollers. The system consists of a sensor package aboard the rocket that transmits temperature, pressure, and humidity data via ESP-NOW to a ground station, which relays the telemetry to a laptop for logging and analysis.
The rocket-based system samples environmental data multiple times per second during flight and stores it both locally to onboard flash memory and transmits it in real-time to the ground. The ground station acts as a relay between the rocket and a USB-connected laptop running data logging software. When a predetermined timeout has elapsed, the rocket stops logging telemetry and activates a BLE beacon to help you locate the landing site.
- Rocket Model: Estes Cosmic Cargo kit
- Engine: C6-5 model rocket engine
- Total Mass at Liftoff: 72 grams (36g rocket + 36g telemetry package)
- Microcontroller: TinyPICO v2 ESP32 development board
- Sensor: BME-280 (temperature, barometric pressure, and humidity via I2C)
- Power: 1000mAh Li-Poly 3.7V battery
- Storage: LittleFS partition on onboard flash for CSV logging
On startup the rocket calibrates its altimeter by averaging BME280 pressure readings to establish a ground reference. During flight the main loop (pinned to Core 1) samples the BME280 every READING_INTERVAL milliseconds (20ms by default), transmits each reading as an ESP-NOW packet to the ground station, and queues the reading onto a FreeRTOS queue. A separate CSV logger task (pinned to Core 0) drains that queue into a buffer that is batch-flushed to the CSV file in onboard flash, keeping slow flash writes off the time-critical sensor/transmit path. Once the telemetry timeout elapses, the rocket stops sampling and starts a NimBLE iBeacon so the landing site can be located. The rocket also responds to commands relayed from the ground: START/STOP, RECALIBRATE, DOWNLOAD (stream the flight log back over ESP-NOW), and TRUNCATE (clear the flight log before a flight).
- Microcontroller: Seeed XIAO ESP32S3 development board
- Antenna: 5dBi omnidirectional 2.4GHz antenna (IPEX connector)
- Communication: ESP-NOW using ESP32 proprietary 802.11 LR mode
- Computer Link: USB serial UART connection to laptop
The ground station bridges the rocket and the laptop in both directions. Its ESP-NOW receive callback does minimal work — it enqueues each incoming packet onto a FreeRTOS queue and returns immediately, so slow serial writes never block reception of the next packet. A dedicated forwarding task drains the queue and writes each reading to the laptop over USB serial as a DATA: CSV line with the packet's RSSI appended as the final column (diagnostics are emitted as LOG: lines). In the other direction, it reads text commands from the laptop over serial and relays them to the rocket via ESP-NOW.
- Python-based serial port receiver and command client
- Logs telemetry data to CSV files
- Sends text commands to the rocket via the ground station relay
- Install uv for Python environment management
- Copy
.envrc.exampleto.envrcand configure your device MAC addresses and runtime parameters- Optionally, customize values in
.envrcto change telemetry timeout, sample rate, ESP-NOW channel, BLE beacon UUID, etc.
- Optionally, customize values in
-
Set up the Python environment:
uv sync
-
Build firmware:
# Rocket firmware cd rocket && uv run pio run # Ground station firmware cd ground-station && uv run pio run
-
Flash devices (use correct USB serial device paths):
# Note: You may need to specify the USB device to flash unless you plug the boards in one at a time # Rocket (TinyPICO) cd rocket && uv run pio run -t upload # Ground station (XIAO ESP32S3) cd ground-station && uv run pio run -t upload
Serial console output can be monitored via uv run pio device monitor from inside either the rocket or ground-station directories.
- Board models can be customized by editing
platformio.inifiles in the respective firmware directories - Runtime parameters (MAC addresses, sensor intervals, ESP-NOW channel, etc.) are configured via environment variables listed in
.envrc.example
Both firmware builds read these from the environment (see each platformio.ini). The three required variables must be exported before compiling or flashing, or the build will fail. Copy .envrc.example to .envrc to set them.
Required:
| Variable | Used by | Description |
|---|---|---|
ROCKET_MAC |
ground station | Rocket's ESP32 MAC, as a comma-separated byte list (e.g. 0x7C,0xDF,0xA1,0x11,0x22,0x33) |
GROUND_STATION_MAC |
rocket | Ground station's ESP32-S3 MAC, same format |
ESPNOW_CHANNEL |
both | WiFi channel shared by both boards (default: 1) |
Optional (rocket):
| Variable | Default | Description |
|---|---|---|
READING_INTERVAL |
20 |
Sensor sampling interval in milliseconds |
TELEMETRY_TIMEOUT |
120000 |
Time before telemetry stops and the recovery beacon activates (ms) |
GROUND_REFERENCE_PRESSURE |
1013.25 |
Fallback ground-reference pressure in hPa (overridden by startup calibration) |
BEACON_UUID |
(built-in) | iBeacon proximity UUID for the recovery beacon |
DEBUG_SERIAL |
1 |
Set to 0 at build time (-DDEBUG_SERIAL=0) to disable debug serial output for flight builds |