Through numerous flights using RTTY and dl-fldigi it has been found that dl-fldigi doesn't cope very well with too few stop bits, if you use 2 stop bits instead of 1 or 1.5 it is able to decode far better.
To transmit a character of RTTY first you send a start bit (transmitted as 0) followed by the binary of the character Least Significant Bit first, this is then followed by a 1 or 2 stop bits (transmitted as 1). So for the character 'd' the binary is:
01100100
Remember we transmit the Least Significant Bit first so swap it around:
00100110
We need to add on the start bit 0 and also two stop bits 11 to give us:
00010011011
This is easily done on the arduino using this code:
// ------------------------ // RTTY Functions - from RJHARRISON's AVR Code 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++; } } 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 } void rtty_txbit (int bit) { if (bit) { // high digitalWrite(4, HIGH); digitalWrite(5, LOW); digitalWrite(13, LOW); //LED } else { // low digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(13, HIGH); //LED } //delayMicroseconds(20500); // 10000 = 100 BAUD 20150 delayMicroseconds(20000); // 10000 = 100 BAUD 20150 } void setup() { pinMode(13, OUTPUT); //LED digitalWrite(13, HIGH); pinMode(5, OUTPUT); //Radio pinMode(6, OUTPUT); //Radio EN digitalWrite(6, HIGH); //Turn the radio on pinMode(4, OUTPUT); //Radio } void loop() { rtty_txstring("Hello World!\n"); delay(1000); }
On the first Atlas flight the crystal oven worked great, maintain the crystal at 0 deg C throughout the flight. There was still initially some drift as the radio cooled down from ground temperature to 0 deg C. For the next flight the set point will be 10 deg C , this will reduce the drift and also test how how good that heater is at maintaining the crystals temperature. The flight computer will be individually better insulated to improve the efficiency of the system.
The ublox5 GPS chip has different modes which optimise for a number of scenarios. By default the chip is in Mode 0: Pedestian - suited to being on the ground and so does not work above 12km altitude- this was demonstrated last flight where it stopped working. For a balloon flight we need to set the Nav5 mode to 6: <1g Airborne so that it'll work all the way up to 50km altitude. To do this we need to send a command to the module to change this setting and then check that we have successfully change it to Nav5 mode 6.
// 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 } } } } void setup() { // Check and set the navigation mode (Airborne, 1G) 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(); Serial.println(navmode, DEC); }
Satellite transmitter
int pin = 13; void setup() { pinMode(pin, OUTPUT); Serial.begin(9600); } void loop() { while(digitalRead(4) == HIGH) { digitalWrite(pin, HIGH); Serial.println("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47"); Serial.println("$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39"); delay(1000); digitalWrite(pin, LOW); } }