Open-source GNU Radio Companion (GRC) receiver pipeline and Python telemetry decoder for the FramSat-1 CubeSat by Orbit NTNU.
FramSat-1 transmits periodic direct HDLC-framed telemetry beacons on the 70 cm amateur satellite band. This repository provides amateur radio operators with everything needed to receive, demodulate, and extract raw packet frames and sensor telemetry.
| File | Description |
|---|---|
framsat1_rtlsdr_rx.grc |
The main GNU Radio Companion flowgraph. Open this in GRC to view and run the receiver visually. |
framsat1_rtlsdr_rx.py |
Standalone Python script generated by GNU Radio. Can be run directly in headless environments (e.g. Raspberry Pi) without opening the GRC GUI. |
framsat1_decoder.py |
Standalone frame and telemetry decoder. Unpacks FS1.0 health data (battery, uptime) and 9x GSS/ESS sensor arrays. Parses raw hex or listens live via --listen. |
FramSat_1_Reception_Guide.pdf |
Full technical documentation and RF specification guide. |
| Parameter | Specification |
|---|---|
| Downlink Frequency | 435.141 MHz (IARU Coordinated) |
| Modulation | GFSK (2-FSK with Gaussian filter) |
| Baud Rate | 9600 bps |
| Frequency Deviation ( |
|
| Pulse Shaping | Gaussian ( |
| Scrambler | G3RUH (0x21) |
| Bit Encoding | NRZI |
| Frame Format | Direct Synchronous HDLC (compatible with AX.25 UI encapsulation) |
| Frame Length | 209 bytes fixed (6 B transport header + 199 B telemetry payload + 4 B CRC) |
| Telemetry Identifier | FS1.0 |
The telemetry beacon begins with the static signature "FS1.0" (located at byte offset 6 following the 6-byte onboard transport header). All multi-byte numeric fields are serialized in standard Big-Endian format (network byte order, MSB first).
In LEOP deployment mode (operating_mode = 2), the 180-byte attitude sensor payload array is zero-padded while sensors remain unpowered to conserve power.
| Offset | Size | Field | Type | Description |
|---|---|---|---|---|
| 0–4 | 5 B | signature |
ASCII | Beacon sync signature: always "FS1.0"
|
| 5 | 1 B | beacon_id |
uint8 |
Beacon sequence ID counter |
| 6 | 1 B | operating_mode |
uint8 |
1 = Default Mode, 2 = LEOP (Launch/Early Orbit) |
| 7 | 1 B | satellite_rssi |
uint8 |
Ground uplink RSSI recorded by satellite |
| 8–9 | 2 B | telecommand_count |
uint16 |
Total telecommands accepted by satellite |
| 10 | 1 B | eps_flags |
uint8 |
EPS status and subsystem power flags |
| 11–12 | 2 B | reboot_count |
uint16 |
Total OBC / EPS reboot counter |
| 13–14 | 2 B | battery_voltage |
uint16 |
Battery voltage ( |
| 15–18 | 4 B | uptime_sec |
uint32 |
Satellite uptime in seconds |
| 19–198 | 180 B | sensor_data |
Array[9] | 9x Attitude sensor samples (Sun Sensor & Earth Sensor array) |
Prerequisites: Requires GNU Radio with
gr-satellitesandgr-osmosdrinstalled (both are included out-of-the-box in Radioconda).
The recommended receiver flowgraph (framsat1_rtlsdr_rx.grc) is optimized for standard RTL-SDR dongles:
- RTL-SDR Source: Samples at a stable
2.4 MSpson435.141 MHzwith RF gain set to40 dB. - Low Pass Filter (Decimator): Decimates by
25down to96 kSpswith a40 kHzcutoff to suppress adjacent out-of-band noise. - FSK Demodulator & NRZI: Demodulates the GFSK signal and decodes transitions.
- Descrambler & HDLC Deframer: Descrambles G3RUH and validates the 16-bit CRC-CCITT (FCS).
- Plug in your RTL-SDR dongle.
- Open
framsat1_rtlsdr_rx.grcin GNU Radio Companion. - Press Execute (Play). Received frames will print directly in the
Message Debugconsole. (Optional: Enable theSocket PDUblock to simultaneously stream packets over TCP).
For server setups (e.g. Raspberry Pi), run the SDR receiver in the background and attach the live decoder:
# Terminal 1: Start the RTL-SDR receiver
python3 framsat1_rtlsdr_rx.py
# Terminal 2: Listen and decode live frames over TCP (port 52001)
python3 framsat1_decoder.py --listenPass a received hexadecimal string as a command-line argument to parse historical or recorded frames.
Test against verified on-orbit LEOP frame (Beacon #181, 8.308 V Battery, 13.46 hours uptime):
python3 framsat1_decoder.py 8500850000cf4653312e30b50200000000000120740000bd59000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ce47af75Expected terminal output:
=================================================================
🛰️ FramSat-1 Frame Received at ...
Total Frame Length: 209 bytes
Telemetry Found: Offset index 6
Transport Header: 8500850000CF (6 bytes)
─── [ FramSat-1 Housekeeping Telemetry ] ───
Signature: FS1.0
Beacon ID: #181
Operating Mode: LEOP (Launch / Deployment Mode)
Satellite Uplink RSSI: N/A (No uplink signal received)
Telecommands Accepted: 0
EPS Flags: 0x00
OBC / EPS Reboot Count:1
Battery Voltage: 8.308 V (8308 mV)
Satellite Uptime: 48473 s (13.46 hours)
─── [ Attitude Sensors (LEOP Mode) ] ───
Status: Sensors unpowered during deployment (180 bytes zero-padded).
=================================================================
For complete technical details, download the included FramSat_1_Reception_Guide.pdf.
We welcome reception reports and baseband recordings! Please submit reports via email to satcom@orbitntnu.com or upload observations to the SatNOGS Network under satellite FramSat-1.
