Skocz do zawartości

Arduino i DLG = logger wysokosci, wariometr + alarm napiecia lipo cdn.


Rekomendowane odpowiedzi

Opublikowano

Witajcie,

Wiele osob pyta mnie o zabawki, ktore uzywam w DLG zrobione na arduino. Nie jestem programista, ani elektronikiem, wiec jest wiele bledow. Najważniejsze jednak, że dziala :)

 

 

Jest wiele watkow opisujacych jak zaczac zabawe z arduino (instalujemy srodowisko arduino, sterowniki, dodawanie bibliotek...), dlatego ta czesc pomine.

 

Jako pirwsze opisze prosty i bardzo tani logger wysokosci.

 

Lista zakupow z Chin:

1) plytka arduino pro mini (1,25$ )

https://www.arduino.cc/en/Main/ArduinoBoardProMini

 

1a) dodatkowo do zaprogramowania konieczny bedzie programator na ukladzie FTDI232 (1,20$) - doslownie nie jest to programator a emulator portu RS232 na USB, z wyjsciem TTL.

 

 

2)plyteczka z portem karty microSD, w wersji zasilanej oraz sterowanej napieciem 5V - (ok 0,50$)

https://s15.postimg.org/kfxyhv23f/microsd_breakout_board.jpg

 

3) czujnik cisnienia BMP180 (np shield GY-68) wazne aby byl sterowany poziomem 5v - (2,50$)

4) kabelek od serwomechanizmu (z szuflady 0$).

 

Ceny z aliekspress przy opcji FREE SHIPPING.

Podsumowując 4,25$ bez programatora (po dzisiejszym kursie to nie cale 19zl).

 

No i zaczynamy. Oczywiscie nie lutujemy goldpinow, tylko cienkimi przewodami laczymy plytki na pajaka i skladamy kanapeczke.

 

Oto schemat:

 

post-5212-0-61171200-1479491431_thumb.jpg

 

a oto moj "pajaczek":  Wymiary 40x20x10mm, waga 9g.

 

post-5212-0-29800900-1479491436_thumb.jpg

 

 

No i zostaje wgranie programu. Zaprezentowany przeze mnie kod jest troszke przemodelowanym zlepkiem przykladow arduino (pomiar wysokosci i zapis na SD), zaprezentowany kiedys tu:

http://jadiema.blogspot.com/2014/09/micro-rocket-data-logger.html

 

 

W moim kodzie dodalem filtr dolnoprzepustowy, oraz logowanie poziomu PWM na kanale odbiornika w ktorym bedzie wpiety logger.
 

/*
 SD card datalogger
 This example shows how to log data from three analog sensors
 to an SD card using the SD library.
 The circuit:
 * analog sensors on analog ins 0, 1, and 2
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4

Pins SDA & SCL
BMP085 wiring
** SDA - A4
** SCL - A5
** VCC - 5V
** GND - GND

Pin to receiver channel
** pin 9

*/

#include <Wire.h>
#include <SD.h>

#define PWMpin 9
#define DEBUG
//#define DEBUG_BMP085
int tempomesure = 500; //temporisation de la boucle
unsigned long t0=0;
unsigned long prevMillis=0;
//BMP085
#define BMP085_ADDRESS 0x77  // I2C address of BMP085, idem BMP1080
const unsigned char OSS = 0;  // Oversampling Setting
// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...)
// so ...Temperature(...) must be called before ...Pressure(...).
long b5;

short temperature;
long pressure;

// Use these for altitude conversions
const float p0 = 101325;     // Pressure at sea level (Pa)
float altitude;

//LOW PASS FILTER
float LowPassAltitude;

//Reveiver channel 
int PWMval =0;


//SD CARD
const int chipSelect = 4;

long fileNum = 0;  // maximum 99999
String fileName;
char name[13];
File dataFile;

void incFileNum() { // generate next file name:
  String s = "dat" + String(++fileNum) + ".txt";
  s.toCharArray(name,13);
}

void save(String s) {
  dataFile = SD.open(name, FILE_WRITE);
  if (dataFile) {
    dataFile.println(s);
    dataFile.close();
    Serial.println(s);
  } 
  else Serial.println("error opening " + String(name));

  
}

void setup()
{
  pinMode(chipSelect, OUTPUT);

  // Open serial communications and wait for port to open:

  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

 //Efface le fichier initial
 // SD.remove("DATA.txt");

//GESTION DES NOMS DES FICHIERS
  //--------------------------------------------------
  incFileNum(); // set it to datxxxx.txt
  while (SD.exists(name)) incFileNum();

#ifdef DEBUG
  Serial.println("new file name: " + String(name));
#endif
  //--------------------------------------------------
  
  save("t(ms),Altitude(m)*100,LowPassAltitude(m)*100,Pression(Pa),Temperature(C)*10,PWM");

//CAPTEUR bmp085
  Wire.begin();
  bmp085Calibration();
//initialisation du temps:
unsigned long prevMillis = millis();

  pinMode(PWMpin,INPUT); // reveiver channel PWM

//first measure
  temperature = bmp085GetTemperature(bmp085ReadUT());
  pressure = bmp085GetPressure(bmp085ReadUP());
  altitude = (float)44330 * (1 - pow(((float) pressure/p0), 0.190295));
  LowPassAltitude=altitude;
}

