[Flightcomputer] HoHoHo 3

Parts List

  • NTX2 Radio transmitter
  • GPS receiver with serial interface
  • Arduino or equivalent
  • Sony Ericsson with serial (old) interface
Code The code consists out of two parts: the main controller (Arduino Mega) and a code for the slave controller (which controlled the servo-release (Arduino Duemilenova)). So now first the Master code, then the Slave code. Master Code
  1. // Project Hollands Hoogte Dec 2010
  2. // By Tim Zaman
  3. // Help from Terry Baume (& ntx2 by jharrison)
  4. // Digital Pins
  5. #define GPS_PIN_RX              9       // GPS serial pin RX
  6. #define GPS_PIN_TX              8       // GPS serial pin TX
  7. #define RTTY_PIN_1 		2	// RTTY space pin
  8. #define RTTY_PIN_2 		3	// RTTY mark pin
  9. #define GSM_PIN_RX              5       // GPS serial pin RX
  10. #define GSM_PIN_TX              4       // GPS serial pin TX
  11. #define PHOTOPIN                7       // Photopin to EOS350D
  12. #define RELEASEPIN              6       // Releasepin to Arduino Duemilenova
  13. // Baudot
  14. #define ARRAY_LEN 32
  15. #define LETTERS_SHIFT 31
  16. #define FIGURES_SHIFT 27
  17. #define LINEFEED 2
  18. #define CARRRTN  8
  19. #define is_lowercase(ch)    ((ch) >= 'a' && (ch) <= 'z')
  20. #define is_uppercase(ch)    ((ch) >= 'A' && (ch) <= 'Z')
  21. // T68i
  22. #define num_to_char(number)   ((number) < 10 ?
  23.                                                ('0' + (number)) :
  24.                                                (('A' - 10) + (number)) )
  25. #define first_four(byte)       (0x0F & (byte))
  26. #define last_four(byte)      ((0xF0 & (byte)) >> 4)
  27. #define hexdump_a(byte)  num_to_char( last_four(byte))
  28. #define hexdump_b(byte)  num_to_char(first_four(byte))
  29. // Misc
  30. #define RTTY_ASCII      7       // ASCII set for RTTY (7/8bit)
  31. #define GPSRATE         9600    // GPS baud rate
  32. #define BUFFERSIZE      90      // How many bytes of input to buffer from the GPS?
  33. #define ENDLN           "rn"  // SD
  34. #include <stdint.h>
  35. #include <util/crc16.h>
  36. #include <flash.h>
  37. #include <streaming.h>
  38. //#include <newSoftSerial.h>
  39. #include <softwareSerial.h>
  40. //baudot
  41. char letters_arr[33] = "00EnA SIUrDRJNFCKTZLWHYPQOBG00MXV00";
  42. char figures_arr[33] = "003n- a87r$4',!:(5")2#6019?&00./;00";
  43. // Initialize flight variables
  44. int numSats = 0;
  45. int fixType = 0;
  46. int time[] = {
  47.   0, 0, 0};
  48. double latitude = 0.0;
  49. double longitude = 0.0;
  50. long altitude = 0;
  51. long maxAlt = 0;
  52. int speed = 0;
  53. int txCount = 0;
  54. int intTemp = 0;
  55. int extTemp = 0;
  56. int intHum = 0;
  57. int bitRate = 50;
  58. int descent = 0;
  59. double lon_release = 5.59;
  60. double lon_test = 4.6996;
  61. unsigned long SmsStart = 0;     // SMS-time
  62. unsigned long GpsAltTime = 1800000;    // 1.800.000ms=1.800s=30min
  63. int ExecOnce=0;             // execut0r
  64. int ExecOneRelease=0;          // voor 24km limit ding
  65. char buffer[BUFFERSIZE];
  66. byte nxtln[] = ENDLN;                       //SD ENDLNn
  67. unsigned long NXTlength = sizeof(ENDLN)-1;  //SD ENDLNn length
  68. SoftwareSerial GPS = SoftwareSerial(GPS_PIN_RX, GPS_PIN_TX);  //(rx,tx)
  69. SoftwareSerial GSM = SoftwareSerial(GSM_PIN_RX, GSM_PIN_TX);  //(rx,tx)
  70. void setup() {
  71.   // Start up serial ports
  72.   Serial.begin(9600);
  73.   Serial.println("Serial started");
  74.   GPS.begin(4800);
  75.   GSM.begin(9600);
  76.   // LED's
  77.   delay(1000);
  78.   GPS.println("$PSTMNMEACONFIG,0,4800,1,1");
  79.   GPS.println("$PSTMINITGPS,5200.000,N,00421.000,E,0197,22,10,2007,11,40,00");
  80.   GPS.println("$PSRF103,02,00,00,01*26");
  81.   // Canon EOS 350D
  82.   pinMode(PHOTOPIN,OUTPUT);
  83.   pinMode(RELEASEPIN,OUTPUT);
  84.   // Setup for RTTY
  85.   pinMode(2, OUTPUT);
  86.   pinMode(3, OUTPUT);
  87.   //GPS
  88.   pinMode(GPS_PIN_RX, INPUT);
  89.   pinMode(GPS_PIN_TX, OUTPUT);
  90.   //GSM
  91.   pinMode(GSM_PIN_RX, INPUT);
  92.   pinMode(GSM_PIN_TX, OUTPUT);
  93. }
  94. void loop() {
  95.   // Get a GGA string from the GPS,
  96.   // check if it's a valid fix, and extract the data
  97.   getNMEA("$GPGGA");
  98.   numSats = getSats();
  99.   fixType = getFixType();
  100.   digitalWrite(RELEASEPIN, LOW);
  101.   // Make sure we have a valid fix
  102.   if (fixType != 0) {
  103.     getTime(time);
  104.     latitude = getLat();
  105.     longitude = getLong();
  106.     altitude = getAlt();
  107.     // Keep track of the maximum altitude
  108.     if (altitude > maxAlt) {
  109.       maxAlt = altitude;
  110.     }
  111.     // Check to see if we've fallen 600m, if so switch to descent mode
  112.     if (altitude < (maxAlt - 600)) {
  113.       descent = 1;
  114.       if (ExecOneRelease == 0){
  115.         ExecOneRelease = 1;
  116.         digitalWrite(RELEASEPIN, HIGH);  //Release
  117.       }
  118.     }
  119.    }
  120.   // Convert lat & long into strings
  121.   char latString[12];
  122.   char longString[12];
  123.   doubleToString(latitude, 4, latString);
  124.   doubleToString(longitude, 4, longString);
  125.   sprintf(buffer, "$$HHH,%d,%02d:%02d:%02d,%s,%s,%ld,%d", txCount, time[0], time[1], time[2], latString, longString, altitude, numSats);
  126.   txCount++;
  127.   if (fixType != 0) { //Als we een fix hebben
  128.     if(txCount >100){ //En we zeker 100 strings hebben gehad
  129.       if (longitude > lon_release){ //En hij is rond flevoland
  130.         ExecOneRelease = 1;
  131.         digitalWrite(RELEASEPIN, HIGH);
  132.         TxString("RELEASE MECHANISM IN OPERATION");
  133.         delay(100);
  134.       }
  135.     }
  136.   }
  137.   if(txCount == 10){
  138.    send_sms(buffer);
  139.    delay(50);
  140.   }
  141.    if (txCount >12){ //Na 12 strings
  142.       if ( (txCount & 0x01) == 0) { //Elke oneven
  143.         digitalWrite(PHOTOPIN, HIGH);  //Maak foto
  144.         Serial.println("Foto");
  145.     }
  146.   }
  147.   if (altitude > 23000){
  148.     if (ExecOneRelease == 0){
  149.       ExecOneRelease = 1;
  150.       digitalWrite(RELEASEPIN, HIGH);
  151.     }
  152.   }
  153.   // Transmit and log to SD card
  154.   TxString(buffer);
  155.   digitalWrite(PHOTOPIN, LOW); //Put low anyway
  156.   // SMS <1000m mode
  157.   if (descent == 1){
  158.     if (altitude < 900){
  159.       if (ExecOnce == 0){
  160.         SmsStart = millis();
  161.         ExecOnce = 1;
  162.         send_sms(buffer);
  163.         delay(50);
  164.       }
  165.       if (millis() - SmsStart > 25000){
  166.         ExecOnce =0;
  167.       }
  168.     }
  169.   }
  170.   // Delay a moment before restarting loop
  171.   delay(100);
  172. } //end
  173. // ------- GPS Parsing ----------
  174. // Reads a line from the GPS NMEA serial output
  175. // Give up after trying to read 1000 bytes (~2 seconds)
  176. int readLine(void) {
  177.   char c;
  178.   byte bufferIndex = 0;
  179.   boolean startLine = 0;
  180.   byte retries = 0;
  181.   while (retries < 20) {
  182.     //if (GPS.available() > 0) {
  183.       c= GPS.read();
  184.       if (c == -1) {
  185.         delay(2);
  186.         continue;
  187.       }
  188.       if (c == 'n') continue;
  189.       if (c == '$') startLine = 1;
  190.       if ((bufferIndex == BUFFERSIZE-1) || (c == 'r')) {
  191.         if (startLine) {
  192.           buffer[bufferIndex] = 0;
  193.           return 1;
  194.         }
  195.       }
  196.       if (startLine) buffer[bufferIndex++] = c;
  197.     //}
  198.     else {
  199.       retries++;
  200.       delay(50);
  201.     }
  202.   }
  203.   Serial.println(buffer);
  204.   return 0;
  205. }
  206. // Returns a specific field from the buffer
  207. void getField(int getId, char *field, int maxLen) {
  208.   byte bufferIndex = 0;
  209.   byte fieldId = 0;
  210.   byte i = 0;
  211.   while (bufferIndex < sizeof(buffer)) {
  212.     if (fieldId == getId) {
  213.       // End of string, or string overflow
  214.       if (buffer[bufferIndex] == ',' || i > (maxLen - 2)) {
  215.         field[i] = 0;	// Null terminate
  216.         return;
  217.       }
  218.       // Buffer chars to field
  219.       field[i++] = buffer[bufferIndex++];
  220.     }
  221.     else {
  222.       // Advance field on comma
  223.       if (buffer[bufferIndex] == ',') {
  224.         bufferIndex++;						// Advance in buffer
  225.         fieldId++;							// Increase field position counter
  226.       }
  227.       else {
  228.         bufferIndex++;						// Advance in buffer
  229.       }
  230.     }
  231.   }
  232.   // Null terminate incase we didn't already..
  233.   field[i] = 0;
  234. }
  235. // Polls for an NMEA sentence of type requested
  236. // Validates checksum, silently retries on failed checksums
  237. int getNMEA(char *getType) {
  238.   char type[7];
  239.   byte retries = 0;
  240.   while (retries < 2) {
  241.     if (readLine() && validateChecksum()) {
  242.       ;
  243.       getField(0, type, sizeof(type));
  244.       if (strcmp(type, getType) == 0) {
  245.         Serial.println(buffer);
  246.         return 1;
  247.       }
  248.     }
  249.     else {
  250.       retries++;
  251.     }
  252.   }
  253.   Serial.println("Failed to read GPS");
  254.   return 0;
  255. }
  256. // Validates the checksum on an NMEA string
  257. // Returns 1 on valid checksum, 0 otherwise
  258. int validateChecksum(void) {
  259.   char gotSum[2];
  260.   gotSum[0] = buffer[strlen(buffer) - 2];
  261.   gotSum[1] = buffer[strlen(buffer) - 1];
  262.   // Check that the checksums match up
  263.   if ((16 * atoh(gotSum[0])) + atoh(gotSum[1]) == getCheckSum(buffer)) return 1;
  264.   else return 0;
  265. }
  266. // Calculates the checksum for a given string
  267. // returns as integer
  268. int getCheckSum(char *string) {
  269.   int i;
  270.   int XOR;
  271.   int c;
  272.   // Calculate checksum ignoring any $'s in the string
  273.   for (XOR = 0, i = 0; i < strlen(string); i++) {
  274.     c = (unsigned char)string[i];
  275.     if (c == '*') break;
  276.     if (c != '$') XOR ^= c;
  277.   }
  278.   return XOR;
  279. }
  280. // Returns the groundspeed in km/h
  281. int getSpeed(void) {
  282.   char field[10];
  283.   getField(7, field, sizeof(field));
  284.   int speed = atoi(field);
  285.   return speed;
  286. }
  287. // Return the fix type from a GGA string
  288. int getFixType(void) {
  289.   char field[5];
  290.   getField(6, field, sizeof(field));
  291.   int fixType = atoi(field);
  292.   return fixType;
  293. }
  294. // Return the altitude in meters from a GGA string
  295. long getAlt(void) {
  296.   char field[10];
  297.   getField(9, field, sizeof(field));
  298.   long altitude = atol(field);
  299.   return altitude;
  300. }
  301. // Returns the number of satellites being tracked from a GGA string
  302. int getSats(void) {
  303.   char field[3];
  304.   getField(7, field, sizeof(field));
  305.   int numSats = atoi(field);
  306.   return numSats;
  307. }
  308. // Read the latitude in decimal format from a GGA string
  309. double getLat(void) {
  310.   char field[12];
  311.   getField(2, field, sizeof(field));			// read the latitude
  312.   double latitude = atof(field);					// convert to a double (precise)
  313.   int deg = (int) latitude / 100;				// extract the number of degrees
  314.   double min = latitude - (100 * deg);			// work out the number of minutes
  315.   latitude = deg + (double) min/60.0;			// convert to decimal format
  316.   getField(3, field, sizeof(field));			// get the hemisphere (N/S)
  317.   if (strcmp(field, "S") == 0) latitude *= -1;	// sign the decimal latitude correctly
  318.   return latitude;
  319. }
  320. // Read the longitude in decimal format from a GGA string
  321. double getLong(void) {
  322.   char field[12];
  323.   getField(4, field, sizeof(field));			// read the longitude
  324.   double longitude = atof(field);					// convert to a double
  325.   int deg = (int) longitude / 100;				// extract the number of degrees
  326.   double min = longitude - (100 * deg);			// work out the number of minutes
  327.   longitude = deg + (double) min/60.00;			// convert to decimal format
  328.   getField(5, field, sizeof(field));			// get the E/W status
  329.   if (strcmp(field, "W") == 0) longitude *= -1; // sign decimal latitude correctly
  330.   return longitude;
  331. }
  332. // Converts UTC time to the correct timezone
  333. void convertTime(int *time) {
  334.   // How many hours off GMT are we?
  335.   float offset = 1;
  336.   long sectime = ((long)(time[0]) * 3600) + (time[1] * 60) + time[2];
  337.   sectime += (offset * 3600.0);
  338.   // Did we wrap around?
  339.   if (sectime < 0) sectime += 86400;
  340.   if (sectime > 86400) sectime -= 86400;
  341.   // Convert back to time
  342.   time[0] = (int)(sectime / 3600);
  343.   time[1] = (int)((sectime % 3600) / 60);
  344.   time[2] = (int)((sectime % 3600) % 60);
  345. }
  346. // Parses a time field from a GGA string
  347. void parseTime(char *field, int *time) {
  348.   char tmp[3];
  349.   tmp[2] = 0; // Init tmp and null terminate
  350.   tmp[0] = field[0];
  351.   tmp[1] = field[1];
  352.   time[0] = atoi(tmp); // Hours
  353.   tmp[0] = field[2];
  354.   tmp[1] = field[3];
  355.   time[1] = atoi(tmp); // Minutes
  356.   tmp[0] = field[4];
  357.   tmp[1] = field[5];
  358.   time[2] = atoi(tmp); // Seconds
  359. }
  360. // Gets the hours, minutes and seconds from a GGA string
  361. void getTime(int *time) {
  362.   char field[12];
  363.   getField(1, field, sizeof(field));
  364.   parseTime(field, time);
  365.   convertTime(time);
  366. }
  367. // ------ RTTY ----------
  368. // Transmit a string, log it to SD & produce debug output
  369. void TxString(char *string) {
  370.   // Checksum
  371.   char txSum[4];
  372.   int checkSum = getCheckSum(string);
  373.   sprintf(txSum, "%02X", checkSum);
  374.   Serial << F("RTTY: ") << string << "#" << txSum << ENDLN;
  375.   rtty_txstring(string);
  376.   rtty_txstring("#");
  377.   rtty_txstring(txSum);
  378.   rtty_txstring("rn");
  379. }
  380. uint8_t char_to_baudot(char c, char *array)
  381. {
  382.   int i;
  383.   for (i = 0; i < ARRAY_LEN; i++)
  384.   {
  385.     if (array[i] == c)
  386.       return i;
  387.   }
  388.   return 0;
  389. }
  390. void rtty_txbyte(uint8_t b)
  391. {
  392.   int8_t i;
  393.   rtty_txbit(0);
  394.   /* TODO: I don't know if baudot is MSB first or LSB first */
  395.   /* for (i = 4; i >= 0; i--) */
  396.   for (i = 0; i < 5; i++)
  397.   {
  398.     if (b & (1 << i))
  399.       rtty_txbit(1);
  400.     else
  401.       rtty_txbit(0);
  402.   }
  403.   rtty_txbit(1);
  404. }
  405. enum baudot_mode
  406. {
  407.   NONE,
  408.   LETTERS,
  409.   FIGURES
  410. };
  411. void rtty_txstring(char *str)
  412. {
  413.   enum baudot_mode current_mode = NONE;
  414.   char c;
  415.   uint8_t b;
  416.   while (*str != '')
  417.   {
  418.     c = *str;
  419.     /* some characters are available in both sets */
  420.     if (c == 'n')
  421.     {
  422.       rtty_txbyte(LINEFEED);
  423.     }
  424.     else if (c == 'r')
  425.     {
  426.       rtty_txbyte(CARRRTN);
  427.     }
  428.     else if (is_lowercase(*str) || is_uppercase(*str))
  429.     {
  430.       if (is_lowercase(*str))
  431.       {
  432.         c -= 32;
  433.       }
  434.       if (current_mode != LETTERS)
  435.       {
  436.         rtty_txbyte(LETTERS_SHIFT);
  437.         current_mode = LETTERS;
  438.       }
  439.       rtty_txbyte(char_to_baudot(c, letters_arr));
  440.     }
  441.     else
  442.     {
  443.       b = char_to_baudot(c, figures_arr);
  444.       if (b != 0 && current_mode != FIGURES)
  445.       {
  446.         rtty_txbyte(FIGURES_SHIFT);
  447.         current_mode = FIGURES;
  448.       }
  449.       rtty_txbyte(b);
  450.     }
  451.     str++;
  452.   }
  453. }
  454. // Transmit a bit as a mark or space
  455. void rtty_txbit (int bit) {
  456.   if (bit) {
  457.     // High - mark
  458.     digitalWrite(2, HIGH);
  459.     digitalWrite(3, LOW);
  460.   }
  461.   else {
  462.     // Low - space
  463.     digitalWrite(3, HIGH);
  464.     digitalWrite(2, LOW);
  465.   }
  466.   // Delay appropriately - tuned to 50 baud.
  467.   delay(20);
  468.   //delayMicroseconds(250);
  469. }
  470. // ------ T68i GPRS ----------
  471. // © D> Richman
  472. void hexdump_byte(unsigned char byte)
  473. {
  474.   GSM.print(hexdump_a(byte), BYTE);
  475.   GSM.print(hexdump_b(byte), BYTE);
  476. }
  477. void send_sms(char *data)
  478. {
  479.   size_t data_length, x;
  480.   char c, l;
  481.   long i;
  482.   long n;
  483.   data_length = strlen(data);
  484.   i = data_length * 7;
  485.   /* Round i up to a multiple of 8 */
  486.   if (i & 0x07) i = (i & ~0x07) + 0x08;
  487.   /* Calculate the number of message octets */
  488.   i = i / 8;
  489.   GSM.println("AT+CMGF=0");
  490.   delay(1500);
  491.   GSM.print("AT+CMGS=");
  492.   delay(1500);
  493.   GSM.println(i + 14);
  494.   delay(1500);
  495.   GSM.print("0011000B911356537837F80000AA");
  496.   hexdump_byte(data_length & 0xFF);
  497.   /* from sms_example_v2.c ALIEN Project Daniel Richman */
  498.   l = 0;
  499.   n = 0;
  500.   for (x = 0; x < data_length; x++)
  501.   {
  502.     if (data[x] == '$')  data[x] = 0x02;
  503.     n |= (data[x] & 0x7F) << l;
  504.     l += 7;
  505.     if (l >= 8)
  506.     {
  507.       hexdump_byte(n & 0xFF);
  508.       l -= 8;
  509.       n >>= 8;
  510.     }
  511.   }
  512.   if (l != 0)
  513.   {
  514.     hexdump_byte(n & 0xFF);
  515.   }
  516.   GSM.println(0x1A, BYTE);
  517. }
  518. // DO NOT COPYRIGHT WITHOUT HIS PERMISSION
  519. // ------ MISC ----------
  520. // Returns a string with a textual representation of a float
  521. void doubleToString(double val, int precision, char *string){
  522.   // Print the int part
  523.   sprintf(string, "%d", (int)(val));
  524.   if(precision > 0) {
  525.     // Print the decimal point
  526.     strcat(string, ".");
  527.     unsigned long frac;
  528.     unsigned long mult = 1;
  529.     int padding = precision -1;
  530.     while (precision--) {
  531.       mult *=10;
  532.     }
  533.     if (val >= 0)
  534.       frac = (val - (int)(val)) * mult;
  535.     else
  536.       frac = ((int)(val)- val ) * mult;
  537.     unsigned long frac1 = frac;
  538.     while (frac1 /= 10) {
  539.       padding--;
  540.     }
  541.     while (padding--) {
  542.       strcat(string, "0");
  543.     }
  544.     // Convert and print the fraction part
  545.     sprintf(string+strlen(string), "%d", (int)(frac));
  546.   }
  547. }
  548. // Converts a HEX string to an int
  549. int atoh(char c) {
  550.   if (c >= 'A' && c <= 'F')
  551.     return c - 55;
  552.   else if (c >= 'a' && c <= 'f')
  553.     return c - 87;
  554.   else
  555.     return c - 48;
  556. }
