Advertisement
Guest User

Untitled

a guest
Dec 19th, 2014
185
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.81 KB | None | 0 0
  1. #include <Tone.h>
  2.  
  3. /*
  4. Arduino Vario by Jaros, 2012 (dedicated to atmega328 based arduinos)
  5. Part of the "GoFly" project
  6. https://sites.google.com/site/jarosrwebsite/para-nav
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18.  
  19. Arduino board creates NMEA like protocol with variometer output and beping sound.
  20. LK8000 EXTERNAL INSTRUMENT SERIES 1 - NMEA SENTENCE: LK8EX1
  21. VERSION A, 110217
  22.  
  23. $LK8EX1,pressure,altitude,vario,temperature,battery,*checksum
  24.  
  25. Field 0, raw pressure in hPascal:hPA*100 (example for 1013.25 becomes 101325)
  26. no padding (987.25 becomes 98725, NOT 098725)
  27. If no pressure available, send 999999 (6 times 9)
  28. If pressure is available, field 1 altitude will be ignored
  29. Field 1, altitude in meters, relative to QNH 1013.25
  30. If raw pressure is available, this value will be IGNORED (you can set it to 99999
  31. but not really needed)!(if you want to use this value, set raw pressure to 999999)
  32. This value is relative to sea level (QNE). We are assuming that currently at 0m
  33. altitude pressure is standard 1013.25.If you cannot send raw altitude, then send
  34. what you have but then you must NOT adjust it from Basic Setting in LK.
  35. Altitude can be negative. If altitude not available, and Pressure not available, set Altitude
  36. to 99999. LK will say "Baro altitude available" if one of fields 0 and 1 is available.
  37. Field 2, vario in cm/s
  38. If vario not available, send 9999. Value can also be negative.
  39. Field 3, temperature in C , can be also negative.If not available, send 99
  40. Field 4, battery voltage or charge percentage.Cannot be negative.If not available, send 999.
  41. Voltage is sent as float value like: 0.1 1.4 2.3 11.2. To send percentage, add 1000.
  42. Example 0% = 1000. 14% = 1014 . Do not send float values for percentages.
  43. Percentage should be 0 to 100, with no decimals, added by 1000!
  44. Credits:
  45. (1) http://code.google.com/p/bmp085driver/ //bmp085 library
  46. (2) http://mbed.org/users/tkreyche/notebook/bmp085-pressure-sensor/ //more about bmp085 and average filter
  47. (3) http://code.google.com/p/rogue-code/ //helpfull tone library to make nice beeping without using delay
  48. (4) http://www.daqq.eu/index.php?show=prj_sanity_nullifier //how to make loud piezo speaker
  49. (5) http://lk8000.it //everything because of that
  50. (6) http://taturno.com/2011/10/30/variometro-la-rivincita/ //huge thanks for Vario algorithm
  51. (7) http://code.google.com/p/tinkerit/wiki/SecretVoltmeter //how to measure battery level using AVR ucontroller
  52. */
  53.  
  54. #include <Wire.h> //i2c library
  55. #include <BMP085.h> //bmp085 library, download from url link (1) //tone library, download from url link (3)
  56. #include<stdlib.h> //we need that to use dtostrf() and convert float to string
  57. /////////////////////////////////////////
  58. ///////////////////////////////////////// variables that You can test and try
  59. short speaker_pin1 = 8; //arduino speaker output -
  60. short speaker_pin2 = 9; //arduino speaker output +
  61. float vario_climb_rate_start = 0.4; //minimum climb beeping value(ex. start climbing beeping at 0.4m/s)
  62. float vario_sink_rate_start = -1.1; //maximum sink beeping value (ex. start sink beep at -1.1m/s)
  63. #define SAMPLES_ARR 6 //define moving average filter array size (2->30), more means vario is less sensitive and slower
  64. #define UART_SPEED 9600 //define serial transmision speed (9600,19200, etc...)
  65. /////////////////////////////////////////
  66. /////////////////////////////////////////
  67. BMP085 bmp085 = BMP085(); //set up bmp085 sensor
  68. Tone tone_out1;
  69. Tone tone_out2;
  70. long Temperature = 0;
  71. long Pressure = 101325;
  72. float Altitude;
  73. int Battery_Vcc = 0; //variable to hold the value of Vcc from battery
  74. const float p0 = 101325; //Pressure at sea level (Pa)
  75. unsigned long get_time1 = millis();
  76. unsigned long get_time2 = millis();
  77. unsigned long get_time3 = millis();
  78. boolean thermalling = false;
  79. int my_temperature = 1;
  80. char altitude_arr[6]; //wee need this array to translate float to string
  81. char vario_arr[5]; //wee need this array to translate float to string
  82. int samples=40;
  83. int maxsamples=50;
  84. float alt[51];
  85. float tim[51];
  86. float beep;
  87. float Beep_period;
  88. static long k[SAMPLES_ARR];
  89.  
  90. static long Averaging_Filter(long input);
  91. static long Averaging_Filter(long input) // moving average filter function
  92. {
  93. long sum = 0;
  94. for (int i = 0; i < SAMPLES_ARR; i++) {
  95. k[i] = k[i+1];
  96. }
  97. k[SAMPLES_ARR - 1] = input;
  98. for (int i = 0; i < SAMPLES_ARR; i++) {
  99. sum += k[i];
  100. }
  101. return ( sum / SAMPLES_ARR ) ;
  102. }
  103.  
  104. void play_welcome_beep() //play only once welcome beep after turning on arduino vario
  105. {
  106. for (int aa=300;aa<=1500;aa=aa+100)
  107. {
  108. tone_out1.play(aa,200); // play beep on pin 8 (note,duration)
  109. tone_out2.play(aa+3,200); // play beep on pin 9 (note,duration), it is louder if we move aplitude phase
  110. delay(100);
  111. }
  112. for (int aa=1500;aa>=100;aa=aa-100)
  113. {
  114. tone_out1.play(aa,200); // play beep on pin 8 (note,duration)
  115. tone_out2.play(aa+3,200); // play beep on pin 8 (note,duration)
  116. delay(100);
  117. }
  118. }
  119.  
  120. long readVcc() // function to read battery value - still in developing phase
  121. {
  122. long result;
  123. // Read 1.1V reference against AVcc
  124. ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  125. delay(2); // Wait for Vref to settle
  126. ADCSRA |= _BV(ADSC); // Convert
  127. while (bit_is_set(ADCSRA,ADSC));
  128. result = ADCL;
  129. result |= ADCH<<8;
  130. result = 1126400L / result; // Back-calculate AVcc in mV
  131. return result;
  132. }
  133.  
  134. void setup() // setup() function to setup all necessary parameters before we go to endless loop() function
  135. {
  136. Serial.begin(UART_SPEED); // set up arduino serial port
  137. Wire.begin(); // lets init i2c protocol
  138. tone_out1.begin(speaker_pin1); // piezo speaker output pin8 -
  139. tone_out2.begin(speaker_pin2); // piezo speaker output pin9 +
  140. bmp085.init(MODE_ULTRA_HIGHRES, p0, false);
  141. // BMP085 ultra-high-res mode, 101325Pa = 1013.25hPa, false = using Pa units
  142. // this initialization is useful for normalizing pressure to specific datum.
  143. // OR setting current local hPa information from a weather station/local airport (QNH).
  144. play_welcome_beep(); //everything is ready, play "welcome" sound
  145. }
  146.  
  147. void loop(void)
  148. {
  149. float tempo=millis();
  150. float vario=0;
  151. float N1=0;
  152. float N2=0;
  153. float N3=0;
  154. float D1=0;
  155. float D2=0;
  156. bmp085.calcTruePressure(&Pressure); //get one sample from BMP085 in every loop
  157. long average_pressure = Averaging_Filter(Pressure); //put it in filter and take average
  158. Altitude = (float)44330 * (1 - pow(((float)Pressure/p0), 0.190295)); //take new altitude in meters
  159. //Serial.println(Battery_Vcc);
  160. for(int cc=1;cc<=maxsamples;cc++){ //samples averaging and vario algorithm
  161. alt[(cc-1)]=alt[cc];
  162. tim[(cc-1)]=tim[cc];
  163. };
  164. alt[maxsamples]=Altitude;
  165. tim[maxsamples]=tempo;
  166. float stime=tim[maxsamples-samples];
  167. for(int cc=(maxsamples-samples);cc<maxsamples;cc++){
  168. N1+=(tim[cc]-stime)*alt[cc];
  169. N2+=(tim[cc]-stime);
  170. N3+=(alt[cc]);
  171. D1+=(tim[cc]-stime)*(tim[cc]-stime);
  172. D2+=(tim[cc]-stime);
  173. };
  174.  
  175. vario=1000*((samples*N1)-N2*N3)/(samples*D1-D2*D2);
  176. if ((tempo-beep)>Beep_period) // make some beep
  177. {
  178. beep=tempo;
  179. if (vario>vario_climb_rate_start && vario<15 )
  180. {
  181. Beep_period=350-(vario*5);
  182. tone_out1.play((1000+(100*vario)),300-(vario*5)); //when climbing make faster and shorter beeps
  183. tone_out2.play((1003+(100*vario)),300-(vario*5));
  184. thermalling = true; //ok,we have thermall in our hands
  185. } else if ((vario < 0 ) && (thermalling == true)) //looks like we jump out the thermall
  186. {
  187. //Beep_period=200;
  188. // play_siren(); //oo, we lost thermall play alarm
  189. thermalling = false;
  190. } else if (vario< vario_sink_rate_start){ //if you have high performace glider you can change sink beep to -0.95m/s ;)
  191. Beep_period=200;
  192. tone_out1.play(300,340);
  193. tone_out2.play(303,340);
  194. thermalling = false;
  195. }
  196. }
  197.  
  198. if (millis() >= (get_time2+1000)) //every second get temperature and battery level
  199. {
  200. bmp085.getTemperature(&Temperature); // get temperature in celsius from time to time, we have to divide that by 10 to get XY.Z
  201. my_temperature = Temperature/10;
  202. Battery_Vcc =(readVcc()/42)+1000; // get voltage and prepare in percentage
  203. get_time2 = millis();
  204. }
  205.  
  206. if (millis() >= (get_time3+333)) //every 1/3 second send NMEA output over serial port
  207. {
  208. String str_out = //combine all values and create part of NMEA data string output
  209. String("LK8EX1"+String(",")+String(average_pressure,DEC)+ String(",")+String(dtostrf(Altitude,0,0,altitude_arr))+String(",")+
  210. String(dtostrf((vario*100),0,0,vario_arr))+String(",")+String(my_temperature,DEC)+String(",")+String(Battery_Vcc,DEC)+String(","));
  211. unsigned int checksum_end,ai,bi; // Calculating checksum for data string
  212. for (checksum_end = 0, ai = 0; ai < str_out.length(); ai++)
  213. {
  214. bi = (unsigned char)str_out[ai];
  215. checksum_end ^= bi;
  216. }
  217. //creating now NMEA serial output for LK8000. LK8EX1 protocol format:
  218. //$LK8EX1,pressure,altitude,vario,temperature,battery,*checksum
  219. Serial.print("$"); //print first sign of NMEA protocol
  220. Serial.print(str_out); // print data string
  221. Serial.print("*"); //end of protocol string
  222. Serial.println(checksum_end,HEX); //print calculated checksum on the end of the string in HEX
  223. get_time3 = millis();
  224. }
  225. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement