
In June of 2025, I worked with New England Sci-Tech as a part of Apex to launch StratoSpore: my first ballooning project. I used this opportunity to use algae as a biosensor for altitude, and I learned a lot in the process. Wanting to experiment in the stratosphere again, I worked with Sam Flynn to make a reliable and flight-ready payload.
I had a few goals with this payload from what I learned from last year:
- Have redundancy for tracking systems
- Send images to the ground with actual details
- Last payload sent pictures 18x10 pixels
- Use a more reliable GPS module
- Implement more elaborate radio functionality
- Use my amateur radio license?
- Use more efficient data packing techniques for telemetry
My plan for this post is to cover how I implemented these changes, along with documenting my learning process in hopes to inform my future launches.
The Experiment(s)
StratoSpore last year had two goals: examine how altitude/UV exposure affects algae fluorescence, and send images to the ground over a radio link.
UpLink, our payload this year, follows a similar style and did two things:
- Test how 3D printing filaments (foaming PLA vs. non-foaming) affects payload insulation
- Send high-resolution images over a radio link
Testing Payload Insulation
Historically, most high-altitude research teams use styrofoam boxes for payload enclosures. There is a reason most teams avoid experimenting with other types of enclosures: styrofoam provides excellent thermal insulation and is easy to manipulate.
Despite their popularity, they have a few disadvantages:
- They come in predefined sizes which mandate a certain weight allowance
- They cannot be flexible for your specific payload, making it hard to be efficient with payload layout
- They are expensive compared to more custom solutions
The entire payload (parachute, flight line, electronics, enclosures) we sent up weighed 491 grams. A traditional foam enclosure would already weigh ~200 grams. Ultralight payloads are more attractive the lighter your balloon is. Ours was a 350 gram balloon from Kaymont. As a general rule, the bigger the balloon, the more helium you will need. Costs of it add up quickly!
Sam designed our enclosure in Fusion360 over a few weeks, creating something that fit our payload perfectly, had predefined standoffs, standardized mounting hardware, and pockets for fitting cameras, temperature sensors, and other electronics.

For measuring how the different filaments insulate the temperature sensors, small capsules were attached to the payload’s lid. Internally, the sensors were sealed with hot glue to isolate them from ambient air that would impact similarity between the pods.
The enclosure was printed in Sunlu’s LW-PLA filament. It is unlike normal filament, and contains microscopic air bubbles which actively foam during the printing process. At the advantage of being 30-50% lighter than PLA, it is a nightmare to print with. I created a special print profile to make it somewhat bearable:
- It must be printed ~7x slower
- Cooling must be disabled/limited as it impacts foam expansion
- Bed temperature must be increased as adhesion is not great
- Acceleration must be disabled or else infill and walls will have varying strengths
With all these changes, it can still be very brittle and difficult to print if not properly dried. If you are interested in experimenting with this filament, you can download my print profile for Orca Slicer. I am open to recommendations!
The results
The hypothesis with the foaming PLA filament is that the microscopic air bubbles would provide a noticeable difference in insulation performance over typical PLA.
The data told a different story:

As you can see, there are no conclusive results regarding how foaming PLA performs versus bare PLA. There are times where foaming performs better, but the opposite can also be observed.
My suspicion is that the microscopic air bubbles in reality did nothing for actual insulation, and that for proper payload enclosures, infill and wall count matters much more than filament composition. Another thing to try may be multiline infill: insulation works on the property of air pockets slowing down heat transfer. Perhaps thicker walls between internal air pockets would help?
Even with the lack of results regarding insulation properties, it is clear that printing a custom payload enclosure is beneficial, as insulated sensors were ~7°C warmer than the ambient air. Better sealing would likely improve this substantially, and we also observed through simulations that radiation from the sun heated the payload several degrees if painted black instead of white.
This is a simulation Sam ran to verify that the 3D printed payload would be able to insulate the electronics from the cold ambient air:

Painting the foaming PLA enclosure with black acrylic paint
Foaming PLA filament still bears the crown in terms of the weight to strength ratio, so I am confident using it for future launches.
Image Transmission
Most amateur ballooning payloads have cameras. The view at 30 km up is incredible, and knowing those pictures came from a custom designed payload makes them even more special.
Last year, I transmitted images that were 18x10 pixels, which had no discernible details visible:

