[Flightcomputer] HoHoHo 3

This is the flightcomputer for the infamous HoHoHo3 high altitude balloon flight.

It uses GPS serial data from a GPS receiver, strips it and parses it to a NTX2 433mhz radio transmitter. Also, it fires of a Canon EOS350 which makes nice pictures. Furthermore, it rotates a servo as release mechanism when it crosses certain borders.

Also, it sends a textmessage through a Sony Ericsson with serial interface (in this case a t68i) to send a textmessage when it lands.

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

Slave Code

  1.  
  2. #include <servo.h>
  3.  
  4. Servo myservo;  // create servo object to control a servo
  5. // a maximum of eight servo objects can be created
  6.  
  7.  
  8. int inPin = 7;   // pushbutton connected to digital pin 7
  9. int val = 0;     // variable to store the read value
  10. int sum = 0;
  11.  
  12.  
  13. void setup()
  14. {
  15.   myservo.attach(8);  // attaches the servo on pin 9 to the servo object
  16.   Serial.begin(9600);
  17.  
  18.   pinMode(inPin, INPUT);      // sets the digital pin 7 as input
  19.  
  20. }
  21.  
  22.  
  23. void loop()
  24. {
  25.   sum=0;
  26.   val = digitalRead(inPin);   // read the input pin
  27.   delay(500);
  28.   while (val == 1){
  29.     val = digitalRead(inPin);   // read the input pin
  30.     delay(500);
  31.     sum=sum+val;
  32.     if (sum > 10){
  33.       release();
  34.     }
  35.   }
  36. }
  37.  
  38. void release(){
  39.   myservo.attach(8);
  40.   myservo.write(0);
  41.   delay(2500);
  42.   myservo.write(180);
  43.   delay(2500);
  44.   myservo.detach();
  45.   delay(10000); //wait 10 sec
  46.   releaseinv();
  47.   delay(1000);
  48.   releasevibrate();
  49.   delay(10000);
  50. }
  51.  
  52. void releaseinv(){
  53.   myservo.attach(8);
  54.   myservo.write(180);
  55.   delay(5000);
  56.   myservo.write(0);
  57.   delay(5000);
  58.   myservo.detach();
  59. }
  60.  
  61. void releasevibrate(){
  62.   myservo.attach(8);
  63.   myservo.write(180);
  64.   delay(500);
  65.   myservo.write(0);
  66.   delay(500);
  67.   myservo.write(180);
  68.   delay(500);
  69.   myservo.write(0);
  70.   delay(500);
  71.   myservo.write(180);
  72.   delay(500);
  73.   myservo.write(0);
  74.   delay(500);
  75.   myservo.write(180);
  76.   delay(3000);
  77.   myservo.detach();
  78. }

Tim Zaman

MSc Biorobotics. Specialization in computer vision and deep learning. Works at NVIDIA.

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?