Poor Mans Vario

Discussie in 'Zweefvliegen' gestart door hmeijdam, 11 nov 2013.

  1. hmeijdam

    hmeijdam

    Lid geworden:
    29 jan 2010
    Berichten:
    1.884
    Locatie:
    Barneveld
    Funny that you mention strobelights as your other project as that was my next project after the vario. You can read the details here.

    Veel plezier met je vario en een boel thermiek.
     
  2. Ludger Kuhnen

    Ludger Kuhnen

    Lid geworden:
    13 feb 2020
    Berichten:
    3
    Locatie:
    Duitsland
    Goede morgen ,

    volgend nu de aangepaste Code met de mogelijkheid, het deadband met een teede kanaal te kunnen besturen.
    Ik heb er een waarde ingevoegd von 0 t/m 300.
    De kanaal komt binnen op pin D6, waarbij 1000µS voor 0 staat, en 2000µS voor 300.
    Sorry voor mijn slecht geschreven Nederlands.

    Code:
    //**********************************
    //*   BMP085 and BMP180 version    *
    //**********************************
    // This is the Poor Mans Vario code for the cheaper BMP085 and the BMP180 sensor by BOSCH Sensortec
    // Arduino <> Sensor: Connect VCC to VCC and GND to GND, SCL goes to analogue pin 5, SDA to analogue pin4.
    // Servo signal input, connect to Arduino pin D3
    // Audio output to transmitter on pin D2
    // All code by Rolf R Bakke, Oct 2012
    // Modified by Hans Meijdam, June 2013: added altitude feature
    // Modified by Hans Meijdam, November 2013: Sensor routine created for BMP085 and BMP180.
    // Modified by Hans Meijdam, July 2014: BETA Version
    
    // - Switch to select if whole meters are called out if below 100 meters altitude
    // - Deadband to make vario silent if no certain climb or sink level is achieved
    // - Negative altitude becomes now indicated as if it was positive altitude
    
    // Modified by Ludger Kuhnen, January 2020
    // - Deadband adjustable via 2nd Receiver-channel ( input D6 1000 - 2000µs sets 0 to 300 deadband )
    
    //  ****** This is a customizable variable that acts as a switch *****
    // choose "1" if you also want to hear the altitude in meters if you fly below 100 meters.
    // choose "0" if you only want to hear the 10 meters rounded altitude at all times.
    // Default is 0.
    //const byte altitude_per_meter = 0; // only altitude in 10 meters
    const byte altitude_per_meter = 1; // altitude in whole meters if below 100 meters
    
    
    //  ****** This is a customizable variable (0 - 300 range) that defines how large the dead band is ******
    // A dead band of "0" (= default) means that the vario will beep constantly, even with no climb or sink at all.
    // A small dead band (e.g. value 25 - 50) means that with a small amount of climb or sink the vario will start beeping
    // A medium dead band (e.g. value 50 - 100) means that the vario will be silent, unless it observes a medium rate of climb or medium rate of sink.
    // A high dead band (> 100) makes the vario only active at high rates of sink or climb.
    int deadband = 0;  // no deadband or deadband defined by RC-channel
    // int deadband = 25;  // small deadband
    // int deadband = 75;  // medium deadband
    // int deadband = 150;  // large deadband
    
    //  ****** Alternatively the deadband can be dynamically set by connecting a 10K potmeter over pins 12, A1 (rocker) and A2 ******
    //const byte deadbandchannel = 0;  // no deadband potmeter present
    const char deadbandchannel = 1;  // deadband channel is present (on digital INPUT D6)
    
    #include "Wire.h"
    const byte led = 13;
    unsigned long time = 0;
    float toneFreq, toneFreqLowpass, flpressure, 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 ch2; // Value for deadband by 2nd channel of TX, preferred by rc-channel, instead of switch
    int ddsAcc;
    #define I2C_ADDRESS 0x77
    const unsigned char oversampling_setting = 3; //oversamplig for measurement
    const unsigned char pressure_waittime[4] = {
      5, 8, 14, 26
    };
    //Sensor parameters taken from the BMP085 datasheet
    int ac1, ac2, ac3;
    unsigned int ac4, ac5, ac6;
    int b1, b2, mb, mc, md;
    int temperature;
    long pressure;
    int analogpin1 = 0;
    
    void setup()
    {
    
      Serial.begin(9600); // start serial for output
      analogpin1 = analogRead(1);    // read the input pin A1 potmeter value
      //Serial.print("Analog pin A0 value: ");
      //Serial.println(analogpin1);
      //Serial.println("Setting up BMP085");
    
      Wire.begin();
      bmp085_get_cal_data();
      bmp085_read_temperature_and_pressure(&temperature, &pressure);
      flpressure = pressure; // move long type pressure into float type flpressure
      p0 = lowpassFast = lowpassSlow = flpressure;
      //Serial.print(" p0 = ");
      //Serial.println(p0);
      pinMode(3, INPUT); // Set our input pins as such for altitude command input from receiver via pin D3
      pinMode(6, INPUT); //Input for RC-Channel to set (change ) deadband during flight
    }
    
    void loop()
    {
      bmp085_read_temperature_and_pressure(&temperature, &pressure);
      float t = temperature / 10.0;
      //Serial.println(t,1);
      //Serial.println(" ");
      float p = flpressure / 100;
      //Serial.println(p,2);
      // Serial.print(" ");
      //Serial.println(deadband);
      //Serial.println(ch1);
      flpressure = pressure;// move long type pressure into float type flpressure
      altitude = (float)44330 * (1 - pow(((float) flpressure / p0), 0.190295));
      //Serial.print(" ");
      //Serial.println(altitude);
      altitude = abs(altitude); // if flying from hills negative altitude becomes indicated as positive
      lowpassFast = lowpassFast + (flpressure - lowpassFast) * 0.2;
      lowpassSlow = lowpassSlow + (flpressure - lowpassSlow) * 0.1;
      toneFreq = (lowpassSlow - lowpassFast) * 50;
      toneFreqLowpass = toneFreqLowpass + (toneFreq - toneFreqLowpass) * 0.1;
      toneFreq = constrain(toneFreqLowpass, -500, 500);
      ddsAcc += toneFreq * 100 + 2000;
    
      if (deadbandchannel == 1)
      {
        int ch2 = pulseIn(6, HIGH, 25000);
        if (ch2 < 1000) {
          ch2 = 1000; //otherwise over-value gives sensless results!
        }
        if (ch2 > 2000) {
          ch2 = 2000; //otherwise over-value gives sensless results!
        }
        deadband = (map(ch2, 1000, 2000, 0, 300));
    
    
      }
    
      if (toneFreq < 0 || ddsAcc > 0)
      {
        if (abs(toneFreq) > deadband)
        {
          tone(2, toneFreq + 550);
          ledOn();  // the Arduino led will blink if the Vario plays a tone, so you can test without having audio connected
        }
      }
      else
      {
        noTone(2);
        ledOff();
      }
      while (millis() < time);        //loop frequency timer
      time += 20;
      int ones = altitude % 10;
      int tens = (altitude / 10) % 10;
      int hundreds = (altitude / 100) % 10;
      int thousands = (altitude / 1000) % 10;
    
      ch1 = pulseIn(3, HIGH, 25000); // Read the pulse width of servo signal connected to pin D3
      //  Serial.print (ch1);
      //
      //   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 won't 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 ten meters altitude
          {
            tone(2, 1100); //1100 Hz tone frequency for the tens
            ledOn();
            delay(200);
            noTone(2);
            ledOff();
            delay(200);
          }
    
        if (altitude_per_meter == 1 && hundreds == 0)
        {
          delay(750);                            //longer delay between tens and ones
    
          if (ones == 0)
          {
            tone(2, 1300);               //long pulse if the number is zero
            ledOn();
            delay(600);
            noTone(2);
            ledOff();
          }
          else
            for (char a = 0; a < ones; a++)         //this loop makes a beep for each meter altitude
            {
              tone(2, 1300); //1300 Hz tone frequency for the ones
              ledOn();
              delay(200);
              noTone(2);
              ledOff();
              delay(200);
            }
        }
      }
    }
    
    void bmp085_read_temperature_and_pressure(int* temperature, long* pressure) {
      int ut = bmp085_read_ut();
      long up = bmp085_read_up();
      long x1, x2, x3, b3, b5, b6, p;
      unsigned long b4, b7;
    
      //calculate the temperature
      x1 = ((long)ut - ac6) * ac5 >> 15;
      x2 = ((long) mc << 11) / (x1 + md);
      b5 = x1 + x2;
      *temperature = (b5 + 8) >> 4;
    
      //calculate the pressure
      b6 = b5 - 4000;
      x1 = (b2 * (b6 * b6 >> 12)) >> 11;
      x2 = ac2 * b6 >> 11;
      x3 = x1 + x2;
    
      if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1;
      if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2);
      if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1;
      if (oversampling_setting == 0) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 2;
    
      x1 = ac3 * b6 >> 13;
      x2 = (b1 * (b6 * b6 >> 12)) >> 16;
      x3 = ((x1 + x2) + 2) >> 2;
      b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
      b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
      p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
    
      x1 = (p >> 8) * (p >> 8);
      x1 = (x1 * 3038) >> 16;
      x2 = (-7357 * p) >> 16;
      *pressure = p + ((x1 + x2 + 3791) >> 4);
    }
    
    unsigned int bmp085_read_ut() {
      write_register(0xf4, 0x2e);
      delay(5); //longer than 4.5 ms
      return read_int_register(0xf6);
    }
    
    void bmp085_get_cal_data() {
      // Serial.println("Reading Calibration Data");
      ac1 = read_int_register(0xAA);
      // Serial.print("AC1: ");
      // Serial.println(ac1,DEC);
      ac2 = read_int_register(0xAC);
      //  Serial.print("AC2: ");
      //  Serial.println(ac2,DEC);
      ac3 = read_int_register(0xAE);
      //  Serial.print("AC3: ");
      //  Serial.println(ac3,DEC);
      ac4 = read_int_register(0xB0);
      //  Serial.print("AC4: ");
      //  Serial.println(ac4,DEC);
      ac5 = read_int_register(0xB2);
      //   Serial.print("AC5: ");
      //   Serial.println(ac5,DEC);
      ac6 = read_int_register(0xB4);
      //   Serial.print("AC6: ");
      //   Serial.println(ac6,DEC);
      b1 = read_int_register(0xB6);
      //   Serial.print("B1: ");
      //  Serial.println(b1,DEC);
      b2 = read_int_register(0xB8);
      //  Serial.print("B2: ");
      //  Serial.println(b2,DEC);
      mb = read_int_register(0xBA);
      //   Serial.print("MB: ");
      //   Serial.println(mb,DEC);
      mc = read_int_register(0xBC);
      //   Serial.print("MC: ");
      //   Serial.println(mc,DEC);
      md = read_int_register(0xBE);
      //   Serial.print("MD: ");
      //   Serial.println(md,DEC);
    }
    
    long bmp085_read_up() {
      write_register(0xf4, 0x34 + (oversampling_setting << 6));
      delay(pressure_waittime[oversampling_setting]);
    
      unsigned char msb, lsb, xlsb;
      Wire.beginTransmission(I2C_ADDRESS);
      Wire.write(0xf6); // register to read
      Wire.endTransmission();
    
      Wire.requestFrom(I2C_ADDRESS, 3); // read a byte
      while (!Wire.available()) {
        // waiting
      }
      msb = Wire.read();
      while (!Wire.available()) {
        // waiting
      }
      lsb |= Wire.read();
      while (!Wire.available()) {
        // waiting
      }
      xlsb |= Wire.read();
      return (((long)msb << 16) | ((long)lsb << 8) | ((long)xlsb)) >> (8 - oversampling_setting);
    }
    
    void write_register(unsigned char r, unsigned char v)
    {
      Wire.beginTransmission(I2C_ADDRESS);
      Wire.write(r);
      Wire.write(v);
      Wire.endTransmission();
    }
    
    char read_register(unsigned char r)
    {
      unsigned char v;
      Wire.beginTransmission(I2C_ADDRESS);
      Wire.write(r); // register to read
      Wire.endTransmission();
    
      Wire.requestFrom(I2C_ADDRESS, 1); // read a byte
      while (!Wire.available()) {
        // waiting
      }
      v = Wire.read();
      return v;
    }
    
    int read_int_register(unsigned char r)
    {
      unsigned char msb, lsb;
      Wire.beginTransmission(I2C_ADDRESS);
      Wire.write(r); // register to read
      Wire.endTransmission();
    
      Wire.requestFrom(I2C_ADDRESS, 2); // read a byte
      while (!Wire.available()) {
        // waiting
      }
      msb = Wire.read();
      while (!Wire.available()) {
        // waiting
      }
      lsb = Wire.read();
      return (((int)msb << 8) | ((int)lsb));
    }
    
    
    void ledOn()
    {
      digitalWrite(led, 1);
    }
    
    
    void ledOff()
    {
      digitalWrite(led, 0);
    }
    
    
    
     
    PapaHotel en Berrie vinden dit leuk.
  3. hmeijdam

    hmeijdam

    Lid geworden:
    29 jan 2010
    Berichten:
    1.884
    Locatie:
    Barneveld
    Omdat de foto's verdwenen waren uit de bouwinstructie van de ontvanger hierbij opnieuw
    Bouwinstructie Poor Mans Vario ontvanger versie 2

    Voor de ontvanger van de Poor Mans Vario heb ik een dubbelzijdig printje laten maken, waardoor het bouwen veel simpeler is. Hieronder een foto van het printje en de Versie 2 ontvanger.

    P1120451.JPG
    De benodigde onderdelen om de ontvanger te bouwen zijn verder niet gewijzigd.


    Bij het bouwen van de ontvanger is het handig om de platste onderdelen eerst te solderen en dan de hoogte in te werken. Dan vallen de onderdelen er niet uit als je het printje omdraait om ze vast te solderen.

    Stap 1: Soldeer de weerstand
    P1120456.JPG

    stap 2: Soldeer de LM386. Let op dat je hem er niet ondersteboven in soldeert. Het halve rondje in zijn dak zit op dezelfde plek als het getekende halve rondje op het printje. Let op: dit is een component met meerdere pootjes. Soldeer eerst één pootje vast en kijk dan of het component niet scheef zit en of het vlak op de print ligt. Nu kun je nog de ene soldering weer zacht maken en het component bewegen tot hij goed zit. Pas als je zeker weet dat hij goed zit soldeer je de overige pootjes vast.
    P1120457.JPG

    Stap 3: Soldeer de oortelefoon connector, de rechte pinheaders en de condensator. Ook dit zijn weer componenten met meerdere pootjes. Let op: soldeer de pinheaders met hun korte kant in de print, het langste stuk steekt naar boven uit. Let op: Bij het solderen van de condensator moet je zijn langste pootje in het gaatje met de " + " solderen.
    P1120459.JPG

    Stap 4: Soldeer de aan-uit schakelar. Hierbij kan een wasknijper helpen om hem mooi vlak te houden en aangeschoven tegen de 6 pinheaders. Het maakt niet uit bij de schakelaar wat onder of boven is.
    P1120460.JPG
    Uiteindelijk moet de schakelaar zo vastgesoldeerd worden:
    P1120461.JPG

    Stap 5: Ontvangermodule solderen
    Pak nu de ontvangermodule en de 4 gebogen pinheaders en controleer goed met onderstaande foto of je de gebogen pinheaders er correct in hebt gestoken, voor je ze vast soldeert (ze kunnen er op 4 manieren in worden gestoken en er is er maar één goed).
    P1120462.JPG

    Stap 6: Ontvangermodule op de print solderen. Check ook weer na één pootje solderen of hij een beetje recht zit, alvorens de andere 3 vast te zetten.
    P1120463.JPG

    Stap 6 Potmeter en antenne solderen. Dit zijn de laatste 2 componenten die gesoldeerd moeten worden. Als antenne kan de bijgeleverde spiraal worden gebruikt of een 17,2cm lang draadje. Ik heb soms de indruk dat een draadje iets beter ontvangt, maar dan moet het wel gestrekt zijn.
    P1120464.JPG

    Stap 7: Luidspreker solderen.
    P1120465.JPG


    in het volgende bericht staat de aansluiting, want ik mag per bericht maar 10 foto's uploaden.
     
    Laatst bewerkt: 19 apr 2020
    Berrie vindt dit leuk.
  4. hmeijdam

    hmeijdam

    Lid geworden:
    29 jan 2010
    Berichten:
    1.884
    Locatie:
    Barneveld
    Nu ben je klaar om de ontvanger aan te sluiten. Op onderstaande foto zie je dat de speaker rechts wordt aangesloten, waarbij het niet uitmaakt welk plugje waar. Aan de linkerkant zie je de aansluiting van de batterij. Hierbij zit de plus (rode draad) in het midden en de min (zwarte draad) zit aan de rechterkant. Hier maakt de oriëntatie van de plug natuurlijk wel uit.
    P1120466.JPG

    Mocht je de zender nog niet hebben gebouwd, dan kun je de ontvanger testen met bijvoorbeeld een afstandbedienbare autosleutel. Als je een oortelefoon aansluit, schakelt de speaker uit.
     
    Berrie, Arnold 85 en Erik Janssen vinden dit leuk.
  5. Andreotti

    Andreotti

    Lid geworden:
    20 jun 2012
    Berichten:
    372
    Locatie:
    Alphen aan den Rijn
    Hi Hans,

    Je kan de hoogte ook uit laten spreken met een simpel stukje code:

    #include <Arduino.h>

    // https://github.com/ArminJo/Talkie
    #include "Talkie.h"
    #include "TalkieUtils.h"
    #include "Vocab_US_Large.h"

    // Talkie voice;
    Talkie voice(true, false); // wel pin 3, niet pin 11 (inverted)

    void setup() {}

    void loop()
    {
    sayQNumber(&voice, random(1000));
    voice.say(sp2_METER);
    delay(1500);
    }


    Klinkt zo:
    http://www.andreotti.nl/audio/speak-hight.mp3

    Als een oude C64 :D

    Je moet alleen wat pinnen omgooien aangezien de speech altijd op pin 3 zit.

    Groetjes,
    André
     
  6. hmeijdam

    hmeijdam

    Lid geworden:
    29 jan 2010
    Berichten:
    1.884
    Locatie:
    Barneveld
    haha, dat klinkt inderdaad een beetje als mijn oude C64 "I am Sam, the speaking program"

    [​IMG]

    ik heb dat ook geprobeerd, toen ik de PMV ontwierp, maar de On-Off-Key (OOK) modulatie RF setjes die ik gebruik maken het helemaal onverstaanbaar. Ik neem aan dat jij dit hebt opgenomen aan de uitgangspin van de Arduino en niet ook door de TX/RX modules.
     
    Laatst bewerkt: 30 jul 2021
  7. Andreotti

    Andreotti

    Lid geworden:
    20 jun 2012
    Berichten:
    372
    Locatie:
    Alphen aan den Rijn
    Dat klopt idd. Ik was van plan het in mijn pmv te bouwen, maar zo te horen is dat geen best plan. Misschien dat ik het nog wel even test met een andere Arduino en zendmodule aangezien er anders wat om gesoldeerd moet worden op de pmv.
     
  8. hmeijdam

    hmeijdam

    Lid geworden:
    29 jan 2010
    Berichten:
    1.884
    Locatie:
    Barneveld
    Is de moeite waard om te testen. Op enig moment ben ik overgestapt op een ander TX/RX setje met de SRX882 superheterodyne ontvanger en volgens mij heb ik het met dat setje nooit geprobeerd.
     
  9. Andreotti

    Andreotti

    Lid geworden:
    20 jun 2012
    Berichten:
    372
    Locatie:
    Alphen aan den Rijn
    Welja. Als ik zelf testresultaten heb laat ik het je weten.
    Ik liep hier tegenaan en moest meteen aan de pmv denken. Als het goed werkt leek me dit een mooie toevoeging.
    Groetjes,
    Andre
     
  10. Andreotti

    Andreotti

    Lid geworden:
    20 jun 2012
    Berichten:
    372
    Locatie:
    Alphen aan den Rijn
    Nou, daar is echt geen chocola van te maken!
    [​IMG]

    Het klinkt alsof 1 kant van de sinus is weggevallen en het is zwaar over gemoduleerd. Er is echt niks van de stem te horen, alleen maar geknerp en geschetter.
    Misschien met een weerstandje en een condensator dat het wel beter te krijgen is, maar ik denk dat die RX/TX setjes alleen bedoeld zijn voor data en niet voor audio.
    Tsja, als je het niet probeert...
     
  11. hmeijdam

    hmeijdam

    Lid geworden:
    29 jan 2010
    Berichten:
    1.884
    Locatie:
    Barneveld
    Klop. het zijn datatransmissie setjes. Een blokgolf piepsignaal lukt dan prima, maar dat spraaksignaal helaas niet. Ik weet ook niet of het spraaksignaal uit een blokgolf bestaat of dat ze een truukje hebben gevonden om de Arduino een variabele amplitude te geven. Een Arduino heeft immers geen DAC, dus je kunt hem geen sinus laten aanmaken. Met een weerstandje en condensator filter kun je dat wel benaderen, maar daar heeft de RF module niks aan, want die snapt alleen 0 of 1 als binnenkomend signaal. Vandaar de OOK modulatie (On-Off-Key).
     
  12. Andreotti

    Andreotti

    Lid geworden:
    20 jun 2012
    Berichten:
    372
    Locatie:
    Alphen aan den Rijn
    Dat "truukje" is misschien wel het vermelden waard en ook waarom er hier maar bepaalde pinnen voor beschikbaar zijn.
    Door de PWM uitgang op hoge frequentie te voorzien van korte en lange pulsen (afhankelijk van de toon frequentie) word een soort DAC gecreëerd.
    Iets wat op een lagere frequentie werkt zal dit zien als verandering in voltage, variabele amplitude?
    Die pulsen werken op dusdanig hoge frequenties dat ze ver boven de gehoorgrens liggen, dus daar merk je niet zo veel van, het klinkt toch al waardeloos.
    De RX/TX setjes kunnen hier niks mee (die kunnen die hoge frequentie misschien helemaal niet aan). De input is aan of uit (boven of onder een bepaald gemeten voltage). De pulsen worden heel anders verwerkt.
    Deze DAC emulator werkt alleen op pin 3 en 11 omdat dat de enige pinnen zijn waar een hele hoge frequentie op gehaald kan worden.
    Ja, ik gebruik ook die SRX882/STX882 setjes. Dat werkt ongelofelijk goed, wat een bereik!
     

Deel Deze Pagina