Table of Contents
PicoAtlas
Sunday - Aim
Micro payload - balloon flight with a payload that weighs < 100g in total
Recently there has been considerable discussion on the UKHAS mailing list regarding the concept of micro payloads. The main thinking behind developing small payloads was a matter of cost and ease - to allow someone to launch as soon as possible.
However another way of thing would be that micro balloons could also be seen as an advancement of the 'standard' balloon payload - the development of optimised feather light payloads. The aim of PicoAtlas is to create in a week a ultra light payload without compromising on function. Micro balloons have only become possible with the development of smaller, lower powered modules and the ability to provide more power using lithium batteries.
PicoAtlas components won't necessarily be cheap - it however will be constructed from spare parts I've gathered over the years. The flight will be on Monday 17/1/11 from Cambridge, while this sized payload would do very well on a latex balloon another reason for developing such a light payload is to test out the concept using Mylar/foil party balloons as super-pressure balloons.
Finally I'll strive to document the complete build - hopefully this will be useful for future 'standard' payloads but also open up the concept of micro balloons to others.
This is also an invitation for people to get involved - while I'll be constructing the payload I'll certainly be needing help with code etc so feel free to get involved - will be on #highaltitude during the build so get in touch.
Components
- Seeeduino film - flight computer
- GPSbee Ublox module + patch antenna
- Radiometrix NTX2 10mW 434.075MHz module
- Aerocomm AC4868-250mW 868MHz 250mW Radio Modem
- 2000mAh LiPo Battery
- Insulation
- Mylar/Foil Party Balloon
Super-pressure balloons
Depending on how light I can make the payload we'll attempt to use a few Mylar balloons, these will be under-filled to allow them to ascend. As the balloon rises the helium expands to take up the balloons volume. However unlike latex balloons the foil won't stretch, maintaining its volume. This results in an increase in pressure but not volume - the balloon will stop ascending and float. The float altitude will depend upon the volume of helium used but will be approximately 5km, the lighter the payload the higher we can fly the balloon.
The limiting factor in a super-pressure balloon is the strength of the balloon material itself, as the pressure increases the balloon will slowly leak helium and will eventually lose buoyancy and descend. The other terminating factor is that the balloon bursts and the payload descends rapidly.
Functions
With these components PicoAtlas will be fully functioning:
- Main downlink 434.075MHz via dl-fldigi and spacenear.us
- Uplink/Downlink 868MHz 250mW via the Radio modems - accept serial data
- Temperature sensor (on-board the radio modem)
- Any other clever ideas we can come up with.
Reading
Monday - Design
Pseudo Code
- Setup hardware
- Setup outputs
- Setup NewSoftSerial
- Setup Aerocomm (baud rate)
- Main Loop
- Poll GPS
- Convert Data
- Read temperature
- Send over Aerocomm
- Send over NTX2
- Wait for uplink via Aerocomm
Code
Code Jobs
- Test, test and more testing
- Add control of aerocomm radio modem
- Set baud rate
- Grab temperature data
- Get 'In Range' info
- Add the ability to upload commands
- Tune the baud rate on the radio
Masses
- LiPo (2000mAh) Battery - 40.2g
- Aerocomm Radiomodem - 15.4g
- Radiometrix NTX2 - 5.7g
- GPSbee 3.0g
- Mini GPS patch antenna - 7.7g
- Arduino Pro - 13.6g
- Total = 85.6g
- Potential mass saving ideas
- Use a Seeeduino film instead of the Arduino Pro = -12.6g
- Smaller LiPo e.g. 980mAh = -18.2g
Tuesday - GPS interfacing
Hardware
The GPS module requires 4 connections:
- Vcc (3.3v Regulated)
- GND
- Tx
- Rx
The Arduino Pro I am using conveniently has a 3.3v output socket and so I created 2 connectors Tx and Rx together and then 3.3v and Gnd. While i adds a small amount of weight its worth using headers and sockets to connect the GPS to the Arduino as it allows you to disconnect and change them easily.
Now when the Arduino Pro is powered on the GPSbee also turns on and will start to try and find lock.
Software
The GPSbee uses a Ublox 5 Neo-5Q gps module, I use a modified version of the tinyGPS library to decode the GPS location data. Most GPS modules output a stream of text which contain the location data called NMEA. This is relatively easy to decode however you have to configure your flight computer to wait and collect the burst of data (every 1 second). Ublox 5 GPS modules have a great feature where you can send the GPS module a command it'll send you back a single string with all the data you need. The modified tinyGPS library is configured to accept the returned data.
First thing is to grab the modified tinyGPS library and install it, then import it into your Arduino sketch.
Setup
In the code, when you boot the Arduino you need to setup the serial port, currently the GPS is connected to the hardware serial port of the Arduino Pro. All this code should go in the setup function.
Serial.begin(9600);
Next you need to wait for the ublox module to completely boot
delay(5000);
Once booted it'll be ready to accept commands. Next step is to turn off the NMEA data stream as it'll just confuse the library.
Serial.println("$PUBX,40,GLL,0,0,0,0*5C"); Serial.println("$PUBX,40,GGA,0,0,0,0*5A"); Serial.println("$PUBX,40,GSA,0,0,0,0*4E"); Serial.println("$PUBX,40,RMC,0,0,0,0*47"); Serial.println("$PUBX,40,GSV,0,0,0,0*59"); Serial.println("$PUBX,40,VTG,0,0,0,0*5E");
Again you should wait a little while to let it process the commands.
delay(3000);
Finally you should set the UBlox module to airborne mode to allow it to work over 12km altitude
uint8_t setNav[] = {0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC}; sendUBX(setNav, sizeof(setNav)/sizeof(uint8_t)); navmode = getUBXNAV5();
This also checks to see that the mode has been set and places the result in the variable navmode. For airborne <1g mode the result will be 6.
Loop
To read the GPS module you need to send the command requesting for a single string to be returned with the location data.
Serial.println("$PUBX,00*33"); //Poll GPS
Next you need to wait for the reply from the GPS module
while (Serial.available()) { int c = Serial.read(); if (gps.encode(c)) { //Get Data from GPS library //Get Time and split it gps.get_datetime(&date, &time, &age); hour = (time / 1000000); minute = ((time - (hour * 1000000)) / 10000); second = ((time - ((hour * 1000000) + (minute * 10000)))); second = second / 100; } }
In this section of code the Arduino checks to see if there is any data waiting in the serial port buffer, if there is it feeds it into the tinyGPS library and once a complete string is decoded it starts to process it. First it gets the time data which is returned in a long number and splits that into the main components with a little bit of maths.
Now all the data is stored in the tinyGPS library we can easily access it and don't need to read the serial port again (until the next loop of course). First we can grab the number of satellites the GPS module is tracking.
numbersats = gps.sats();
We can also check if the GPS thinks it has a position lock
navstatus = gps.navstatus();
If the GPS does have a lock then we should get the location and altitude data and process it.
if (numbersats >= 1) { //Get Position gps.f_get_position(&flat, &flon); //convert float to string dtostrf(flat, 7, 4, latbuf); dtostrf(flon, 7, 4, lonbuf); //just check that we are putting a space at the front of lonbuf if(lonbuf[0] == ' ') { lonbuf[0] = '+'; } // +/- altitude in meters ialt = (gps.altitude() / 100); }
The latitude and longitude are returned as floats which will be useful for calculations however for transmitting this data we'll want it as a string so we use dtostrf to convert them. As dtostrf sometimes puts a space at the front of the converted longitude if it is positive we just check for this and if necessary swap the space for a plus sign. Finally we get the reported altitude and store it as a long int (long int rather than int as at maximum altitude it'll will exceed the size of a normal int).
Finally for all this to work you'll need to add two functions and some global variables to the top of your sketch , these functions are used to set and check the navigation mode to allow it to go above 12km altitude (quite useful for high altitude balloons!)
TinyGPS gps; byte navmode = 99; float flat, flon; unsigned long date, time, chars, age; int hour = 0 , minute = 0 , second = 0, navstatus = 0, numbersats = 99; char latbuf[12] = "0", lonbuf[12] = "0"; long int ialt = 123; // Send a byte array of UBX protocol to the GPS void sendUBX(uint8_t *MSG, uint8_t len) { for(int i=0; i<len; i++) { Serial.print(MSG[i], BYTE); } Serial.println(); } // Get the current NAV5 mode int getUBXNAV5() { uint8_t b; uint8_t byteID = 0; int startTime = millis(); // Poll/query message uint8_t getNAV5[] = { 0xB5, 0x62, 0x06, 0x24, 0x00, 0x00, 0x2A, 0x84 }; // First few bytes of the poll response uint8_t response[] = { 0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF}; // Interrogate Mr GPS... sendUBX(getNAV5, sizeof(getNAV5)/sizeof(uint8_t)); // Process his response... while (1) { // Timeout if no valid response in 3 seconds if (millis() - startTime > 3000) { return -1; } // Make sure data is available to read if (Serial.available()) { b = Serial.read(); // 8th byte is the nav mode if (byteID == 8) { return b; } // Make sure the response matches the expected preamble else if (b == response[byteID]) { byteID++; } else { byteID = 0; // Reset and look again, invalid order } } } }
Wednesday - Radio interfacing
Radiometrix NTX2
The Radiometrix NTX2 is the workhorse of UK high altitude balloonining, there are 2 frequencys we can use 434.075Mhz and 434.650Mhz. It is recommended that you use the 434.075Mhz module as this does not clash with any other users (well an experimental band which is clear) while 434.650Mhz is the output frequency of a number of amateur radio repeaters. Each module has a set centre frequency and so you need to take this into account when you order them. The module transmits with a power of 10mW, it has 4 pins to control the module and 3 pins to the antenna - this is all well detailed in the datasheet.
The output pins are:
- En - this enables the radio when pulled high and puts it to sleep when pulled low (do not leave floating)
- Vcc - requires between 2.7v and 15v (has onboard reg)
- Gnd
- Tx - the module will vary its frequency depending upon the voltage applied to this pin.
Our aim is to produce RTTY using this module. RTTY is a commonly used protocol in amateur radio and is a similar concept to digital - we have a high and a low, we send a character in binary - when its a 1 it goes high and for a 0 it goes low. We need to get the module to produce two alternating frequencies (the high and low), with a very small shift in between (e.g. 425Hz) which will make two tones on our receiving radio allowing it to decode the data. To create these two frequencies we apply 2 voltages to the Tx line e.g. 1.1v and 1.3v.
To produce these two frequencies there are a number of ways; for picoatlas we are going to use a resistor divider and two pins from the Arduino.
Arduino Radio 8 ------------------------------- EN 9 ---22K -------------\ ---------- TX 10---22K -- 2K2 - 2K2-/ GND-------------------------------GN 3v-------------------------------VCC RF_OUT
In this diagram you can see that pin 9 is connected to a 22K resistor and then to Tx, pin 10 is connected to a 22K, 2K2 and another 2K2 and then the Tx pin. There is a difference in the resistance between the two pins now of 4K4 ohms. To send a 1 or a HIGH we set pin 9 to high and set pin 10 to low, this creates a resistor divider and produces a voltage at the Tx. To send a 0 or a LOW we do the opposite and so set 9 low and 10 high which forms a different resistor divider producing a slightly different voltage. The resistors shown here work for my current setup and create a 425hz shift in frequency but it is necessary to tune the values of the resistors depending on your own setup.
Now that the hardware is done all we need to do is to take the binary version of a character and alternate our pins 9 and 10 to create the 2 different tones.
void rtty_txstring (char * string) { /* Simple function to sent a char at a time to ** rtty_txbyte function. ** NB Each char is one byte (8 Bits) */ char c; c = *string++; while ( c != '\0') { rtty_txbyte (c); c = *string++; } }
This function takes a string and then feeds each character separately in order into another function rtty_txbyte to be sent via the radio. So we now have a single character to send, in RTTY we first send a start bit to tell the recevier we are sending data, we then send the binary form of the character and then this is followed by a stop bit (or two in this case.
void rtty_txbyte (char c) { /* Simple function to sent each bit of a char to ** rtty_txbit function. ** NB The bits are sent Least Significant Bit first ** ** All chars should be preceded with a 0 and ** proceded with a 1. 0 = Start bit; 1 = Stop bit ** ** ASCII_BIT = 7 or 8 for ASCII-7 / ASCII-8 */ int i; rtty_txbit (0); // Start bit // Send bits for for char LSB first for (i=0;i<8;i++) { if (c & 1) rtty_txbit(1); else rtty_txbit(0); c = c >> 1; } rtty_txbit (1); // Stop bit rtty_txbit (1); // Stop bit }
The final bit of code does the hard work of switching the pins HIGH and LOW depending on whether it is a 1 or a 0
void rtty_txbit (int bit) { if (bit) { // high digitalWrite(9, HIGH); digitalWrite(10, LOW); digitalWrite(13, LOW); //LED } else { // low digitalWrite(10, HIGH); digitalWrite(9, LOW); digitalWrite(13, HIGH); //LED } delayMicroseconds(20000); // 10000 = 100 BAUD }
This code again requires some tuning, delayMicroseconds allows you to vary the speed of the transmission, it will depend on what frequency your arduino is working at as well - again in this project I have found that delayMicroseconds(20000) gives me 50 baud.
Of course you'll need to use these functions so:
void setup() { pinMode(13, OUTPUT); //LED pinMode(9, OUTPUT); //Radio Tx0 pinMode(10, OUTPUT); //Radio Tx1 pinMode(11, OUTPUT); //Radio En digitalWrite(11, HIGH); // Enables the radio on, if set to LOW will put radio to sleep } void loop() { rtty_txstring("Hello World\n"); delay(500); }
Now listening to the radio tuned to the right frequency you should hear the characteristic 'warble' of RTTY, when you connect the radio to your computer and run dl-fldigi you be able to see the 2 frequencies on the waterfall and if you set it up to decode you'll get the data you sent:
- ASCII-8
- 50 baud
- 425 Shift
- No parity
- 2 Stop bits
So how do we send the data that we've grabbed off the GPS, for the rtty_txstring function we need to provide a string but much of our data are integers so we need to use sprintf to make the string, for example:
n=sprintf (superbuffer, "$$PICO,%d,%02d:%02d:%02d,%s,%s,%ld,%d,%d,%d;%d", count, hour, minute, second, latbuf, lonbuf, ialt, navstatus, numbersats, navmode, txmode); if (n > -1){ n = sprintf (superbuffer, "%s*%04X\n", superbuffer, gps_CRC16_checksum(superbuffer)); rtty_txstring(superbuffer); }
Once we've formed the first string in superbuffer we then need to generate the checksum. Now we have a string with a checksum at the end ready to be transmitted using the new rtty functions.
AeroComm Radio Modem (868Mhz)
This modem is slightly easier to use as it takes serial data, does all the hard work encoding the data and then decodes it on the other side and spits it out as serial data.
As the Arduino only has 1 serial port we'll be creating another using a software library, the theory is very similar to what we did with the NTX2 toggling a pin with high and low depending on the character however its at a far faster rate then before - best to let the library do the work.
For the hardware the Aerocomm requires 4 lines:
- Vcc (3.3-5.5v)
- Gnd
- Tx
- Rx
As we are doing software serial we can chose which outputs we use on the Arduino, I'm using pins 2 and 3. For this we are using the excellent NewSoftSerial library which will work with our Arduino. You'll need to download and install it first, then import it into your sketch. You'll also need to tell it which pins to use as its rx and tx.
#include <NewSoftSerial.h> NewSoftSerial nss(2, 3);
In your setup loop
void setup() { nss.begin(57600); }
Now you can treat it just like a normal serial port so to send data you use:
nss.println("Hello World");
Now we can send data easily to the Aerocomm radio and receive it on the other side.
Software serial is also useful for debugging your project if you are using the hardware serial, or you could put the GPS on to the software serial pins instead of using the hardware serial.
Friday - Payload construction + Testing
Update
Now that all the components are working onboard I've decided to remove the AeroComm radio modem from the payload - as this is an experimental flight using foil balloons to do super pressure then its probably best not to also try out an experimental new form of communication at the same time. This will also reduce the mass of the payload allowing us to use less helium and so ascended to a higher altitude.
I've therefore created a new Arduino sketch on my github Pico2 where I've removed the newsoftserial parts.
Low Power Mode
As this is a long duration flight I've added in some additional if clauses at the end of the loop. The scenarios are:
- For the first 1000 loops it'll transmit with only a gap of 1 second between strings - this is to allow for easy setup and initial tracking.
- After 1000 loops it'll then vary its transmission rate depending on the time - this is to maximise receiving but at the same time implementing some low power modes to save on batteries.
- Evening mode (0) - between 1600UTC and 2200UTC - the most likely time that people will be at home and able to listen in - only 1 second gaps (similar to < 1000) and the radio isn't turned off
- Day mode (1) - between 0600UTC and 1600UTC - people at work/school but some people able to listen out - radio is powered down for 10 seconds between strings
- Night mode (2) - people are asleep - radio powered down for 30 seconds in between strings.
if (count < 1000) { delay(1000); txmode = 0; } else { if (hour > 6 && hour < 16) { txmode = 1; //day mode digitalWrite(A0, LOW); //radio sleep delay(10000); //sleeping 10 seconds digitalWrite(A0, HIGH);//radio on delay(3000);// wait for it to 'tune' up } else if (hour > 16 && hour < 22) { txmode = 0; //evening mode digitalWrite(A0, HIGH); delay(1000); } else { txmode = 2; //night mode digitalWrite(A0, LOW); //radio sleep delay(30000); //sleeping 30 seconds digitalWrite(A0, HIGH);//radio on delay(3000);// wait for it to 'tune' up } }
Antenna
For this flight I'm going to use the trusty 1/4 wave + 4x radial design. From the radiometrix NTX2 there is a short piece of coax, at the end is a 16.4cm piece of wire soldered onto the core wire and then 4x 16.4cm radial wires soldered to the shield. Be careful with the solder joints as they are often a weak spot and if your antenna falls off you'll struggle to track your payload! I often put a straw over the wires to keep them straight and also reduce the risk of stressing and damage.
Saturday - Final preparations
Jobs
Secure coax to radio - hot glueMount onto small piece of card for a bit of rigidityCharge LiPo cells- If feeling brave test in freezer
- Get bubblewrap
Monday - Launch
Mission report
After arriving a little late we met in CUED, collected the launch gear and headed over to Churchill where we met up with G8KHW. After adding some more insulation to the payload we turned it on and placed it outside in the rain where it got a lock in a few minutes. We then set about filling the balloons. Using a piece of silicone tubing left over from ballasthalo we pushed this up into the foil balloon through the internal valve and attached this with tape to the normal filling tube. We inflated the first balloon ~50% and realised that we wouldn't get enough lift. We then filled the second large balloon and still not enough lift so we also attached the two spare small 48cm balloons we had spare. After removing the newly added insulation and the antenna radial supporting straws we had a bit of positive launch and released the balloon.
The ascent rate was incredibly slow, reaching cloud layers resulted in the balloon nearly stopping ascending and occasionally descending. After an hour in the air and a good number of stations receiving the data the launch team dispersed. The balloon continued to climb slowly with an slow reduction in ascent rate. As can be seen on the altitude graph it seems to have dropped a bit, climbed again and then started to ascend. Its difficult to work out exactly what happened and will certainly require another flight which is slightly more scientific in its calculations.
The balloon gently descended over Ipswich then turn south crossing over a number of estuaries to land in Essex to the west of Harwich. The recovery team went out that night and while were able to pick up the last position of the payload over the radio couldn't see the payload and due to the rain it was incredibly muddy. The next day as they headed over to try again there was a phone call to say the farmer had recovered it for us and placed it in his garage for us to collect.
On arriving we found the balloons and payload sitting on the ceiling of the garage - obviously the morning sun had warmed the He sufficiently for enough lift. The payload was still transmitting though was showing signs of the battery running out as the tx was unstable, it was also quite wet - the foam insulation soaking up water.
- Launch points
- Created a 'spacer' to allow easy filling - just a piece of tape over the end of our normal filling tube with a bit of 3mm tubing pushed through and then more tape to seal.
- Very early on we found that 1 balloon wasn't enough, 2 balloons wasn't enough, 2 balloons + 2 small balloons was enough when we removed all the external insulation on the payload and the straw supports on the antenna. In future we'll need at least 3 balloons and a lighter payload.
- Ublox 5 gps worked great - got a lock very early on which makes the launch a lot less stressful.
- Its a challenge to fill multiple balloons equally.
- If use use a rubber tube to fill when you remove it you will end up pulling out the internal seal plastic - means you can't fill it up more however does mean you can seal the balloon well (twist and tape would work well).
- Balloon didn't float - though the ascent rate slowed considerable, looking at the altitude graph you can see a number of blips which were probably cloud layers.
- Temperature seems to have had a lot of effect on the ascent rate and with the sun beginning to set
- The lose of one of the 'lift' small balloons
- Foam insulation soaking up water
- Tracking went well - got good reception reports though out the flight despite the low altitude.
Receivers
Receiver | No. of strings decoded |
---|---|
G0KYA | 212 |
G3VZV | 529 |
G3VZV with funcube SDR | 292 |
G4FEV | 771 |
G7LEU | 31 |
G8KHW | 80 |
M6JCX | 105 |
M6LEP | 613 |
Improvements for MkII
- Lighter payload
- Smaller battery - 1000mAh
- Better power saving in the code
- Smaller GPS antenna
- Lighter wire UHF antenna
- Use seeeduino rather than arduino pro
- More balloons - order 4 91cm balloons and see how many we need to use
- Preamble before tx'ing when in modes that have gaps
- Temperature sensor
- Photodiode sensor
- Don't use foam insulation as it'll soak up water and increased the payload weight
- Code mistake
- Due to a mistake with using > rather than >= it dropped into night mode between 1600 and 1700 rather than evening mode