Decoding PW-Sat2 with gr-satellites

PW-Sat2 is a students satellite made by the Students Space Association at Warsaw University of Technology, in Poland. The project started in 2013 and was finally launched last Monday in the SSO-A launch. The satellite carries a sail to aid in deorbiting. This will be deployed on the 39th mission day. The deorbit is expected to happen in one year.

The satellite team has made available a lot of open-source software, such as groundstation software for Radio Amateurs, a telemetry server and even the software that runs on the on-board computer. There is also a good amount of design documentation. This is something a bit unusual and admirable for a university satellite.

PW-Sat2 transmits standard G3RUH-scrambled BPSK AX.25 frames in the 70cm Amateur Satellite band. The baudrate can be selected between 1k2, 2k4, 4k8 and 9k6 by the satellite team. The interesting thing is that there are many types of packets besides telemetry. For instance, it can list and transfer on-board files, such as the images taken by the satellite camera. These packets can be decoded by using the FramePayloadDecoder software.

Since the FramePayloadDecoder software is quite complex and it is written in Python, I have decided to make a telemetry parser for gr-satellites that simply loads this software into GNU Radio and passes the frames to the decoder. Here are the instructions to set this up.

First download the FramePayloadDecoder by doing

$ git clone https://github.com/PW-Sat2/FramePayloadDecoder

The FramePayloadDecoder includes the OBC software as a submodule, so you must do

$ cd FramePayloadDecoder
$ git submodule init
$ git submodule update

You need to have bitarray and typing installed, as these are required by the FramePayloadDecoder software. They can be installed either with your distribution’s package manager or with pip2.

Now open the PW-Sat2 decoder flowgraph in gr-satellites with GNU Radio Companion. This flowgraph is found in apps/pwsat2.grc. Find the PW-Sat2 Telemetry Parser block in the flowgraph, enable it, and edit its properties. In the field PW-Sat2 FramePayloadDecoder path you must enter the path to the FramePayloadDecoder software. Optionally, disable the Message debug block if you do not want to see the hex dumps of the decoded packets.

To test the decoder you can use the pwsat2.wav recording in satellite-recordings. This recording contains a telemetry beacon, and shows the following information when decoded:

2018-12-06 21:25:32

0x7f19e4392850: v012-FileListSuccessFrame Seq=00, #files: 11
2018-12-06 21:25:33

0x7f19e4392890: v012-FileListSuccessFrame Seq=00, #files: 11
2018-12-06 21:25:40