The reason I sent down such small images was due to limitations in the radio link: transmissions are slow and limited (by protocol) to 255 bytes. To combat the challenge, I designed an excessive and overly complex image compression algorithm, which in turn made transmitted images unusable.
While studying for my amateur radio license last year, I learned about SSTV (Slow Scan Television), a method of transmitting pictures over an analog video link. SSTV requires a high power budget (at least 5-20 watts) and produces images that are not up to my standard.
I did some more research and found SSDV (Slow Scan Digital Video), a packetized digital version of SSTV. Even if the ground station misses packets, the image can be reconstructed.
I modified Philip Heron’s C implementation of SSDV for my specific needs: I reduced the packet size, removed call sign transmission, and disabled the Reed-Solomon error correction as the radio link already does this. You can find my changes on GitHub.
The camera takes an image, saves a full resolution copy to the SD card, and encodes the 320x240 version before transmitting ~15 packets per image.

The ground station received 328 images throughout the flight, which you can view at the gallery.

Here is some image science on how images were captured at different altitudes, and how light was scattered differently leading to the sky turning black.

On the descent, the payload was swinging heavily. Here is a picture it captured of the sun:
The Sun Is A Deadly Lazer
This graph shows how images tended to look as altitude increased, with later images being able to see the black of space.

This shows a map of images taken throughout the flight.

I am very happy with how the images turned out this year!
Electronics

Prior to everything I have made since, last year’s payload circuit boards were the most complex design I had made. Since then, I have learned KiCad, a free and open source EDA program. With my changes in tooling, my skill has grown significantly.
The custom electronics had four main sections:
- Power Electronics (voltage regulator, load switch)
- Microcontroller (ESP32-S3, camera, SD card)
- GPS & Tracking (module, antenna, redundancy)
- Radio Link (SX1262)
- Sensor Integration (external SPI ADC, temperature sensors)
As usual, I had the boards manufactured by OSH Park, and they turned out perfect. Additionally, I got the boards open-source certified.

Power Electronics

With a low expected weight budget, my power budget was even lower than I thought. The use of 4x Energizer Ultimate Lithium double-A batteries worked well last launch due to ample weight, but I had to make tradeoffs and use 3x triple-A from Energizer’s same series. With a high power budget previously, I ran a Raspberry Pi Zero 2 W, an RP2040, and various sensors. The challenge with low power is finding solutions that work well, but efficiently and how you would like.
This payload used a buck-boost converter for power: meaning it stabilizes a solid 3.3V supply to the electronics whether or not the batteries are actually above this voltage. This is a significant upgrade, where I previously used highly inefficient low-dropout regulators, which purely drop voltage.
Mistakes Made
I originally had planned on using a load switch to control if the payload was turned on or off. This later proved to not actually work the way I implemented it, and provided power even if not intended to. In hindsight, the better solution would be using the mechanical switch as an ENABLE signal for the voltage regulator.
Later on in the project, I also accidentally shorted out the board when working on the battery holders and power supply. I was then unable to use the board with a functioning power supply, and instead relied on the microcontroller’s built-in buck regulator.
Battery voltage wasn’t correctly reported during flight due to the fact I possibly killed the voltage dividers meant to report battery health.
Microcontroller

I chose to use an ESP32-S3 microcontroller for data collection and transmission. Seeed Studio makes a variety of tiny microcontroller boards, including ones with cameras, SD cards, microphones, and WiFi. Using their XIAO ESP32-S3 Sense, I was able to fit the purpose of the Pi last year in a much smaller and more power efficient form factor.

The XIAO boards have few GPIO pins, and the camera and SD card claim most of them. To read analog sensors, I added an external SPI ADC (MCP3204), which the analog temperature sensors (MCP9700A) and the battery voltage divider both connect through. The divider is the one that stopped reporting mid-project.
Firmware was written in Arduino, rather than CircuitPython as I did last year. I have been wanting to write lower level code for a long time, and doing so this launch was a huge step for me. There are so many more considerations that must be taken when going this route: efficient memory management, obscure compiler errors, the lack of a native file system, and more. In the end, Arduino was a perfect choice for the firmware, and it made iteration easy despite an initial learning curve.
The firmware interfaces with all the sensors and modules: the ADC, radio, GPS, SD card, and camera. After setting up all hardware, a simple loop is followed where images are captured and packetized, telemetry data is collected, and the radio alternates between transmissions for SSDV and telemetry.
Mistakes Made
As everyone does at one point, I swapped MISO and MOSI for the SPI lines! I was able to fix this issue with some quick but otherwise janky bodges.