void loop()
{
if ((millis() - prevMillis) > tempomesure) {
/////////////////////////////////////////////////////////////// 
   PWMval = pulseIn(9,HIGH);
 //  PWMval=map(PWMval, 0, 1028, 0, 255);
   
//  Capteur pression et temperature
  temperature = bmp085GetTemperature(bmp085ReadUT());
  pressure = bmp085GetPressure(bmp085ReadUP());
  altitude = (float)44330 * (1 - pow(((float) pressure/p0), 0.190295));

// Low pass filter
LowPassAltitude=LowPassAltitude+(altitude - LowPassAltitude)*0.1;

#ifdef DEBUG_BMP085
  Serial.print("Temperature: ");
  Serial.print(temperature, DEC);
  Serial.println(" *0.1 deg C");
  Serial.print("Pressure: ");
  Serial.print(pressure, DEC);
  Serial.println(" Pa");
  Serial.print("Altitude: ");
  Serial.print(altitude, 2);
  Serial.println(" m");
  Serial.println();
  Serial.print("Low_Pass_Altitude: ");
  Serial.print(LowPassAltitude, 2);
  Serial.println(" m");
  Serial.println();
  Serial.print("PWM ");
  Serial.print(PWMval, 2);
  Serial.println();
#endif
  //delay(tempomesure);
///////////////////////////////////////////////////////////////
  // make a string for assembling the data to log:
 
  String dataString = "";
  //OLD
  //t0 = t0 + (millis() - prevMillis);
  //NEW
  t0 = millis();
/*
#ifdef DEBUG
  Serial.print("millis():");
  Serial.print(millis());
  Serial.print(",");
  Serial.print("t0:");
  Serial.print(t0);
  Serial.print(",");
#endif
 */
  unsigned int alti = altitude*100;
  unsigned long pressu = pressure;
  unsigned int tempe = temperature;
  unsigned int LPalti = LowPassAltitude*100;
  unsigned int PWM = PWMval;
 
  dataString = String(t0) + "," + String(alti) + "," + String(LPalti) + "," + String(pressu) + "," + String(tempe)+ "," + String(PWM);
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
 
  //File dataFile = SD.open("DATA.txt", FILE_WRITE);
  File dataFile = SD.open(name, FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    #ifdef DEBUG
        // print to the serial port too:
      Serial.println(dataString);
    #endif   
  } 
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }//fin du if dataFile
  prevMillis = millis();
}
 
}// fin de loop

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

// Stores all of the bmp085's calibration values into global variables
// Calibration values are required to calculate temp and pressure
// This function should be called at the beginning of the program
void bmp085Calibration()
{
  ac1 = bmp085ReadInt(0xAA);
  ac2 = bmp085ReadInt(0xAC);
  ac3 = bmp085ReadInt(0xAE);
  ac4 = bmp085ReadInt(0xB0);
  ac5 = bmp085ReadInt(0xB2);
  ac6 = bmp085ReadInt(0xB4);
  b1 = bmp085ReadInt(0xB6);
  b2 = bmp085ReadInt(0xB8);
  mb = bmp085ReadInt(0xBA);
  mc = bmp085ReadInt(0xBC);
  md = bmp085ReadInt(0xBE);
}

// Calculate temperature given ut.
// Value returned will be in units of 0.1 deg C
short bmp085GetTemperature(unsigned int ut)
{
  long x1, x2;
 
  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
  x2 = ((long)mc << 11)/(x1 + md);
  b5 = x1 + x2;

  return ((b5 + 8)>>4); 
}

// Calculate pressure given up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(...) must be called first.
// Value returned will be pressure in units of Pa.
long bmp085GetPressure(unsigned long up)
{
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;
 
  b6 = b5 - 4000;
  // Calculate B3
  x1 = (b2 * (b6 * b6)>>12)>>11;
  x2 = (ac2 * b6)>>11;
  x3 = x1 + x2;
  b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
 
  // Calculate B4
  x1 = (ac3 * b6)>>13;
  x2 = (b1 * ((b6 * b6)>>12))>>16;
  x3 = ((x1 + x2) + 2)>>2;
  b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
 
  b7 = ((unsigned long)(up - b3) * (50000>>OSS));
  if (b7 < 0x80000000)
    p = (b7<<1)/b4;
  else
    p = (b7/b4)<<1;
   
  x1 = (p>>8) * (p>>8);
  x1 = (x1 * 3038)>>16;
  x2 = (-7357 * p)>>16;
  p += (x1 + x2 + 3791)>>4;
 
  return p;
}

// Read 1 byte from the BMP085 at 'address'
char bmp085Read(unsigned char address)
{
  unsigned char data;
 
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();
 
  Wire.requestFrom(BMP085_ADDRESS, 1);
  while(!Wire.available())
    ;
   
  return Wire.read();
}

// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
int bmp085ReadInt(unsigned char address)
{
  unsigned char msb, lsb;
 
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();
 
  Wire.requestFrom(BMP085_ADDRESS, 2);
  while(Wire.available()<2)
    ;
  msb = Wire.read();
  lsb = Wire.read();
 
  return (int) msb<<8 | lsb;
}

// Read the uncompensated temperature value
unsigned int bmp085ReadUT()
{
  unsigned int ut;
 
  // Write 0x2E into Register 0xF4
  // This requests a temperature reading
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x2E);
  Wire.endTransmission();
 
  // Wait at least 4.5ms
  delay(5);
 
  // Read two bytes from registers 0xF6 and 0xF7
  ut = bmp085ReadInt(0xF6);
  return ut;
}

// Read the uncompensated pressure value
unsigned long bmp085ReadUP()
{
  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;
 
  // Write 0x34+(OSS<<6) into register 0xF4
  // Request a pressure reading w/ oversampling setting
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x34 + (OSS<<6));
  Wire.endTransmission();
 
  // Wait for conversion, delay time dependent on OSS
  delay(2 + (3<<OSS));
 
  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF6);
  Wire.endTransmission();
  Wire.requestFrom(BMP085_ADDRESS, 3);
 
  // Wait for data to become available
  while(Wire.available() < 3)
    ;
  msb = Wire.read();
  lsb = Wire.read();
  xlsb = Wire.read();
 
  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);
 
  return up;
}

Testujemy. Jak? Po zaprogramowaniu, nie odpinamy ukladu od komputera, tylko w srodowisku arduino otwieramy okno "monitor szeregowy", predkosc transmisji ustawiamy na 9600 i cieszymy sie z efektow naszej pracy.

 

Najważniejsze, czyli JAK TO DZIALA?

Uklad podlaczamy pod wolny kanal odbiornika (zasilanie 5V). Od razu po wlaczeniu, program sprawdza czy obecna jest karta SD, nastepnie tworzony jest na karcie plik TXT z kolejnym numerkiem w nazwie i  urzadzonko zaczyna w nim zapisywac:

czas (ms), cisnienie (hPa), wysokosc bezwzgledna(m n.p.m.), wysokosci bezwzgledna po filtrze dolnoprzepustowym(m n.p.m.), wartosc PWM zczytana z kanalu w ktory wpiety jest logger.

 

Czas pomiedzy kolejnymi zapisami to okolo 2sek.

 

Poziom PWM osobiscie wykorzystuje jako znacznik, kiedy zmieniam w terenie parametry lotu i pozniej w domu analizujac chce wiedziec dokladnie ktora czesc barografki odpowiada jakiemu ustawieniu modelu.

 

 

Odczyt danych:

Wyjmujemy karte mikroSD, wkladamy do czytnika i zgrywamy pliki *.txt. Nastepnie otwieramy plik txt przy pomocy excela, wybierajac jako separator przecinek ",".

 

W kolejnych kolumnach mamy zapisane:

>> czas [ms]

>> cisnienie [hPa]

>> wysokosc bezwzgledna [m n.p.m.]

>> wartosc wysokosci po filtrze dolnoprzepustowym [m n.p.m.]

>>Wartość PWM

 

Mam nadzieje ze nie popelnilem tu zadnych bledow, dlatego jesli ktos sie pokusi o poskladanie loggera prosze o info czy wszystko jest OK.

 

 

===================================================================================

 

 

 

Kolejny projekt to wariometr. Urzadzenie pracujace na 433MHz, no i niestety cena juz jest znaczaco wyzsza, bo wynosci bedzie okolo 21zl.

 

Zakupy:

 

nadajnik latajacy w modelu:

1) plytka arduino pro mini (1,25$)

2) plyteczka z czujnikiem cisnienia BMP180 (2,50$)

3) nadajnik i odbiornik na 433MHz ( odbiornik XY-MK-5V, nadajnik fs1000a) (0,60$)

4) kabelek od serwa (z szuflady - 0$).

 

odbiornik na ziemi:

5) wzmacniacz audio (scalak LM386, w PL jakies 2zl)

6) jakis glosniczek - ja skorzystalem ze starej kolumienki od glosnikow komputerowych (skorzystalem z tej z gniazdem jack oraz potencjometrem z wylacznikiem).

7) bakteria (ja uzywam lipola 2s i stabilizatora 7805).

 

No to zaczynamy. Cale wario opisane jest bardzo dokladnie tu:

https://www.rcgroups.com/forums/showthread.php?t=1749208

 

oraz tu bardziej zaawansowana wersja:

http://www.modelbouwforum.nl/threads/poor-mans-vario.199904/page-5

 

 

Nadajnik:

Podlaczenie kabelka serwa do arduino robimy jak w schemacie z dataloggera z ta roznicza ze przewod sygnalu PWM podpinamy pod pin 3 arduino. Czujnik cisnienia podpinamy jak na schemacie dataloggera.

Nadajnik fs1000a podpinamy w nastepujacy sposob:

GND - do GND arduino czyli (-) zasilania

DATA - do pinu 2 arduino.

VCC - do VCC 5V arduino.

AND - dolutowac tu nalezy antenke w postaci przewodu o dlugosci 16,5cm

 

Odbiornik

Zaczynamy od podpiecia do osbiornika zasilania 5V pomiedzy VCC i GND, oraz glosniczka pomiedzy DATA i GND.

Do AND dolutowujemy kabelek 16,5cm.

 

 

Program:

//**********************************
//* 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
//
//
// ****** 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 - 500 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 potmeter
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 deadbandpotmeter = 0; // no deadband potmeter present
// const char deadbandpotmeter = 1; // deadband potmeter is present (10K potmeter over pins 12, A1 (rocker) and A2)

#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 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()
{
pinMode(A2, OUTPUT); // Prepare for high end of potmeter
pinMode(12, OUTPUT); // Prepare for low end of potmeter
pinMode(A1, INPUT_PULLUP); // Prepare for potmeter input
digitalWrite(A2, HIGH); // High end potmeter to 5 volt
digitalWrite(12, LOW); //Low end potmeter to 0 volt
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
}

void loop()
{
bmp085_read_temperature_and_pressure(&temperature,&pressure);
// Serial.print(temperature,DEC);
// Serial.print(" ");
// Serial.println(pressure,DEC);
// Serial.print(" ");
flpressure = pressure;// move long type pressure into float type flpressure
altitude = (float)44330 * (1 - pow(((float) flpressure/p0), 0.190295));
//Serial.print(" ");
// Serial.print(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;
Serial.print(" ddsAcc: ");
Serial.println(ddsAcc);
if (deadbandpotmeter == 1)
{
analogpin1 = analogRead(1); // read the input pin A1 potmeter value
deadband = map(analogpin1, 0, 1024, 500, 0); // map potmeter value to deadband range from 500 - 0
}

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;
// Serial.print ("thousands: ");
// Serial.println (thousands);
// Serial.print ("hundreds: ");
// Serial.println (hundreds);
// Serial.print ("tens: ");
// Serial.println (tens);
// Serial.print ("ones: ");
// Serial.println (ones);
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);
}

Jak to dziala?

Nadajniczek wariometru wpinamy w wolny slot w odbiorniku RC (zasilanie 5V) sterowany w aparaturze rc przelacznikiem.

Dzialanie zalezy od ustawienia wspomnianego przelacznika: W pierwszej skrajnej pozycji wariometr mierzy wysokosc, przepuszcza przez dwa filtry dolnoprzepustowe a z roznicy wartosci miedzy wynikami z tych dwoch filtrow wylicza czestotliwosc dzwieku. Wysyla sygnal do nadajnika, a odbiornik nie robi nic poza odbiorem analogowego sygnalu i wysterowaniem glosniczka.

W drugiej skrajnej pozycji przelacznika wariometr "pikajac" podaje wysokosc. Wyjasnione jest to w komentarzach w kodzie programu.

 

Cieszymy sie z dzialania, ale... jest cicho i zasieg na kilka metrow. Czyli slabo.

 

Operacja pierwsza - modyfikacja odbiornika:

Odbiornik musimy wyposarzyc we wzmacniacz audio. W tym celu wykorzystamy scalony wmacniacz LM386 oraz stara kolumne od glosnikow komputerowych, w ktorej znajdziemy glosnik, potencjometr i gniazdko sluchawkowe (pomocne gdy na startowisku jest wiecej niz jeden modelarz).

Korzystamy z tego schematu:

post-5212-0-88976600-1479494253.jpg

 

Czy to trudne? Nie :) wzmacniacz z powodzeniem mozemy poskladac "na pajaka", Vin to nasz sygnal z odbiorniczka (dwa zwarte piny podpisane DATA), sygnal ten trafia na dzielnik z potencjometru i na noge nr 3 ukladu scalonego. Noga 2 i 4 zwieramy do GND, noge nr 6 podpinamy do zasilania 5v. Noge nr 5 zapinamy do masy przez maly kondensator 0,05uF  i opornik 10ohm. Glosnik wpinamy miedzy GND i noge nr 5 - szeregowo z kondensatorem elektrolitycznym 250uF

Koszt super wzmiacniacza - 5zl :)

 

Operacja druga - modyfikacja anteny odbiornika:

Duzo lepszy zasieg otrzymamy stosujac zamiast antenki "bacika" antene typu dipol. Co potrzebujemy? Ok 50cm przewodu ekranowanego (np tego miedzy komputerem a wspomnianymi starymi glosniczkami).

Jeden koniec podpinamy do odbiornika:

>>ekran do GND

>>zyla do ANT

 

Na drugim koncu przewodu wykonujemy antene: Odizolowac nalezy 16,5cm przewodu i oddzielic ekranosobno i zyle sygnalowa osobno. Nastepnie odgiac ekran w jedna strone a zyle sygnalowa w druga, tak aby z przewodem do odbiornika utworzyly ksztalt litery T, lub Y. Oczywiscie konstrukcje dobrze jest usztywnic drewnianym patyczkiem lub precikiem z tworzywa sztucznego.

Zdjecie zaporzyczone z sasiedniego forum

post-5212-0-25719800-1479495137_thumb.jpg

 

Operacja trzecia - zasilanie nadajnika:

Bardzo waznym parametrem wyplywajacym bezposrednio na moc nadawanego sygnalu jest napiecie zasilania nadajnika. Skoro tak, to przy samym nadajniku miedzy piny GND i VCC nalezy wlutowac kondensator elektrolityczny (wystarczy 100uF, nalezy pamietac o polaryzacji kondensatora elektrolitycznego).

 

Osobiscie zasilam model z lipo 2S 7,2V przez tzw BEC. Zasilajac wariometr z odbiornika RC zasilam go napieciem 5V.  Zatem prosta modyfikacja znacznie poprawiajaca zasieg, jest odlutowanie przewodu zasilajacego pomiedzy arduino i nadajniczkiem VCC fs1000a. I zasilenie nadajniczka 433MHz bezposrednio z lipola (np. z gniazda balansera - jak na foto mojego wariometru:

 

post-5212-0-91255100-1479495924.jpg

 

Schematy nadajnika po wspomnianych modyfikacjach zasilania:

post-5212-0-68779400-1479497872.jpg

jakie

Schemat odbiornika ze wzmacniaczem i antena dipol

post-5212-0-75999800-1479499496_thumb.jpg

 

 

Mam nadzieje ze nic nie pomylilem, poniewaz schematy powstaly tylko na potrzebe tego postu.

Na zdjeciu mojego wario widać, że fioletowy przewod podlaczany do lipola wchodzi pod termokurcza na arduino i dopiero tam jest polaczony z zasilajacym przewodem do nadajniczka. A to dlatego, ze pod termokurczem zrobiony jest dzielnik napiecia z dwoch rezystorow i podlaczony do wejscia analogowego arduino. Chodzi o to ze arduino ma mierzyc napiecie na lipolu i w momencie spadku ponizej zadanej wartosci w glosniku wariometru ma byc slyszalny alarm. Przedstawie to rozwiazanie ponizej.

 

 

 

======================================================================================

 

Wariometr modelarski z pomiarem napiecia baterii lipo i alarmem rozladowanej baterii

 

 

Wariometr wykonujemy dokladnie tak jak to opisano powyzej, w wersji podlaczenia zasilania nadajnika fs1000a bezposrednio do lipola 2S (napiecie pomiedzy 8,4V a 7,2V).

 

Jedyna modyfikacją jest dolutowanie dzielnika napiecia zrobionego z dwoch opornikow 10kOhm. Zgodnie ze schematem:

post-5212-0-91409000-1479567274_thumb.jpg

 

Oczywiscie pamietajmy, ze wszystkie piny w arduino podpisane GND sa ze soba zwarte, podobnie piny VCC. Chcac podlutowac sie pod mase od nas zalezy ktory pin podpisany GND wybierzemy. Dlatego ponizsze zdjecia przedstawiajace moje wario nie sa w 100% zgodne ze schematem:

 

Wariometr bez koszulki:

post-5212-0-71431400-1479566048_thumb.jpg

 

Zblizenie na podlaczenie na plytce arduino:

post-5212-0-35098800-1479566072_thumb.jpg

 

Komplet elektroniki jaki lata w moim modelu (oczywiscie plus serwa):

post-5212-0-96885000-1479566940.jpg

 

 

Kod programu:

//**********************************
//*   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
//
//
//  ****** 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 - 500 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 potmeter
   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 deadbandpotmeter = 0;  // no deadband potmeter present
//const char deadbandpotmeter = 1;  // deadband potmeter is present (10K potmeter over pins 12, A1 (rocker) and A2)

#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 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;
int analogpin2 = 0;
int voltage;


void setup()
{
  pinMode(A0, INPUT); // pomiar npiecia baterii
  pinMode(A2, OUTPUT); // Prepare for high end of potmeter
  pinMode(12, OUTPUT); // Prepare for low end of potmeter
  pinMode(A1, INPUT_PULLUP); // Prepare for potmeter input
  digitalWrite(A2, HIGH); // High end potmeter to 5 volt
  digitalWrite(12, LOW); //Low end potmeter to 0 volt
  Serial.begin(9600); // start serial for output
  analogpin1 = analogRead(A1);    // read the input pin A1 potmeter value
  Serial.print("Analog pin A1 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
}

void loop()
{
  
// Pomiar napiecia baterii, wartosc napiecia mnozona *10. 

  analogpin2 = analogRead(A0);    // read the input pin A0 potmeter value
     voltage = map(analogpin2, 0, 1024, 0, 100); // map potmeter value to deadband range from 0 - 100 (0-10v)
   Serial.print("voltage= ");
   Serial.print(voltage,DEC);
   Serial.println("V");
  
  if (voltage < 74) // jezeli napiecie pakietu nizsze niz 7,4v >> wlacz alarm
  {
    tone(2, 3000);
    delay(100);
    noTone(2);
    delay(100);
    tone(2, 3000);
    delay(100);
    noTone(2);
    delay(100);
  }
    
    
  
  
  
  bmp085_read_temperature_and_pressure(&temperature,&pressure);
  // Serial.print(temperature,DEC);
  // Serial.print(" ");
 //  Serial.println(pressure,DEC);
  // Serial.print(" ");
  flpressure = pressure;// move long type pressure into float type flpressure
  altitude = (float)44330 * (1 - pow(((float) flpressure/p0), 0.190295));
  //Serial.print(" ");
  // Serial.print(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;
  Serial.print(" ddsAcc: ");
  Serial.println(ddsAcc);
  if (deadbandpotmeter == 1)
  {
    analogpin1 = analogRead(A1);    // read the input pin A1 potmeter value
    deadband = map(analogpin1, 0, 1024, 500, 0); // map potmeter value to deadband range from 500 - 0
  }

  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;
  //   Serial.print ("thousands: ");
  //   Serial.println   (thousands);    
  //   Serial.print ("hundreds:  ");
  //   Serial.println   (hundreds);  
  //   Serial.print ("tens:      ");
  //   Serial.println   (tens);  
  //   Serial.print ("ones:      ");
  //   Serial.println   (ones);    
  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);
}

Jak to dziala? W glownej ptli programu mierzone jest napiecie na pinie A0 do ktorego podlaczone przez dzielnik jest zasilanie z lipolka. Sygnal przeliczany jest na wartosc napiecia brutto na lipolu mnozona *10.

Jesli warunek jest spelniony napiecie<7,4V (w programie warunek "voltage<74 ")w glosniku uslyszymy charaktrystyczne pikanie.

Oczywiscie wartosc 7,4v mozemy zmieniac dowolnie. Nalezy jednak pamietac ze pomiar napiecia jest wzgledem napiecia zasilania procesora w arduino 5V. Czyli jesli napiecie lipolka spadnie na tyle, ze po BECu napiecie bedzie nizsze niz wspomniane 5V, pomiar bedzie obarczony bledem.

 

Obawiam sie, czy spadki napiecia spowodowane przez dzialajace serwa, nie beda powodowaly zadzialanie alarmu. Jesli tak, dopisze filtr dolnoprzepustowy na pomiar napiecia. Niestety teraz pogoda nie nastraja na proby terenowe, a tylko wtedy bede wiedzial czy pomiar dziala jak nalezy.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • Lubię to 3
Opublikowano

Szczerze, pogniotłeś mi moją młodą psychikę ;)  Wygląda to zbyt pięknie żeby mogło być prawdziwe.

Mam nadziej, że uda mi się zrobić taki wariometr :D

Opublikowano

Ja od razu korzystam z funkcji dla tego czujnika zwracającej wysokość na podstawie pierwszego pomiaru ciśnienia.
Wychodzi mniejszy plik i szybciej się zapisuje na wolnych kartach (ot 3 bajty zamiast 6) i chyba na to znaczenie przy bieżących niskich temperaturach.

 

---Edit

 

Coś mi się nie wszystko z pierwszego posta wyświetliło w taplatalku, wobec czego po ponownym obejrzeniu wątku na PC - to co wyżej napisałem - jest jakoś tak średnio odkrywcze ;-)

Opublikowano

...

tani logger wysokości

...

Testujemy. Jak? Po zaprogramowaniu, nie odpinamy ukladu od komputera, tylko w srodowisku arduino otwieramy okno "monitor szeregowy", predkosc transmisji ustawiamy na 9600 i cieszymy sie z efektow naszej pracy.

...

 

Dało się uruchomić, wyniki są (ustrojstwo trzymane w ręku)

 

 

Teraz tylko kawałek dobrej pogody by się przydał...

Opublikowano

Zapis na SD działa poprawnie?

Generalnie wykorzystasz tylko wartość czasu, wysokość po filtrze dolnoprzepustowym i ewentualnie PWM.

Zapisywana jest też temperatura czujnika, niestety jest ona zazwyczaj o kilka stopni wyższa niż temperatura otoczenia.

Opublikowano

Zapis na kartę jest bez problemowy.

 

Pliczek w załączniku.

Zapis co ok. 30 sekund

Opublikowano

Chyba dlatego jest wyższa, bo płytka się grzeje. Zauważyłem że ten czujnik wystawiony na zewnątrz modelu ma mniejszy błąd względem otoczenia niż schowany w modelu.

Ale nie ma co narzekać. Jest ultra tani. Zawsze można dołożyć ds18b20 jeśli zależy nam na dokładnym pomiarze temperatury. Prawie nic nie waży i jest mały.

Opublikowano

Skoro zapis na kartę działa, to znaczy, ze schemat połączeń i wsad sa OK :) ciesze sie.

 

Co do temperatury, to mierzona jest właśnie temperatura samego czujnika, bo jest ona potrzebna do kalibracji wskazań. Wystawianie poza model to chyba nie najlpszy pomysł ze względu na ciśnienie dynamiczne podczas lotu i błędne wskazania ciśnienia.  Jednak dołożenie ds18b20 jest doskonałym pomysłem. Pytanie tylko po co mierzyć temperaturę ;) ...może w przypadku motoszybowca gdzieś blisko silnika, albo baterii.

Opublikowano
Cieszymy sie z dzialania, ale... jest cicho i zasieg na kilka metrow. Czyli slabo.

Jaki jest zasięg po tych wszystkich modyfikacjach? Da się uzyskać bezproblemowo kilkaset metrów?

 

I druga kwestia - bardzo trudno by było zrobić wersję, która by podawała wysokość poprzez komunikaty głosowe?

Opublikowano

Kiedyś również zrobiłem sobie taki prosty wariometr na bmp180 i błąd pomiaru wysokości u mnie wynosił około +-2 metry. U Was też są tak duże rozbieżności?

Opublikowano

Odczyt danych:

Wyjmujemy karte mikroSD, wkladamy do czytnika i zgrywamy pliki *.txt. Nastepnie otwieramy plik txt przy pomocy excela, wybierajac jako separator przecinek ",".

 Drobna modyfikacja:

 

w linii 77  

             String s = "dat" + String(++fileNum) + ".txt";

zmieniamy txt na csv:

             String s = "dat" + String(++fileNum) + ".csv";

 

w linii 127

             save("t(ms),Altitude(m)*100,LowPassAltitude(m)*100,Pression(Pa),Temperature©*10,PWM");

zmieniamy przecinek na średnik:

             save("t(ms);Altitude(m)*100;LowPassAltitude(m)*100;Pression(Pa);Temperature©*10;PWM");

 

w linii 203

             dataString = String(t0) + "," + String(alti) + "," + String(LPalti) + "," + String(pressu) + "," + String(tempe)+ "," + String(PWM);

też zmieniamy przecinek na średnik:

             dataString = String(t0) + ";" + String(alti) + ";" + String(LPalti) + ";" + String(pressu) + ";" + String(tempe)+ ";" + String(PWM);

 

 

Excel otwiera plik jak "swój"

Opublikowano

Kiedyś również zrobiłem sobie taki prosty wariometr na bmp180 i błąd pomiaru wysokości u mnie wynosił około +-2 metry. U Was też są tak duże rozbieżności?

Gąbka na czujniku zmniejsza rozbieżności.

 

Natomiast co do zasięgu - robiłem testy na takich modułach i uzyskałem max 62m latając idealnie nad odbiornikiem i ustawiając anteny równolegle w poziomie. Program był inny - m in nadawanie było co 2sekundy i z użyciem jakiegoś kodowania (już nie pamiętam). Ciągłość transmisji po ziemi miałem do max 30 m (odbierałem każdą paczkę). Powyżej tej odległości skuteczność odbioru spadała strasznie.

 

Są inne moduły (np od open lrs) które mają większy zasięg i mniej wpływają na odbiornik rc.

Opublikowano

 

Kiedyś również zrobiłem sobie taki prosty wariometr na bmp180 i błąd pomiaru wysokości u mnie wynosił około +-2 metry. U Was też są tak duże rozbieżności?

Dlatego wyniki trzeba filtrować.

 

 

Jaki jest zasięg po tych wszystkich modyfikacjach? Da się uzyskać bezproblemowo kilkaset metrów?

 

I druga kwestia - bardzo trudno by było zrobić wersję, która by podawała wysokość poprzez komunikaty głosowe?

Zasięg?

Kluczowym jest, że transmisja jest analogowa (sygnalu audio), zatem trudno powiedzieć kiedy "zasięg jest" a kiedy juz sygnal jest na tyle slaby i trudny do wyłowienia z szumu i "zasiegu nie ma".

Po zasileniu nadajnika prosto z lipo, oraz zbudowaniu anteny dipol na odbiornik ja nie tracę zasięgu (albo trace na chwilke przy zaslonieciu anteny przez weglowy kadlub)  do 200m, niestety wtedy juz prawie nie widzę modelu. Moj max na wysokosci to 220m, ale juz tylko kropka na niebie i lot właśnie słuchając wariometru.

Wplywu na link RC nie zaobserwowalem, pomimo iż obie anteny mam odsuniete jedynie o szerokosc kadluba.

 

Komunikaty głosowe sa bardzo łatwe do zorganizowania, odtwarzacz mp3 na microSD kosztuje 2$, pytanie tylko po co? W tym rozwiązaniu transmisji sygnalu musiałby on latać w modelu. Jest to płytka 20x20mm i wazy kolejne kilka gramów.

Tu jest minimum z minimum, czyli jak najtaniej i przede wszystkim - jak najmniejszy wymiar i jak najlżej .

 

 String s = "dat" + String(++fileNum) + ".txt";

zmieniamy txt na csv:

             String s = "dat" + String(++fileNum) + ".csv";

 

Ano :) calkiem fajne rozwiazanie, ja akurat mam zrobiony arkusz w Excelu, w którym makro samo otwiera plik, kopiuje dane i robi wykresy. Przy takim rozwiązaniu rozszerzenie nie ma znaczenia. 

Opublikowano

Zasięg?

Kluczowym jest, że transmisja jest analogowa (sygnalu audio), zatem trudno powiedzieć kiedy "zasięg jest" a kiedy juz sygnal jest na tyle slaby i trudny do wyłowienia z szumu i "zasiegu nie ma".

 

Komunikaty głosowe sa bardzo łatwe do zorganizowania, odtwarzacz mp3 na microSD kosztuje 2$, pytanie tylko po co? W tym rozwiązaniu transmisji sygnalu musiałby on latać w modelu. Jest to płytka 20x20mm i wazy kolejne kilka gramów.

Tu jest minimum z minimum, czyli jak najtaniej i przede wszystkim - jak najmniejszy wymiar i jak najlżej .

 

W międzyczasie temat trochę rozeznałem i większego problemu z lepszymi modułami nadawczo - odbiorczymi za rozsądne pieniądze raczej nie ma. 

 

Rozumiem, że jest to wersja minimum i w DLG liczy się każdy gram. Mi zależy na wersji do innych modeli, gdzie te parę gram nie ma znaczenia natomiast ważniejsza jest funkcjonalność. Po co komunikaty głosowe? Przyzwyczaiłem się do vario Pitlaba, gdzie mogę w każdej chwili odpytać o wysokość. I mi się to przydaje w krążenie w "zerze". Vario co chwilę zmienia dźwięk i trudno określić czy model się minimalnie wznosi czy opada. Wtedy odpytuje o wysokość raz, za chwilę drugi raz i wiem czy mam noszenie czy model opada. Tutaj też ta funkcjonalność jest zaszyta, ale bez komunikatów głosowych praktycznie bezużyteczna.

 

