Poor Mans Vario too sensitive. (solved)

I have assembled my very first Arduino project and got it working. Mine is based on this site here:

https://translate.google.com/translate?depth=2&hl=en&rurl=translate.google.com&sl=auto&sp=nmt4&tl=en&u=http://www.modelbouwforum.nl/threads/poor-mans-vario.199904/page-6&xid=17259,1500004,15700022,15700124,15700149,15700186,15700191,15700201#post-3241059

However, I understand that the original code was written by Rolfe Bakke.

Mine worked right from the start. However, it is far too sensitive. So much so, it seems to be unstable.

Is there a sensitivity line or lines in the code that I can “tweak”?
My apologies if I have posted in the wrong forum. Or asked a question that is too basic for this forum.

[FONT = Arial] [SIZE = 3]
 // **********************************
 // * MS5611 sensor version *
 // **********************************
 [/ SIZE] [/ FONT] // [FONT = Arial] [SIZE = 3] [FONT = Verdana] [SIZE = 2] This is the Poor Mans Vario code for the MS5611 sensor [/ SIZE] [/ FONT] [ / SIZE] [/ FONT]
 // All code by Rolf R Bakke, Oct 2012
 // Modified by Hans Meijdam, June 2013. added altitude feature
 // Modified by Hans Meijdam, November 2013.
 // Led on Arduino is in sync with audio
 // Bug fixed that now "Vario Mode" is default mode if no servo channel PWM data is present on pin D3
 // Improved documentation here and there

 #include <Wire.h>
 const byte led = 13;
 unsigned int calibrationData [7];
 unsigned long time = 0;
 float toneFreq, toneFreqLowpass, pressure, lowpassFast, lowpassSlow;
 float p0;  // this will be used to store the airfield elevation pressure
 int altitude;
 int ch1;  // Here's where we'll keep our channel values
 int ddsAcc;


 void setup ()
 {
   Wire.begin ();
   Serial.begin (9600);  // in case you want to use the included serial.print debugging commands that are currently commented out
   delay (200);
   setupSensor ();
   for (int p0 = 0; p0 <= 100; p0 ++) {
     pressure = getPressure ();  // warming up the sensor for ground level setting
   }
   p0 = getPressure ();  // Setting the ground level pressure
   lowpassFast = lowpassSlow = pressure;
   pinMode (3, INPUT);  // Set our input pins as such for height command input from receiver via pin D3
 }


 void loop ()
 {
   pressure = getPressure ();
   // Serial.print (p0);
   // Serial.print ("");
   // Serial.print (pressure);
   altitude = (float) 44330 * (1 - pow (((float) pressure / p0), 0.190295));
   // Serial.print ("");
   // Serial.println (altitude);
   lowpassFast = lowpassFast + (pressure - lowpassFast) * 0.1;
   lowpassSlow = lowpassSlow + (pressure - lowpassSlow) * 0.05;
   toneFreq = (lowpassSlow - lowpassFast) * 50;
   toneFreqLowpass = toneFreqLowpass + (toneFreq - toneFreqLowpass) * 0.1;
   toneFreq = constrain (toneFreqLowpass, -500, 500);
   ddsAcc + = toneFreq * 100 + 2000;
   if (toneFreq <0 || ddsAcc> 0)
   {
     tone (2, toneFreq + 510);
     ledOn ();  // the Arduino led will blink if the Vario plays a tone, so you can test without having audio connected
   }
   else
   {
     noTone (2);
     ledOff ();
   }
   int ones = altitude% 10;
   int tens = (altitude / 10)% 10;
   int hundreds = (altitude / 100)% 10;
   int thousands = (altitude / 1000)% 10;
   // Serial.print ("thousands:");
   // Serial.println (thousands);
   // Serial.print ("hundreds:");
   // Serial.println (hundreds);
   // Serial.print ("tens:");
   // Serial.println (tens);
   // Serial.print ("ones:");
   // Serial.println (ones);
   while (millis () <time);  // loop frequency timer
   time + = 20;

   ch1 = pulseIn (3, HIGH, 25,000);  // Read the pulse width or servo signal connected to pin D3
   // if (ch1> 1000) {
   // Serial.println ("Left Switch: Engaged");
   //}
   // if (ch1 <1000) {
   // Serial.println ("Left Switch: Disengaged");
   //}
   if ((map (ch1, 1000,2000, -500,500))> 0) // interpret the servo channel pulse, if the Vario should beep altitude or send vario sound
   {
     noTone (2);  // create 750 ms of silence, or you will not hear the first altitude beep
     ledOff ();
     delay (750);
     if (hundreds == 0)
     {
       tone (2,900);  // long duration tone if the number is zero
       ledOn ();
       delay (600);
       noTone (2);
       ledOff ();
     }
     else
       for (char a = 0; a <hundreds; a ++) // this loop makes a beep for each hundred meters altitude
       {
         tone (2,900);  // 900 Hz tone frequency for the hundreds
         ledOn ();
         delay (200);
         noTone (2);
         ledOff ();
         delay (200);
       }
     delay (750);  // longer delay between hundreds and tens

     if (tens == 0)
     {
       tone (2,1100);  // long pulse if the number is zero
       ledOn ();
       delay (600);
       noTone (2);
       ledOff ();
     }
     else
       for (char a = 0; a <tens; a ++) // this loop makes a beep for each at meters altitude
       {
         tone (2,1100);  // 1100 Hz tone frequency for the tens
         ledOn ();
         delay (200);
         noTone (2);
         ledOff ();
         delay (200);
       }

     for (int p0 = 0; p0 <= 40; p0 ++)
     {
       pressure = getPressure ();  // warming up the sensor again, by reading it 40 times
     }
   }
 }


 long getPressure ()
 {
   lung D1, D2, dT, P;
   float TEMP;
   int64_t OFF, SENS;

   D1 = getData (0x48, 10);
   D2 = getData (0x50, 1);

   dT = D2 - ((long) calibrationData [5] << 8);
   TEMP = (2000 + (((int64_t) dT * (int64_t) calibrationData [6]) >> 23)) / (float) 100;
   OFF = ((unsigned long) calibrationData [2] << 16) + (((int64_t) calibrationData [4] * dT) >> 7);
   SENS = (unsigned long) calibrationData [1] << 15) + (((int64_t) calibrationData [3] * dT) >> 8);
   P = (((D1 * SENS) >> 21) - OFF) >> 15;

   // Serial.println (TEMP);
   //Serial.println (P);

   return P;
 }


 long getData (byte command, byte del)
 {
   long result = 0;
   twiSendCommand (0x77, command);
   delay (del);
   twiSendCommand (0x77, 0x00);
   Wire.requestFrom (0x77, 3);
   if (Wire.available ()! = 3) Serial.println ("Error: raw data not available");
   for (int i = 0; i <= 2; i ++)
   {
     result = (result << 8) |  Wire.read ();
   }
   return result;
 }


 void setupSensor ()
 {
   twiSendCommand (0x77, 0x1e);
   delay (100);

   for (byte i = 1; i <= 6; i ++)
   {
     unsigned int low, high;

     twiSendCommand (0x77, 0xa0 + i * 2);
     Wire.requestFrom (0x77, 2);
     if (Wire.available ()! = 2) Serial.println ("Error: calibration data not available");
     high = Wire.read ();
     low = Wire.read ();
     calibrationData [i] = high << 8 |  low;
     Serial.print ("calibration data #");
     Serial.print (i);
     Serial.print ("=");
     Serial.println (calibrationData [i]);
   }
 }


 void twiSendCommand (byte address, byte command)
 {
   Wire.beginTransmission (address);
   if (! Wire.write (command)) Serial.println ("Error: write ()");
   if (Wire.endTransmission ())
   {
     Serial.print ("Error when sending command:");
     Serial.println (command, HEX);
   }
 }


 void ledOn ()
 {
   digitalWrite (LED, 1);
 }


 void ledOff ()
 {
   digitalWrite (LED, 0);
 }