Slave Code
  1. #include <servo.h>
  2. Servo myservo;  // create servo object to control a servo
  3. // a maximum of eight servo objects can be created
  4. int inPin = 7;   // pushbutton connected to digital pin 7
  5. int val = 0;     // variable to store the read value
  6. int sum = 0;
  7. void setup()
  8. {
  9.   myservo.attach(8);  // attaches the servo on pin 9 to the servo object
  10.   Serial.begin(9600);
  11.   pinMode(inPin, INPUT);      // sets the digital pin 7 as input
  12. }
  13. void loop()
  14. {
  15.   sum=0;
  16.   val = digitalRead(inPin);   // read the input pin
  17.   delay(500);
  18.   while (val == 1){
  19.     val = digitalRead(inPin);   // read the input pin
  20.     delay(500);
  21.     sum=sum+val;
  22.     if (sum > 10){
  23.       release();
  24.     }
  25.   }
  26. }
  27. void release(){
  28.   myservo.attach(8);
  29.   myservo.write(0);
  30.   delay(2500);
  31.   myservo.write(180);
  32.   delay(2500);
  33.   myservo.detach();
  34.   delay(10000); //wait 10 sec
  35.   releaseinv();
  36.   delay(1000);
  37.   releasevibrate();
  38.   delay(10000);
  39. }
  40. void releaseinv(){
  41.   myservo.attach(8);
  42.   myservo.write(180);
  43.   delay(5000);
  44.   myservo.write(0);
  45.   delay(5000);
  46.   myservo.detach();
  47. }
  48. void releasevibrate(){
  49.   myservo.attach(8);
  50.   myservo.write(180);
  51.   delay(500);
  52.   myservo.write(0);
  53.   delay(500);
  54.   myservo.write(180);
  55.   delay(500);
  56.   myservo.write(0);
  57.   delay(500);
  58.   myservo.write(180);
  59.   delay(500);
  60.   myservo.write(0);
  61.   delay(500);
  62.   myservo.write(180);
  63.   delay(3000);
  64.   myservo.detach();
  65. }
]]>

You may also like...

1 Response

  1. Americo says:

    Damn it do not compile the code do i need some libraries that do not comes with standard IDE ? if not waht version of ide did you use?