SDL’s Packet System
- Justin Michaud
- May 8
- 9 min read
SDL is built around a simple idea: collect useful flight data, store it reliably, and make it easy to analyze after the flight. That sounds straightforward, but the data has to move through several different paths.
During development, USB serial output is useful because it gives immediate feedback. During flight, onboard flash is the priority because it can store data directly on the board. After flight, SD card export makes the data easy to retrieve. LoRa telemetry adds a live link for status and basic information from the pad or during flight.
Rather than treating each output as a separate system with its own format, SDL uses a shared packet structure. Sensor data is collected, converted into known units, formatted into a packet, and then sent to whichever outputs are enabled.
The goal is to build the data once and reuse it everywhere.
Why SDL uses packets
A rocket data logger does not only produce one kind of data. SDL records information from several subsystems, including IMUs, barometers, GPS, power monitoring, temperature sensing, and board status.
Each of those data types has a different structure. An IMU packet may include acceleration and gyroscope values from several sensors. A GPS packet may include latitude, longitude, satellite count, and HDOP. A power packet may include voltage, current, and calculated power.
If every subsystem produced completely different output with no common structure, the logs would be harder to parse and the firmware would be harder to extend.
The packet system solves that by giving every message a type.
A simplified example looks like this:
0x00 = Board information
0x02 = IMU data
0x03 = Barometer data
0x05 = Power data
0x06 = GPS data
The packet ID tells the receiving code what kind of data it is looking at. That receiving code might be a Python script, a ground station program, a USB serial monitor, or a future onboard replay/debug tool.
This makes the system expandable. New packet types can be added without completely changing the existing log structure.
Current packet categories
The current SDL packet system is still designed to be readable and easy to debug. It is not trying to be the most compact possible format yet. At this stage, being able to inspect the data quickly is more valuable than shaving off every byte.
The current and planned packet categories are roughly:
Packet ID | Purpose | Example contents |
0x00 | Board info | Board name, revision, firmware version |
0x01 | State estimate | Future filtered attitude, altitude, velocity, and flight-state data |
0x02 | IMU debug | Acceleration, gyroscope, and high-G sensor data |
0x03 | Barometer debug | Pressure and temperature data from pressure sensors |
0x04 | Compass debug | Magnetometer data |
0x05 | Power info | Battery voltage, current, power, and pack status |
0x06 | GPS info | Latitude, longitude, satellites, HDOP, and fix status |
0x07 | Other sensors | Board temperature and miscellaneous slower sensor data |
This structure gives the firmware a common language for flight data.
Instead of having one custom format for IMU data over USB, another format for IMU data in flash, and another format for IMU data over radio, SDL can build one IMU packet and send it through multiple outputs.
CSV-style packets for early development
For early testing, SDL uses a mostly CSV-style text format.
That may not be the final format forever, but it is very useful during development. CSV-style packets can be opened in a text editor, spreadsheet, serial terminal, or Python script without needing a custom binary decoder.
A simplified packet might look something like this:
0x05,123456,7600,120,912
In this example, the first value is the packet type, followed by a timestamp and power-related values. The exact fields depend on the packet type.
The benefit is that the log remains human-readable. If something looks wrong, I can open the file and inspect the raw output directly. That makes bring-up and debugging much faster.
A binary format may eventually make sense for higher-rate logging or more constrained radio telemetry, but the message ID structure can remain the same. The current CSV-style packets are a practical early format, not a dead end.
One packet, multiple outputs
The most important part of the packet system is that it separates data generation from data transport.
The packet builder should not need to know whether a packet is going to USB, flash, LoRa, or the SD card. Its job is only to take known data and format it into a consistent message.
After that, the output layer decides where the message goes.
Sensor data
\/
Packet builder
\/
Shared packet buffer
USB serial output
LoRa telemetry
QSPI flash log
SD card export
This keeps the firmware cleaner. A sensor driver does not need to know about the radio. The radio code does not need to know about every sensor. The flash logger does not need to understand how the GPS parser works.
Each part of the system has a clear responsibility.
The driver produces data. The packet builder formats it. The logging and telemetry outputs move it.
Flash-first logging
For flight data, SDL treats onboard flash as the primary log location.
SD cards are extremely convenient, but they are not always ideal for fast, predictable flight logging. They can have variable write latency, have filesystem overhead, are susceptible to vibration, can be damaged during a hard landing and can have edge cases that are annoying to deal with in a short-duration flight environment.
QSPI flash is much more directly controlled by the microcontroller. For SDL, the intended flow is:
During flight:
Sensors -> Packets -> QSPI flash
After flight or disarm:
QSPI flash -> SD card
This gives SDL the advantages of both storage types.
The flash chip is used for the actual flight log because it is onboard and predictable. The SD card is used as the convenient transfer medium after the flight. Once the flash contents are copied to SD and verified, the flash can be erased and prepared for the next run.
This also means the SD card does not need to be the most timing-critical part of the flight logging system.
USB serial during development
USB output is mostly a development and debugging tool.
When SDL is connected to a computer, USB serial makes it easy to see live packet output, confirm that sensors are initializing, and check that the packet system is working before the board ever flies.
This is especially useful during bring-up. If a barometer is returning strange pressure values or an IMU is not initializing correctly, USB output gives immediate feedback without needing to remove an SD card or decode flash contents.
For early development, this makes USB one of the fastest ways to inspect the system.
However, USB is not the primary flight data path. During flight, the board needs to log independently. USB is useful when available, but the firmware cannot depend on a computer being connected.
LoRa telemetry
LoRa telemetry adds a different kind of output.
Unlike onboard flash, LoRa is not meant to carry every high-rate sensor sample. Radio bandwidth is limited, and the link quality can change throughout a flight. Instead, LoRa is most useful for live status, lower-rate telemetry, and command/response behavior before launch.
Examples of useful radio data include:
Board info
Battery status
GPS status
Basic sensor health
Logging state
Low-rate flight telemetry
Acknowledgements for ground commands
This makes the radio link useful without forcing it to replace onboard logging.
The flash log remains the source of truth for high-rate flight data. The radio link provides situational awareness and control.
That distinction is important. Trying to send everything over the radio would limit the entire system to the speed and reliability of the telemetry link. SDL avoids that by separating high-rate onboard logging from lower-rate live telemetry.
SD card export
The SD card is mainly used for recovery and analysis.
After a flight, the board can copy the flash log to the SD card. From there, the data can be moved to a computer and analyzed using scripts, spreadsheets, or future ground station tools.
This keeps the user-facing workflow simple:
Fly the rocket
\/
Dump flash log to SD
\/
Remove SD card
\/
Open log on computer
\/
Plot and analyze data
That workflow matters because flight data is only useful if it can actually be recovered and inspected easily.
The SD card is not the fastest or most deterministic part of the system, but it is very convenient after the flight. By using flash first and SD later, SDL can keep the flight logging path more controlled while still making post-flight analysis straightforward.
Scaled integer values
SDL generally stores and transmits sensor values as scaled integers rather than formatted floating-point values.
For example:
12.345 V -> 12345 mV
23.75 °C -> 2375 centi-degrees C
1.250 g -> 1250 mg
90.000 °/s -> 90000 mdps
This keeps packets compact and consistent.
A value like 12345 in a voltage field is unambiguous if the packet definition says that field is measured in millivolts. The conversion back to 12.345 V can happen later in the ground station, spreadsheet, or Python plotting script.
Scaled integers also avoid some of the overhead and inconsistency that comes with printing floating-point numbers on an embedded system. The firmware can focus on collecting and storing reliable data, while the analysis tools can handle display formatting later.
This is especially useful for radio telemetry. Text-based floating-point values can get long quickly, while scaled integers keep the data smaller and easier to parse.
Packet IDs versus command IDs
As SDL grows, there is an important distinction between data packets and commands.
Data packets are messages sent by the rocket to describe what the board is measuring or doing. These include IMU packets, barometer packets, power packets, GPS packets, and board information packets.
Ground commands are different. They are messages from the ground station to the rocket asking it to do something or report something.
For example:
Rocket -> Ground:
0x00 Board info
0x02 IMU data
0x05 Power data
0x06 GPS data
Ground -> Rocket:
0x11 Request acknowledgement
0x12 Request board info
0x14 Enable high-rate logging
0x16 Trigger flash-to-SD transfer
Keeping these ID ranges separate helps avoid confusion. A packet ID should not accidentally mean one thing when sent by the rocket and a different thing when sent by the ground station.
The current system is still early, but the long-term goal is to keep telemetry packets and command packets organized as separate parts of the protocol.
Why readability matters right now
It is tempting to make the packet system highly optimized right away, but early in the project, readability is more valuable.
SDL is still being used to validate hardware, debug sensors, test storage behavior, and understand real flight data. During that phase, logs should be easy to inspect.
Readable packets make it easier to answer questions like:
Did the board boot correctly?
Did each sensor initialize?
When did the flight start?
Did pressure drop during ascent?
Did the gyro capture launch motion?
Did battery voltage sag?
Was GPS valid?
Did the flash log contain complete data?
Those questions matter more than raw efficiency during early flight tests.
Once the system is more mature, the packet format can become more compact where needed. The important part is that the overall structure is already there: message IDs, known fields, known units, and shared outputs.
How this supports analysis
The packet system does not end at the board. It also affects how the data is analyzed later.
Because each line has a packet type, a Python script can read the log, split it by message ID, and plot the relevant data. IMU packets can become acceleration and gyro plots. Barometer packets can become pressure or altitude plots. Power packets can show battery behavior. GPS packets can show position and fix quality.
A simplified analysis flow looks like this:
Raw SDL log
\/
Parse by packet ID
\/
Convert scaled integers to display units
\/
Build time-aligned data sets
\/
Plot flight events
This is one of the reasons the packet format matters so much. A good log format makes post-flight analysis easier. A messy format makes every graph harder to generate.
The goal is not just to collect data. The goal is to collect data in a way that can be reused.
How this supports future development
The packet system is also important for future SDL features.
As the firmware improves, SDL can add new packet types without throwing away the old structure. For example, the future state estimate packet can include filtered orientation, altitude, velocity, and flight-state information while the raw sensor packets continue to exist for debugging.
That makes it possible to compare raw data against processed data.
Future uses could include:
Live ground station graphs
Lower-rate radio telemetry
High-rate onboard logs
State estimation output
Sensor health reporting
Flight event detection
Replay of old flight data through new filters
Comparison between firmware versions
The replay idea is especially useful. If SDL can process old flight logs through newer filtering code, then the same flight data can be used to test multiple versions of the algorithm. That makes real flight data more valuable because each flight can continue helping development after it is over.
The packet system is what makes that practical.
Closing
SDL’s packet system is the bridge between the sensors, the storage system, the radio link, and the analysis tools.
Each driver produces standardized data. The packet builder turns that data into known message types. The output layer sends those packets to flash, USB, LoRa, or SD export depending on the current mode.
That structure keeps the firmware flexible. It allows readable early logs, reliable onboard storage, live telemetry, and future ground station support to all build on the same foundation.
For now, the format is intentionally simple and easy to debug. As SDL grows, the same packet structure can support higher-rate logging, more compact telemetry, state estimation, and replay-based filter development.
The result is a system where flight data is not trapped in one output path or one tool. It becomes a common data stream that can be logged, transmitted, exported, plotted, and reused.



Comments