GPS & Tracking
The NEO-6M GNSS module used on StratoSpore was unreliable and hard to use. At a higher cost, I used the SAM-M10Q module this time. It has an integrated patch antenna, and used the ground plane of the circuit board as part of the setup. The datasheet notes using a 50x50mm ground plane is ideal, but it worked well at the 30x60mm size I used. It can be pretty sensitive indoors, sometimes working great or not, but I found using Assisted GNSS helped. During flight, the module was maxed out, tracking 32 satellites.
Live coordinates and altitude were transmitted over the radio link, and were then fed to Sam’s custom dashboard and SondeHub for live tracking and predictions.

As one of my goals was to use a secondary tracker, I programmed a QRP Labs U4B balloon tracker to transmit WSPR and JT9 at specific intervals on the 10 meter (licensed) band. These are weak-signal protocols and are very slow, with WSPR messages lasting 110.6 seconds, and JT9 at 50 seconds. While this is useful for tracking something like a picoballoon running on solar panels, it is inconvenient and not feasible to be used for tracking high altitude balloons on their descent.
Ultimately, the U4B did not fulfill its purpose, and was not suitable for tracking the balloon. In the future, I might try using a Tiny4FSK or making a standalone tracker running 70cm LoRa.
Radio Link

I used the Wio-SX1262 from Seeed Studio to integrate LoRa (Long Range) radio transmissions with the electronics. LoRa is meant for low-power transmissions that can reach far distances. It operates at 915 MHz (33 cm band) for unlicensed use, making it easy to get into.
LoRa has different configuration settings that affect how effectively transmissions can be received at distance. Spreading Factor controls the speed of the data transmission, going from SF7-SF12. I used SF9 as a good middle ground, up from SF7 last year. SF9 provides a receiver sensitivity of -129 dBm while not making packets too long.
Airtime is especially important for LoRa: the longer the message, the greater the chance of interference and symbol loss. Telemetry messages had 247 ms of airtime, with SSDV packets at 677 ms. During testing, longer messages at higher spreading factors were harder to receive with my SDR. Coding rate (error correction ratios) is also a factor in reception, but I found transmitting at SF9 with a coding rate of 4/5 (4 data bits + 1 parity bit, the lowest detection level with no correction) and 125 kHz bandwidth worked well. Shorter messages also buy us a cheaper failure: losing a small image packet doesn’t hurt as much as losing a big one.

Telemetry on the 33 cm band worked surprisingly well, and packets were received during the entire flight. There were occasional losses in signal during the chase, as we passed through some deep canyons and towns where we received interference.
All telemetry was packed into a single 35-byte packet. I was able to create a more efficient packet structure than last year, using packed latitude and longitude values rather than Plus Codes. I also took more care to use correctly sized integers.
SSDV images were also sent over the LoRa protocol with 128-byte packets, modified from Philip Heron’s implementation using 256 bytes. LoRa has built-in error detection, negating the need for SSDV to send this information.
Mistakes Made
I mistakenly configured the SX1262 to use its internal LDO, so it was operating inefficiently compared to using the DC-DC converter it has. This means it drew higher current than needed, draining batteries faster than expected.
Launch Day
UpLink was launched on August 16th, 2026 outside of Townsend, MT. In Montana, winds predominantly blow from west to east. Townsend was our best bet for launching, as we can clear the mountains east of it easily.

