COTB R ‘n’ D

Payload

The payload consists of an Arduino Nano, GSM transceiver, SD card module, LoRa transceiver and Neo 6m GPS receiver with active 3v3 antenna, all soldered to a protoboard. Using a 17.3cm quarter wave monopole with a 4 radial groundplane, a bandwidth of 62.5KHz, 10mw TX power and LoRa’s Chirp Spread Spectrum modulation on the 70cm ISM band a string of telemetry has a range of a few hundred kilometres. The telemetry string will include parsed NMEA data, altitude, heading, speed and internal/external temperature from a 18B20 and TMP36GT9Z sensor. The receiver will compute the received telemetry and upon calculating a 16bit checksum will upload to the online Habhub for easy access and tracking throughout the flight. The payload will experience violent turbulence, temperatures as low as -40°C and minimal heat dissipation from the high altitude environment of only a few percent atmosphere. Lift will be provided from a high altitude weather balloon with an inline parachute which will self deploy once the balloon expands to its maximum width of approximately 8 meters around 100,000ft (35km) and burst! Permission is of course required from the CAA before deployment. For further information please refer to Dave Akerman’s (M0RPI) website, his efforts and extensive documentation has made this project possible for myself and many others.

3km Range – Live Image Stablity

Google Earth Telemetry Test

Arduino IDE Code

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <LoRa.h>
#include <SD.h>
#include <OneWire.h>
#include <util/crc16.h>

static const int RXPin = 7, TXPin = 6;
const int chipSelect = 4;
int sensorPin = 6;
int counter = 0;
String telemetry;
char telemetry_copy[100];

#define GPS_BAUD 9600
#define gpsPort ssGPS

OneWire  ds(8);
TinyGPSPlus tinyGPS;
SoftwareSerial ssGPS(RXPin, TXPin);

void setup()
{
 pinMode(9, OUTPUT);
 Serial.begin(9600);
 gpsPort.begin(GPS_BAUD);
 
//  ****** LoRa Module Check ****** 

 if (!LoRa.begin(433.525E6)){
   Serial.println("Starting LoRa failed!");}

//  ****** SD Card Module Check ******  

 if (!SD.begin(chipSelect)){
   Serial.println("SD Card failed, or not present");}

//  ****** LoRa Module Settings ******

//  LoRa.setSPIFrequency(6);  
 LoRa.setTxPower(17); // 2-17 
 LoRa.setSpreadingFactor(11); //6-12
 LoRa.setCodingRate4(8); //5-8  
 LoRa.setSignalBandwidth(62.5E3);  //7.8E3, 10.4E3, 15.6E3, 20.8E3, 31.25E3, 41.7E3, 62.5E3, 125E3, and 250E3.
   
/// ****** Prepare SD Card File ******     

 File Data = SD.open("Data.txt", FILE_WRITE);
 Data.println("HAB ID, Counter, Time, Lat, Long, Altitude, Sats, Int Temp, Ext Temp");  
 Data.close(); 

/// *** Buzzer Confirm Setup ***  

 delay(200);
 tone(9, 2000); 
 delay(100);
 noTone(9);
 delay(50);
 tone(9, 2000); 
 delay(100);
 noTone(9);
  
}

 // ****** CRC Checksum ******
 
uint16_t gps_CRC16_checksum (char *string)
{
 size_t i;
 uint16_t crc;
 uint8_t c;

 crc = 0xFFFF;

 // Calculate checksum ignoring the first two $s
 for (i = 2; i < strlen(string); i++)
 {
   c = string[i];
   crc = _crc_xmodem_update (crc, c);
 }

 return crc;
}
void loop()
{
 Main();
 SmartDelay(20000); 
}
void Main()
{
    
// ****** Temperature Sensor ****** Bus Upto 50 Sensors ******

 byte i;
 byte present = 0;
 byte type_s;
 byte data[12];
 byte addr[8];
 float celsius;      
 if ( !ds.search(addr)) {     
   ds.reset_search();    
   return;  }  
 ds.reset();
 ds.select(addr);
 delay(1000);
 ds.write(0x44, 1);  
 delay(1000);  
 present = ds.reset();
 ds.select(addr);    
 ds.write(0xBE); 

// ****** Internal Temperaure Data Conversion to Celcius ******

 for ( i = 0; i < 9; i++) {
   data[i] = ds.read();    }
 int16_t raw = (data[1] << 8) | data[0];
 if (type_s) {
   raw = raw << 3;
   if (data[7] == 0x10) {
     raw = (raw & 0xFFF0) + 12 - data[6];  }  }
   else {
   byte cfg = (data[4] & 0x60);    
   if (cfg == 0x00) raw = raw & ~7; 
   else if (cfg == 0x20) raw = raw & ~3; 
   else if (cfg == 0x40) raw = raw & ~1;   }    
 celsius = (float)raw / 16.0;  

// ****** External Temperature Sensor ******

 delay(500);
 int reading = analogRead(sensorPin);
 float voltage = reading * 5.0;  //Reference voltage 5.0 for pefect 5v line
 voltage /= 1024.0;
 float temperatureC = (voltage - 0.5) * 100;

// ***** String Edit ******

 float latt = (tinyGPS.location.lat());
 float lngg = (tinyGPS.location.lng());
 float alt = (tinyGPS.altitude.meters());

 String telemetry = "$CornOnTheBranch,";

 telemetry += counter; telemetry += ",";
   if (tinyGPS.time.hour() < 10) telemetry += "0";
 telemetry += (tinyGPS.time.hour());
 telemetry += ":";  
   if (tinyGPS.time.minute() < 10) telemetry += "0";
 telemetry += (tinyGPS.time.minute()); 
 telemetry += ":";
   if (tinyGPS.time.second() < 10) telemetry += "0";
 telemetry += (tinyGPS.time.second());
 telemetry += ","; 
 telemetry += String(latt, 6); telemetry += ","; 
 telemetry += String(lngg, 6); telemetry += ","; 
 telemetry += String(alt, 1); telemetry += ","; 
 telemetry += (tinyGPS.satellites.value()); telemetry += ",";
 telemetry += celsius; telemetry += ",";
 telemetry += temperatureC;
 telemetry += "*";

 telemetry.toCharArray(telemetry_copy, 100);

// *********** Debug **************
 
 Serial.println(telemetry);
 Serial.println(telemetry_copy);
 Serial.println(gps_CRC16_checksum(telemetry_copy), HEX);

// ****** Transmit Packet ******

 LoRa.beginPacket();
 LoRa.print(telemetry); 
 LoRa.println(gps_CRC16_checksum(telemetry_copy), HEX);
 LoRa.endPacket();

// ****** Buzzer Confirm ******    
  
 tone(9, 2000);
 delay(100); 
 noTone(9);
 delay(500);
 
// ****** Save To SD Card ****** 

 File Data = SD.open("Data.txt", FILE_WRITE);
 if (Data) {
   Data.println(telemetry);
   Data.close();    }   
   delay(500); 

// ****** Plus 1 to Counter ******   

 counter++;  

}

// ****** Timing ******

static void SmartDelay(unsigned long ms)
{
 unsigned long start = millis();
 do
 {
   while (gpsPort.available())
     tinyGPS.encode(gpsPort.read());
 } while (millis() - start < ms);
}