Your link returns this: This page was not retrieved from its original location over a secure connection.

So, can you make a better link or describe exactly what it is you are attempting?

Paul

Thanks for the reply Paul.
This is the original Dutch language version of the site I followed:

It will need translating, of course.
I am building a variometer that is intended for use in a model sailplane. It is an aid for thermal hunting.
It is based on the BMP180 barometric pressure sensing module and a Arduino nano.

It works, but is a bit unstable and too sensitive for aircraft use just yet.
Should I post more information?

Jim.

There's a difference between "too sensitive" and "too unstable".

"Sensitive" might be that it goes off-scale at 1m/s and you need to be able to tell the difference between 2m/s and 5m/s.

"Unstable" might be fixed by filtering or "averaging". You can filter out high-frequency spikes with a low-pass filter.

Looking at the code, there's two low-pass filters:

   lowpassFast = lowpassFast + (pressure - lowpassFast) * 0.1;
   lowpassSlow = lowpassSlow + (pressure - lowpassSlow) * 0.05;
   toneFreq = (lowpassSlow - lowpassFast) * 50;

The fast one takes 10% of the difference between the latest sample and the previous filtered value and adds that to the previous value. The slow one isn't much slower - it uses 5%.

Then it takes the difference between the two. This seems odd until you realize that the results of the two filters are just altitude. The difference between the two is the rate of change - the vario reading - although it's the first time I've seen it done this way.

The 50 multiplier is the sensitivity. If you wanted it to be less sensitive, use a lower number. Try 40 or 30 or whatever works.

Adjusting the "unstable" is a little more complex. Start by adjusting both of the filters together: pick 0.05 for "fast" and 0.025 for "slow". If you slow down the slow one without also slowing down the fast one then the sensitivity will increase because you are comparing an 'older' reading with the current one.

Very good, thanks Morgan. I will have a tweak.

I'll report back with changes etc.

Jim.

Morgan,

I have changed the value of the sensitivity in the sketch, but I don't know how to re-flash the arduino nano. Do I have to delete the old one from the board first and then upload again?

Edit: I found out that old sketch did not need erasing. I managed to flash the modified sketch over the former modified one. I changed the 50 figure parameter to 30 as you describe. (After trying a couple of other values). 30 seems to work fine. The sensitivity is now moderate; I will only know if it is suitable/ or optimum after a flight test. I hope to flight test this device tomorrow, weather permitting. All good though; I have learned something. Thanks for taking the time to assist me.

Should I now mark this thread as solved?

Jim.

Here is where my confusion came from.

. 1. a device for indicating an aircraft's rate of climb or descent. 2. an inductor whose total inductance can be varied by altering the relative position of two coaxial coils connected in series, or by permeability tuning, and so can be used to tune an electric circuit

I always think the second definition. Wonder why there are two totally unconnected definitions?

Paul

Paul_KD7HB: Here is where my confusion came from.

. ............................ 2. an inductor whose total inductance can be varied by altering the relative position of two coaxial coils connected in series, or by permeability tuning, and so can be used to tune an electric circuit

Paul

Is this also called a "variometer"? I assume from your post that it does.

The author of the site with instructions I followed suggested that a laptop could be taken to the flying field to change this sensitivity setting if and when required between flights. But I hope I don't have to do that. My laptop screen is difficult to see in the sunlight.