StratoExplorer is a privately operated technology demonstration for an edge-of-space flight of a stratospheric balloon probe. High altitude ballooning (HAB) got popular in recent years to send all sorts of electronics gadgets (such as smartphones, action-cams, sat-trackers) to the upper atmosphere – and eventually return and retrieve them safely. In contrast, StratoExplorer project focus is set on:
engineering (digital electronics, hardware) of lightweight and robust payload
software design and implementation (fault-tolerant, x-architecture, x-language: C++, Py)
long-range telemetry and IoT connectivity (multi-sensor, data replication, monitoring)
The project relies on ARM-Cortex M7 (“Teensy 4.1”) and ESP8266-12E micro-controller hardware for probe (“StratoExplorer”) and (mobile) ground station (“StratoExplorerRX”) respectively. Both devices make use of identical, proprietary libraries for task scheduling, data sampling and air-ground communications via 433 MHz LoRa. Moreover, both units are synchronized to GPS-based reference time. Therefore, switching of LoRa spreading factors (data rate and range) and bi-directionality (airborne probe acknowledges up-link messages) are available. For the “human” interface, an InfluxDb + Grafana stack is operated on raspberry-pi hardware: a) a Pi-zero device in a LAN with a smartphone (as: display, WiFi access point, Internet gateway), b) a Pi-4 device with replicated telemetry for “world”-access.
StratoExplorer: architecture diagram
StratoExplorerRX preview:
PyStratoExplorerRX “Cockpit” receiving (test) telemetry data from StratoExplorerRX. This gives an impression of the air-to-ground telemetry data received by the ground station: direct and derived information.
PyStratoExplorerRX cockpit web-interface, showing critical telemetry data and map view of 3 targets: payload, predicted landing site, tracking receiver.
Status & next steps
done:
Successful integration-testing-I (hw/sw, static non-flight) of StratoExplorer, StratoExplorerRX & PyStratoExplorerRX
next:
physical mounting of hardware + (long range) telemetry testing
integration-testing-II (hw/sw, simulated flight)
assembly with balloon + parachute and camera units
legal paperwork and flight scheduling
expect further pre-launch posts:
2/4: StratoExplorer 2.0: payload details
3/4: (Py)StratoExplorerRX details
4/4: reports from telemetry testing & integration-test-II
AirStation dashboard (Grafana) showing daily aggregated data
Following an initial version, I wanted to learn and extend from this experience:
Ozone sensor employed so far was a Winsen MQ131 analog sensor, sampled via a voltage divider/ADC circuit. The sensor required extensive burn-in and base resistance calibration and appeared to be critically sensitive to moisture – far beyond what was charted in the MQ131 datasheet’s figure 4: Rs/Rs0 vs. Temperature plot for 3 distinct values of rH%. While I was able to derive a continuous correction function(rH%,T) by interpolating between the graphs provided by the datasheet, this eventually did not resolve the humidity issue. From analysis of environmental data collected so far, MQ131 “runaways” in O3 reading coincided nicely with early morning humidity values rH > 65%. Looks like we have to abandon this cheap thing and go for Winsen’s digital sensor: ZE25-O3. Fortunately, AliExpress was quick to deliver !
AirStation’s central library “myTaskSchedulder” is controlling the asynchronous scheduling of various data sampling tasks and pre/post processing requirements and has seen multiple updates and fixes inspired by the ongoing StratoExplorer project which equally benefits from the lib’s capabilities.
While O3 and particulate matter are already quite rare for privately operated sensors, I wanted to add this one more thing that would make it unique of it’s kind: γ/β radiation ambient dose rate, i.e. a Geiger-Mueller tube counter.
AirStation 2.0 specs after success lab testing:
CPU: ESP8266-NodeMCU v2.8 µ-controller with WiFi.
OTA software updates with AS2.0 remaining connected to domestic WiFi.
DNS device name broadcast
NTP time reference for myTaskScheduler
Web service endpoint, delivering AS2.0 JSON data.
AirStationDb python backend + Postgres database (both on Pi3B) polling/storing AS2.0 data
Each of the sensor value(s) stored with sample time, average, min/max, standard-deviation.
Grafana dashboard (backend) showing spot values and time course.
Implementation notes:
ESP8266 is ideally suited for WiFi based IoT applications thanks to multiple, configurable digital ports. However, simultaneously connecting that many digital applications to a single device is creating issues due to subtle limitations on the CPU’s pins, i.e. interrupt capability, logic levels, behavior during device boot and flashing.
Ozone: ZE25-O3 connected via (Software-)Serial (9600, 8N1). Sensor has two modes that can be selected via serial: i. periodic reports, ii. on-demand reports. The latter mode appears handy but has a documented issue with ESP8266 software-serial. That’s why we operate in (default) periodic mode and invest a bit in parsing queued messages from the serial buffer. Since we are anyhow running out of hardware-serials on ESP8266 (and wanted to keep Serial-0 for bench-diagnostics), sw-serial is a good choice, because it’s ESP8266 implementation is able to handle multiple connections (at low baud rate). With choosing periodic-mode, we can use RX on pin D6 and abandon host TX, thus releasing one interrupt-capable digital pin D5 for the radiation sensor count trigger. Digital O3 readout is in ppb units, conversion to µg/m³ applied taking into account temperature correction according to EU standards. Sampling every 10 minutes for 1 minute at 2s intervals.
Particulate Matter (PM): SDS011 connected via (Software-)Serial (9600, 8N1). Needs both RX/TX to read data from device and switch on/off fan and laser. Warm up time 30s, 2 minutes sampling at 2s intervals, triggered every 3 hours: commanded by myScheduler. Caution: From available pins D7/D8 use D7 for RX. D8 is pulled to GND, boot fails if HIGH. Humidity correction applied according to Zbyszek Kiliański.
Radiation: Interrupt controlled, Geiger-Mueller tube J321 identified as J305/M4011 compatible. Count-per-minute / dose [µS/h] conversion factor: 0.00655. Connected to ESP D5 with an ISR which handles event counting independently from any other tasks. Rate computation + statistics controlled via myTaskScheduler: every 10 minutes for 5 minutes of event data.
BME280 THP: Connected via standard I2C bus SCL/SCA (D1/D2). Continuous sampling every 2s on a 5 minutes sliding average.
Code sample showing basic AS2.0 design:
main.cpp:
[..]
#include <myWifi.h>
#include <AirStation.h>
#include <AirStation_cfg.h>
#include <SensorPM.h>
#include <SensorO3.h>
#include <SensorTHP.h>
#include <SensorRAD.h>
[..]
// myTaskScheduler is given a reference time: SysTime
// SysTime is initialized with reference to wifi's getTimestamp()
// (This works equally well myGPS lib, providing sat-based time)
//
auto wifi = myWifi(CBN_HOME);
auto st = new SysTime(std::bind(&myWifi::getTimestamp, wifi));
auto ts = new myTaskScheduler(st);
[..]
//
// SYSTEM SETUP
//
void setup() {
Serial.begin(28800);
Serial.println("AirStation - setup:");
// Tasks being registered with myTaskScheduler
// Custom task must inherit from a generic Task class
//
ts->addTask("THP", new SensorTHP)->setOnError(RECOVER);
ts->addTask("PM" , new SensorPM )->setOnError(RECOVER);
ts->addTask("O3" , new SensorO3 )->setOnError(RECOVER);
ts->addTask("RAD", new SensorRAD)->setOnError(RECOVER);
ts->setPrintLevel(DEBUG_LEVEL);
wifi.start();
// some configuration options for SysTime
st->setTimeformat(&formatAirStationTimestamp);
st->setSyncInterval(12*3600);
st->autoTimeformat(true);
st->setSyncMode(AUTO);
[..]
bool status = ts->resetTasks() && ts->testTasks();
Serial.printf("SETUP: %s\n", status ? "OK":"FAILED");
}
//
// MAIN LOOP
//
void loop() {
server.handleClient(); // handle webservice requests
ts->run(); // have myTaskSchedule do its scheduling business
st->checksync(); // check sync with time reference
}
Next steps:
Finally assembly caused unexpected harm to the O3 digital sensor: When the sensor was mounted into a short plastic tube connecting it with the atmosphere outside the box, solvent-containing plastic glue was used. While drying, intense hydrocarbon vapor however “blinded” the sensor beyond recovery – a fact that was clearly pointed out in the sensor’s data sheet: “Do not leave the module in a high concentration of organic gas for long time which will cause the sensor zero point to drift and recover slowly” – I told myself: r.t.f.m, next time I will study every tiny detail of hardware documentation ! A replacement sensor is on it’s way from China.
Edit 25.08.2022: The new sensor has arrived from China and was tested ok. But, getting stable O3 readings is a challenge ! Two reasons for this: 1) 4-sensors setup: It appears that AirStation – once booted – performs flawlessly to process data from all sensors. However, with co-existence of radiation and ozone sensors (and the increase in wiring and EMI), there is an issue with ESP8266 boot mode due to “floating” pins which require the RST button to be pressed to properly initiate boot. 2) The Winsen ZE25-O3 is not only very sensitive to gas concentration but also to any airflow impacting the cover membrane of the device. Isolating the chip in a tube connected to a hole in the AirStation box turned out to be a bad idea in “outdoor” conditions. Any air movement flowing alongside or into the opening is inducing pressure oscillations which are being magnified by the sensor. Therefore it is more appropriate to locate the sensor protected within the box and rely on “smooth” air exchange induced by regular runs of the PM sensor fan.
Edit 14.09.2022: Winsen ZE25-O3 sensor has been relocated inside the box and EMI issues have been fixed. AirStation now running on ALL sensors: temperature, humidity, pressure, particulate matter, ozone, ambient radiation. This has required a downtime on Sep 14 resulting in a gap in the data recordings.
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.