A generalnie to najchętniej widziałbym rozwiązanie, gdzie sygnał jest przekazywany na ziemię cyfrowo, potem przez bluetooth trafia do telefonu i tam jest obrabiany z dźwiękiem vario, komunikatami głosowymi, rejestracją danych, wykresami i odpowiednimi wskazaniami na wyświetlaczu smartfona. Niby są takie systemy telemetrii, ale to już jest niestety droższe i aplikacje do nich nie spełniają moich oczekiwań. Generalnie takie coś było by bardzo małe, lekkie i dość tanie. Tylko, żeby ktoś zechciał jeszcze napisać aplikację na smartfona.

 

EDIT:

 

Dziękuję za sugestię z tymi modułami MP3. Faktycznie sprawa wygląda prosto. Będę się musiał za to wziąć. Szkoda tylko, że ostatnio jednoukładówki coś programowałem blisko 20 lat temu i to w asemblerze.

Opublikowano

Wybacz szczerość, ale tak lekko licząc za jednego Pitlaba zbudujesz 25 sztuk wariometrów z tego tematu, więc porównywanie funkcjonalności nie bardzo ma sens :P

 

 

W międzyczasie temat trochę rozeznałem i większego problemu z lepszymi modułami nadawczo - odbiorczymi za rozsądne pieniądze raczej nie ma.

To może podziel sie spostrzeżeniami. Bo akurat temat jest mi bliski i mam zupełnie inne zdanie na temat odbiorników w tym przedziale cenowym.

 

 

 

A generalnie to najchętniej widziałbym rozwiązanie, gdzie sygnał jest przekazywany na ziemię cyfrowo, potem przez bluetooth trafia do telefonu i tam jest obrabiany z dźwiękiem vario, komunikatami głosowymi, rejestracją danych, wykresami i odpowiednimi wskazaniami na wyświetlaczu smartfona. Niby są takie systemy telemetrii, ale to już jest niestety droższe i aplikacje do nich nie spełniają moich oczekiwań. Generalnie takie coś było by bardzo małe, lekkie i dość tanie. Tylko, żeby ktoś zechciał jeszcze napisać aplikację na smartfona.

To jest najlepsze rozwiazanie, zostaje kwestia zapychania odbiornika RC danymi z mocnego nadajnika latającego w modelu. No i.. jak latam, to nie patrze na telefon, zazwyczaj konczy sie to zgubieniem modelu na niebie ;)

 

 

Dużo łatwiejszym rozwiązaniem jest skorzystanie z dwukierunkowej komunikacji linku RC na 2,4GHz. Z czego np. protokoły FrSky oraz Hiteca są już opisane na sasiednim angielskojęzycznym forum. Wchodzi w gre albo wysylanie danych i wyswietlanie na aparaturze (np Aurorze Hiteca), albo wyprowadzenie sygnału z modułu nadawczego i jego interpretacja przez pikanie, sygnaly glosowe, przesylanie bluetootchem itp...

Cena śmiesznie mala.. w sumie wychodzi taniej niż opisany tu wariometr ;)

Opublikowano

Akurat vario Pitlaba nie posiada jakichś mega bajerów. I w opisanym tutaj właśnie wariometrze brakuje mi w zasadzie tylko komunikatów głosowych.

 

Co do cen to mi nie zależy na wariometrze za 20 zł. 150-200 zł za lepszy czujnik ciśnienia i lepszy moduł nadawczy by było dla mnie jak najbardziej OK. A odbiór sygnału najchętniej bym widział na radiotelefonie LPD.

 

Co do komunikacji linku RC na 2,4 GHz to oczywiście racja, ale ja chce to do 35 Mhz. I tutaj specjalny link 2,4 tylko do telemetrii się mija z celem, za drogo i trochę chyba jednak bez sensu.

Opublikowano

EDIT:

 

Dziękuję za sugestię z tymi modułami MP3. Faktycznie sprawa wygląda prosto. Będę się musiał za to wziąć. Szkoda tylko, że ostatnio jednoukładówki coś programowałem blisko 20 lat temu i to w asemblerze.

Do mnie plytka mod-1021 dojechala w tym tygodniu i samo odtwarzanie dziala bardzo fajnie. Manual dostepny tu https://www.embeddedadventures.com/datasheets/MOD-1021_hw_v1.pdf

Jednak przyznam ze jeszcze nie mam pomysłu jak w jeden drut wepchnąć sygnał audio modulowany przez procesor oraz sygnał z odtwarzacza mp3.

Opublikowano

Jednak przyznam ze jeszcze nie mam pomysłu jak w jeden drut wepchnąć sygnał audio modulowany przez procesor oraz sygnał z odtwarzacza mp3.

 

Najprościej tak jak w pasywnych mikserach audio czyli poprzez rezystory na obu liniach plus ewentualnie dzielnik(i) napięcia dla ustalenia podobnego poziomu głośności. Przykład:

post-12748-0-24657600-1480186629.png

Opublikowano

Z poziomem sygnalu problemu nie ma, bo sam odtwarzacz ma regulacje glosnosci. Przy czym da rade wyslac odrazu polecenie aby odtworzyc np sciezke numer 1 z glosnoscia 33% :)

trzeba popróbować.

×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Umieściliśmy na Twoim urządzeniu pliki cookie, aby pomóc Ci usprawnić przeglądanie strony. Możesz dostosować ustawienia plików cookie, w przeciwnym wypadku zakładamy, że wyrażasz na to zgodę.