After planning to use a fishing scale for measuring free lift of the balloon and finding out it was broken, we had to settle with guessing lift from an inaccurate bathroom scale. With such a scale, the balloon ended up underfilled, and had a much slower ascent than expected: around 1.5-3 m/s for most of the flight. An ascent rate of 5 m/s is ideal for most flights, targeting a 2 hour flight.
The helium cylinder and regulator were provided for free by American Welding & Gas, which would have otherwise been expensive for the budget of two high school students.
As this was Sam and my first solo flight, Jared Kamp joined us with his expertise from his work at Montana State University’s BOREALIS program. His help was invaluable, ranging from calling in NOTAMs and the sheriff, to running numerous flight predictions so we had the best possible location to launch.
Along with Jared’s help, my dad and David Hansen also joined for the launch, assisting with setup of the balloon fill station, documenting on video, and providing extra hands for the balloon release.
The Flight
With the slower than expected ascent rate, the flight lasted close to 5 hours. During testing at home, I measured that the payload batteries lasted around 4.5 hours before dying. Unfortunately, this measurement stayed true with the real flight, and we lost radio contact around 15 minutes before the projected landing. Even with the U4B, we were not able to track it down. We suspect something happened to it and that it stopped transmitting entirely. We stopped seeing the WSPR and JT9 signals on the waterfall, and weren’t able to decode any messages in WSJT-X. There should have been plenty of battery life left, and I still don’t know why it stopped.
The balloon traveled 140 km (87 mi) downrange, and reached a burst altitude of 28.42 km (93,000 ft). Packet and SSDV imagery was decoded clearly for most of the flight, and the receiver experienced a median SNR of -4.8 dB.

The Search
The payload landed in central Montana, near Judith Gap. Without a ping from the payload as to where it landed, we were stuck with relying on SondeHub’s prediction to search near. 15 minutes before landing, SondeHub’s predictions are only so accurate: it could have been anywhere in a 3 km radius, or more.

We spent around 2 hours searching farmland on foot and by car near the landing projection, but were unsuccessful in locating the lost payload. We also got access to some private property to search, and it was still nowhere to be found. We stopped searching as it was getting late, and we had already been chasing it for 7 hours. If we had a ping on landing, we would have found it. If you live near Judith Gap and find it, please contact us. :)
Ideas We Dropped
As the electronics can get cold inside high altitude balloon payloads, we considered putting a hand warmer inside the payload to keep them functioning. There were two considerations when implementing hand warmers: how they affect RF and if they would continue to work at high altitudes.
Classic air-activated hand warmers were out of the picture due to potentially affecting GPS and LoRa functionality, since the iron powder could detune antennas in such close proximity. They also would stop working as the air thinned. Sodium acetate-based hand warmers were also an option, but proved to not last long (around 30 mins) and were too heavy (85 grams) to be feasible to put inside the payload.
With these options exhausted, we ended up not using anything to facilitate warming of the payload, as self-heating of the microcontroller was plenty. It stayed above freezing point for the entirety of the flight.
Reflections
Despite being an overall successful launch (besides us not finding it!), we still made many mistakes that can be improved upon for the future.
Proper Fishing Scale
With a working scale to measure free lift of the balloon, the flight would have been an appropriate length, preventing many further problems from occurring.
Payload Separation
With a low power budget from a long flight, the camera drew precious battery from the tracker payload. If these were to run on separate power, the payload would have been found.
70 cm Radio Link
While the 33 cm band proved to work well for tracking the balloon, I would like to experiment with the 70 cm band. 70 cm will give us better range for tracking, but we can keep SSDV on 33 cm for raw throughput of images.
SSDV Imagery
The 320x240 images we received were already beautiful, but I think with a freer radio link, we could send higher resolution images. Maybe even 640x480 px!
Even with the numerous problems we encountered, the goals at the start of the project were implemented (besides proper tracker redundancy). I am still proud of our accomplishments being the first independently organized flight we made.
Data and Source
All hardware, software, firmware, and CAD have been open sourced on our GitHub. Besides source code, we’ve included the data received during the flight, including position, GNSS module information, temperature data, microcontroller memory info, system flags, and receiver station RSSI/SNR. Available as a CSV, one row per received packet. All images are also in the gallery or in Git. This data is all we had received on the ground, so don’t expect full-res images or complete data.
Credits
The project was only possible because of the following:
- Sam Flynn for immense help with the dashboard, enclosure, and launch
- American Welding & Gas for supporting me with helium
- Jared Kamp for planning logistics of the launch and bringing valuable expertise from Borealis
- David Hansen for help with the launch and joining us on the chase
- My parents for supporting me throughout my long nights of work
- Max Kendall for his detailed launch guide and inspiring me to get into ballooning more