{'01: Startup': {'0000: Boot Counter': 293,
'0032: Boot Index': 7,
'0040: Boot Reason': 103},
'02: Program State': {'0056: Program CRC': 49149},
'03: Time Telemetry': {'0072: Mission time': 124682925,
'0136: External time': 946812915},
'04: Error Counters': {'0168: Comm': 0,
'0176: EPS': 0,
'0184: RTC': 0,
'0192: IMTQ': 0,
'0200: N25Q1': 0,
'0208: N25Q2': 0,
'0216: N25Q3': 0,
'0224: N25q TMR': 0,
'0232: FRAM TMR': 0,
'0240: Payload': 10,
'0248: Camera': 0,
'0256: ExpSuns': 0,
'0264: ANT Primary': 0,
'0272: ANT Backup': 0},
'05: Scrubbing State': {'0280: Primary Flash Scrubbing pointer': 2,
'0283: Secondary Flash Scrubbing pointer': 1,
'0286: RAM Scrubbing pointer': 330472},
'06: System': {'0318: Uptime': 41067},
'07: File System': {'0340: Free Space': 14396720},
'08: Antenna': {'0372: Antenna 1 Deployment Switch Ch A': 0,
'0373: Antenna 2 Deployment Switch Ch A': 0,
'0374: Antenna 3 Deployment Switch Ch A': 0,
'0375: Antenna 4 Deployment Switch Ch A': 0,
'0376: Antenna 1 Deployment Switch Ch B': 0,
'0377: Antenna 2 Deployment Switch Ch B': 0,
'0378: Antenna 3 Deployment Switch Ch B': 0,
'0379: Antenna 4 Deployment Switch Ch B': 0,
'0380: Antenna 1 Time Limit Reached Ch A': 0,
'0381: Antenna 2 Time Limit Reached Ch A': 0,
'0382: Antenna 3 Time Limit Reached Ch A': 0,
'0383: Antenna 4 Time Limit Reached Ch A': 0,
'0384: Antenna 1 Time Limit Reached Ch B': 0,
'0385: Antenna 2 Time Limit Reached Ch B': 0,
'0386: Antenna 3 Time Limit Reached Ch B': 0,
'0387: Antenna 4 Time Limit Reached Ch B': 0,
'0388: Antenna 1 Burn Active Ch A': 0,
'0389: Antenna 2 Burn Active Ch A': 0,
'0390: Antenna 3 Burn Active Ch A': 0,
'0391: Antenna 4 Burn Active Ch A': 0,
'0392: Antenna 1 Burn Active Ch B': 0,
'0393: Antenna 2 Burn Active Ch B': 0,
'0394: Antenna 3 Burn Active Ch B': 0,
'0395: Antenna 4 Burn Active Ch B': 0,
'0396: System Independent Burn Ch A': 0,
'0397: System Independent Burn Ch B': 0,
'0398: Ignoring Switches Ch A': 0,
'0399: Ignoring Switches Ch B': 0,
'0400: Armed Ch A': 0,
'0401: Armed Ch B': 0,
'0402: Antenna 1 Activation Count Ch A': 0,
'0405: Antenna 2 Activation Count Ch A': 0,
'0408: Antenna 3 Activation Count Ch A': 0,
'0411: Antenna 4 Activation Count Ch A': 0,
'0414: Antenna 1 Activation Count Ch B': 0,
'0417: Antenna 2 Activation Count Ch B': 0,
'0420: Antenna 3 Activation Count Ch B': 0,
'0423: Antenna 4 Activation Count Ch B': 0,
'0426: Antenna 1 Activation Time Ch A': 0,
'0434: Antenna 2 Activation Time Ch A': 0,
'0442: Antenna 3 Activation Time Ch A': 0,
'0450: Antenna 4 Activation Time Ch A': 0,
'0458: Antenna 1 Activation Time Ch B': 0,
'0466: Antenna 2 Activation Time Ch B': 0,
'0474: Antenna 3 Activation Time Ch B': 0,
'0482: Antenna 4 Activation Time Ch B': 0},
'09: Experiments': {'0490: Current experiment code': 9,
'0494: Experiment Startup Result': 0,
'0502: Last Experiment Iteration Status': 2},
'10: Gyroscope': {'0510: X measurement': -34,
'0526: Y measurement': -55,
'0542: Z measurement': 24,
'0558: Temperature': -24506},
'11: Comm': {'0574: Transmitter Uptime': 40989,
'0591: Transmitter Bitrate': 0,
'0593: [Last transmission] RF Reflected Power': 1179,
'0605: [Last transmission] Power Amplifier Temperature': 2933,
'0617: [Last transmission] RF Forward Power': 3753,
'0629: [Last transmission] Transmitter Current': 2654,
'0641: [Now] RF Forward Power': 3660,
'0653: [Now] Transmitter Current': 3141,
'0665: Transmitter Idle State': 0,
'0666: Beacon State': 0,
'0667: Receiver Uptime': 41008,
'0684: [Last received] Doppler Offset': 994,
'0696: [Last received] RSSI': 2104,
'0708: [Now] Doppler Offset': 1172,
'0720: [Now] Receiver Current': 4033,
'0732: [Now] Power Supply Voltage': 1500,
'0744: [Now] Oscillator Temperature': 3149,
'0756: [Now] Power Amplifier Temperature': 2931,
'0768: [Now] RSSI': 1230},
'12: GPIO': {'0780: Sail Deployed': 0},
'13: MCU': {'0781: Temperature': 2454},
'14: Controller A': {'0793: MPPT_X.SOL_VOLT': 1121,
'0805: MPPT_X.SOL_CURR': 57,
'0817: MPPT_X.SOL_OUT_VOLT': 1220,
'0829: MPPT_X.Temperature': 3154,
'0841: MPPT_X.State': 1,
'0844: MPPT_Y+.SOL_VOLT': 2371,
'0856: MPPT_Y+.SOL_CURR': 284,
'0868: MPPT_Y+.SOL_OUT_VOLT': 1709,
'0880: MPPT_Y+.Temperature': 3148,
'0892: MPPT_Y+.State': 1,
'0895: MPPT_Y-.SOL_VOLT': 1082,
'0907: MPPT_Y-.SOL_CURR': 38,
'0919: MPPT_Y-.SOL_OUT_VOLT': 545,
'0931: MPPT_Y-.Temperature': 3153,
'0943: MPPT_Y-.State': 5,
'0946: DISTR.VOLT_3V3': 366,
'0956: DISTR.CURR_3V3': 22,
'0966: DISTR.VOLT_5V': 547,
'0976: DISTR.CURR_5V': 3,
'0986: DISTR.VOLT_VBAT': 797,
'0996: DISTR.CURR_VBAT': 193,
'1006: DISTR.LCL_STATE': 0,
'1013: DISTR.LCL_FLAGS': 63,
'1019: BATC.VOLT_A': 613,
'1029: BATC.CHRG_CURR': 0,
'1039: BATC.DCHRG_CURR': 210,
'1049: BATC.Temperature': 863,
'1059: BATC.State': 3,
'1062: BP.Temperature A': 121,
'1075: BP.Temperature B': 119,
'1088: Safety Counter': 0,
'1096: Power Cycle Count': 23383,
'1112: Uptime': 127784,
'1144: Temperature': 861,
'1154: SUPP_TEMP': 861,
'1164: ControllerB.3V3d': 558,
'1174: DCDC3V3.Temperature': 872,
'1184: DCDC5V.Temperature': 871},
'15: Controller B': {'1194: BP.Temperature': 242,
'1204: BATC.VOLT_B': 616,
'1214: Safety Counter': 0,
'1222: Power Cycle Count': 45690,
'1238: Uptime': 42079,
'1270: Temperature': 862,
'1280: SUPP_TEMP': 860,
'1290: ControllerA.3V3d': 561},
'16: Imtq Magnetometers': {'1300: Magnetometer Measurement 1': 0,
'1332: Magnetometer Measurement 2': 0,
'1364: Magnetometer Measurement 3': 0},
'17: Imtq Coils Active': {'1396: Coils active during measurement': 0},
'18: Imtq Dipole': {'1397: Dipole 1': 0,
'1413: Dipole 2': 0,
'1429: Dipole 3': 0},
'19: Imtq BDot': {'1445: BDot 1': 0, '1477: BDot 2': 0, '1509: BDot 3': 0},
'20: Imtq Housekeeping': {'1541: Digital Voltage': 0,
'1557: Analog Voltage': 0,
'1573: Digital Current': 0,
'1589: Analog Current': 0,
'1605: MCU Temperature': 0},
'21: Imtq Coils': {'1621: Coil Current 1': 0,
'1637: Coil Current 2': 0,
'1653: Coil Current 3': 0},
'22: Imtq Temperature': {'1669: Coil Temperature 1': 0,
'1685: Coil Temperature 2': 0,
'1701: Coil Temperature 3': 0},
'23: Imtq State': {'1717: Status': 0,
'1725: Mode': 0,
'1727: Error during previous iteration': 0,
'1735: Configuration changed': 0,
'1736: Uptime': 0},
'24: Imtq Self Test': {'1768: Error 1': 0,
'1776: Error 2': 0,
'1784: Error 3': 0,
'1792: Error 4': 0,
'1800: Error 5': 0,
'1808: Error 6': 0,
'1816: Error 7': 0,
'1824: Error 8': 0}}

2 comments

Leave a Reply to mgumiela Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.