Curralt - kleiner, günstiger Stromsensor mit Vario

kalle123

User
Kleine Sensoren mit Atmel 328 und oXs hatten wir schon mal vor Jahren

Quelle: https://openrcforums.com/forum/viewtopic.php?f=86&t=7938

20 x 28 mm

openXsensor.jpg

und eine etwas 'brutale' Methode

MiniOXS.jpg

cu KH
 
Hallo Freunde des Thermikflugs,

anbei ein Auszug des Codes, den ich zum Auswerten der Höhe und zur Berechnung des Vario-Signals nutze.

Code:
//Roll Values in array one down. Last value is discarded (Rolling Average)
for (byte i = ALTITUDE_SAMPLES - 1; i > 0; i--){  
	Altitude[i] = Altitude[i-1];
}

//read altitude
Altitude[0] = bmp.readAltitude(1013.25);  

//calculate average from samples
for (byte i = 0; i < ALTITUDE_SAMPLES; i++){    
	Altitude_average += Altitude[i];
}
Altitude_average = Altitude_average / ALTITUDE_SAMPLES;

//Feed altitude average to filter
altitude_filter.input(Altitude_average);	

//Save maximum altitude
if (altitude_filter.output() > Altitude_max){
	Altitude_max = altitude_filter.output();
}

//Update Vario
if ((millis() - last_vario_update) >= VARIO_UPDATE){
	last_vario_update = millis();
	
	//Roll values in array one down. Last value is discarded
	for (byte i = 12; i > 0; i--){                
		Altitude_History[i] = Altitude_History[i-1];
		Altitude_History_millis[i] = Altitude_History_millis[i-1];
	}
	Altitude_History[0] = altitude_filter.output();
	Altitude_History_millis[0] = millis();
	
	//Set altitude offset
	if (Altitude_offset == 0){    
		//Check if alitude reading is available
		if (bmp.readAltitude(1013.25) != 0){  
			//Use 10 readings as average for offset
			for (byte i = 0; i < 10; i++){      
				Altitude_offset += bmp.readAltitude(1013.25);
			}
			Altitude_offset = Altitude_offset / 10;
		}

	//Initialize Altitude Array to have correct Vario reading from beginning on.
	for (byte i = 1; i < (1000/VARIO_UPDATE); i++){
		Altitude_History[i] = Altitude_offset;
		Altitude_History_millis[i] = millis();
	}
  }
}

//Feed vario values to vario filters
vario_filter_1s.input((Altitude_History[0] - Altitude_History[1000/VARIO_UPDATE]) * (1000/ (Altitude_History_millis[0] - Altitude_History_millis[1000/VARIO_UPDATE])));
vario_filter_3s.input((Altitude_History[0] - Altitude_History[3000/VARIO_UPDATE]) * (3000/ (Altitude_History_millis[0] - Altitude_History_millis[3000/VARIO_UPDATE])));

//Update Temperature
if ((millis() - last_tmp_update) > TMP_UPDATE) {
	BMP_Temp = bmp.readTemperature();
	last_tmp_update = millis();
}

Kurze Erklärung: Ich nehme ein Rolling Average des Höhensensors (BMP280). Aktuell nutze ich dafür 3 Samples (definiert in ALTITUDE_SAMPLES). Diesen Durchschnittswert füttere ich in einen Tiefpass-Filter mit (momentan) 0,4Hz Grenzfrequenz. Dafür nutze ich diese Library: https://github.com/JonHub/Filters
In regelmäßigen Abständen (definiert in VARIO_UPDATE, aktuell alle 250ms) aktualisiere ich das Vario. Dafür Speichere ich die Höhenwerte (Altitude_History) mit zugehöriger Zeit (Altitude_History_millis) der letzten 3 Sekunden alle 250ms ab. Anschließend füttere ich die Werte in die Vario-Filter für 1s (Grenzfrequenz 1Hz) und 3s (Grenzfrequenz 0,2Hz).
Das Abspeichern der Zeit und die Normierung der entsprechenden Vario-Werte brauche ich, da der Controller evtl. mit Antworten auf das Telemetrieprotokoll beschäftigt ist. Dann wird das Vario nicht exakt nach 250ms sondern etwas später.

Das Vario spricht dadurch relativ schnell an.
Gibt es Vorschläge was ich noch verbessern könnte?

Grüße

Niko
 
Hallo Niko,
1. irgendwie fehlt mir fuer Altitude_average die Initialisierung ?

2. Muesste die Durchschnittsberechnung nicht auch den aktuellen Wert im ersten Array-Element beruecksichtigen, also
//calculate average from samples
for (byte i = 0; i < ALTITUDE_SAMPLES; i++){
Altitude_average += Altitude;
}
Altitude_average = Altitude_average / ALTITUDE_SAMPLES;

bis dann
Arnd
 
Hallo Niko,
1. irgendwie fehlt mir fuer Altitude_average die Initialisierung ?

die initialisierung für fast alle Variablen (auch der Arrays) habe ich nicht mit kopiert. Die ist aber vorhanden ;)

2. Muesste die Durchschnittsberechnung nicht auch den aktuellen Wert im ersten Array-Element beruecksichtigen, also
//calculate average from samples
for (byte i = 0; i < ALTITUDE_SAMPLES; i++){
Altitude_average += Altitude;
}
Altitude_average = Altitude_average / ALTITUDE_SAMPLES;



vollkommen richtig, habe ich korrigiert. Danke!
 
Hallo Freunde des Thermikfluges ;)

ich habe den Code etwas optimiert:

Code:
//Roll Values in array one down. Last value is discarded (Rolling Average)
for (byte i = ALTITUDE_SAMPLES - 1; i > 0; i--){  
	Altitude[i] = Altitude[i-1];
}

//read altitude
Altitude[0] = bmp.readAltitude(1013.25);  

//calculate average from samples
for (byte i = 0; i < ALTITUDE_SAMPLES; i++){    
	Altitude_average += Altitude[i];
}
Altitude_average = Altitude_average / ALTITUDE_SAMPLES;

//Feed altitude average to filter
altitude_filter.input(Altitude_average);	

//Save maximum altitude
if (altitude_filter.output() > Altitude_max){
	Altitude_max = altitude_filter.output();
}

//Update Vario
if ((millis() - last_vario_update) >= VARIO_UPDATE){
	last_vario_update = millis();
	
	//Roll values in array one down. Last value is discarded
	for (byte i = 12; i > 0; i--){                
		Altitude_History[i] = Altitude_History[i-1];
		Altitude_History_millis[i] = Altitude_History_millis[i-1];
	}
	Altitude_History[0] = altitude_filter.output();
	Altitude_History_millis[0] = millis();
	
	//Set altitude offset
	if (Altitude_offset == 0){    
		//Check if alitude reading is available
		if (bmp.readAltitude(1013.25) != 0){  
			//Use 10 readings as average for offset
			for (byte i = 0; i < 10; i++){      
				Altitude_offset += bmp.readAltitude(1013.25);
			}
			Altitude_offset = Altitude_offset / 10;
		}

	//Initialize Altitude Array to have correct Vario reading from beginning on.
	for (byte i = 1; i < (1000/VARIO_UPDATE); i++){
		Altitude_History[i] = Altitude_offset;
		Altitude_History_millis[i] = millis();
	}
  }
}

//Feed vario values to vario filters
vario_filter_1s.input((Altitude_History[0] - Altitude_History[300/VARIO_UPDATE]) * (1000/ (Altitude_History_millis[0] - Altitude_History_millis[300/VARIO_UPDATE])));
vario_filter_3s.input((Altitude_History[0] - Altitude_History[1500/VARIO_UPDATE]) * (3000/ (Altitude_History_millis[0] - Altitude_History_millis[1500/VARIO_UPDATE])));

//Update Temperature
if ((millis() - last_tmp_update) > TMP_UPDATE) {
	BMP_Temp = bmp.readTemperature();
	last_tmp_update = millis();
}

Größter Unterschied ist, dass ich die Vario-Filter mit dem Delta von nur 300ms (Vario_1s) bzw. 1500ms (Vario_3s) füttere. Zudem werden die Werte alle 100ms aktualisiert. Dadurch spricht das Vario recht gut an.
Das ganze habe ich mal mit einer Dummy-Höhe, welche mit 1m/s anteigt, simuliert um mir das Ansprechverhalten des Varios anzusehen. Für das Vario habe ich eine Hysterese von 0.25 gesetzt, heißt Steig- bzw. Sinkraten < 0.25 m/s werden als 0 ausgegeben. Dadurch ist der Sender ruhig, wenn der Höhensensor (BMP280) nicht bewegt wird.
Das Ergebnis sieht so aus:

Vario_Start.jpg

Durch den gleitenden Mittelwert und den Tiefpassfilter auf dem Höhensignal, habe ich einen Versatz von ca. 375ms zwischen "echtem" Höhensignal (hier natürlich nur simuliert) und dem Output des Tiefpassfilters für das Höhensignal.
Das Vario_1s Signal "springt" nach 440ms von 0 auf 25cm/s (Hysteresewert) und erreicht nach 812ms 66%.

Vario_Change.jpg

Hier ein Sprung von 1m/s Steigen auf 2m/s Sinken. Hier vergehen ca. 580ms bis das Vario den ersten negativen Wert ausspuckt. Nach ca. 1000ms ist das Vario bei 66% (bzw. -1,33m/s).

Da ich mich noch nie mit Ansprechverhalten von Variometern beschäftigt habe: Sind das gute Werte?? Oder sollte das Vario schneller reagieren?

Grüße

Niko
 
Hallo Niko,

schau mal unter http://www.wstech.de die Variometerkunde an.

Ich hab mir vor Jahren ein Vario mit einem analogen Drucksensor MPX4115A und analoger Differenzierung für meine FrSky D8 Empfänger und DFT Modul gebaut. Die Responce Time auf 68% (Sprungantwort) liegt bei ca. 400 ms. Im nächsten Winter werde ich mir vieleicht auch mal ein GY 63 (MS5611) besorgen.

Dein Projekt Curralt gefällt mir übrigens ausserordentlich gut.

Gruß
Micha
 
Ich glaube nicht dass die Höhenmessungen so sauber daherkommen wie in deiner Simulation. In der Realität (Flug mit Thermikturbulenzen) hatte ich Rauschen mit Amplituden über 1m auf den Messdaten. Wenn man da ein Variosignal mit einer Auflösung von 0.1m/s mit Rauschen kleiner 0.1m/s rausziehen will muss man deutlich stärker filtern. Gerade bei schwacher Thermik ist es eben entscheidend ob ich mit 0.1m/s sinke oder steige um so Bärte auch am Rand zu erkennen und zu zentrieren.

Ich habe bei meinen Eigenbausensoren die Filterwerte über ein Servosignaleingang einstellbar gemacht und so im Flug ermittelt. Auch verschiedene Filtermethoden habe ich so verglichen und wie bereits erwähnt bin ich bei einer mitlaufenden linearen Regression gelandet. Reine Tiefpassfilter waren viel träger bei gleichem Variorauschen.

Gruss Lukas
 
Hallo Niko,

schau mal unter http://www.wstech.de die Variometerkunde an.

Danke für den Link! Sehr interessant (... und auch etwas niederschmetternd :rolleyes:)

An die Präzision des LinkVarios mit +/-0,03m/s :eek: komme ich bei weitem nicht ran. Ich bewege mich mit dem Rauschen bei ca. +/-0,3m/s, was sich auch mit der Beschreibung bei wstech für einfache Varios deckt.
Man darf natürlich auch nicht vergessen, dass hier mit einem Sensor gemessen wird, der weniger als 1$ kostet.

Ich glaube nicht dass die Höhenmessungen so sauber daherkommen wie in deiner Simulation. In der Realität (Flug mit Thermikturbulenzen) hatte ich Rauschen mit Amplituden über 1m auf den Messdaten. Wenn man da ein Variosignal mit einer Auflösung von 0.1m/s mit Rauschen kleiner 0.1m/s rausziehen will muss man deutlich stärker filtern. Gerade bei schwacher Thermik ist es eben entscheidend ob ich mit 0.1m/s sinke oder steige um so Bärte auch am Rand zu erkennen und zu zentrieren.

Das Höhensignal vom Sensor kommt natürlich nicht so schön sauber daher. Bei der Simulation ging es mir ja aber um das Ansprechverhalten der Filter.
Das Höhensignal (Filter Output) rauscht mit ca. +-0,2m. Das Vario-Signal rauscht mit ca. +-0,3m/s. Das auf 0,1m/s zu drücken wäre natürlich eine Herausforderung.
Für ein präziseres Vario ist die gesamte Hardware aber vermutlich gar nicht geeignet. War bzw. ist ja aber auch nicht mein Ziel.
Wäre aber eine Idee fürs nächste Winter-Projekt ;)

Ich habe bei meinen Eigenbausensoren die Filterwerte über ein Servosignaleingang einstellbar gemacht und so im Flug ermittelt. Auch verschiedene Filtermethoden habe ich so verglichen und wie bereits erwähnt bin ich bei einer mitlaufenden linearen Regression gelandet. Reine Tiefpassfilter waren viel träger bei gleichem Variorauschen.

Magst du den zugehörigen Code vielleicht teilen?
Für mich ist die ganze Vario-Berechnung gänzlich neu. Hauptsächlich habe ich das Projekt Curralt eigentlich zur günstigen Strom- und Kapazitätsmessung ins Leben gerufen. Der BMP280 ist nur auf der Platine gelandet, da er so schön klein und günstig ist.

Grüße

Niko
 
Für ein präziseres Vario ist die gesamte Hardware aber vermutlich gar nicht geeignet. War bzw. ist ja aber auch nicht mein Ziel.
Wäre aber eine Idee fürs nächste Winter-Projekt ;)

Hallo Niko,

als Vario für einen ambitionierten Segelflieger ist der BMP280 sicherlich nicht geeignet. Aufgrund dem starken Signalrauschen ist eine
Filterung mit großen Zeitkonstanten unabdingbar. Damit wird das Vario sehr träge. Ein gutes Vario sollte gerade kleine Steigwerte < 1 m/s
schnell und präzise Anzeigen. Ist das Vario sehr träge, dann bin ich mit meinem Segler eventuell schon durch den Bart hindurch geflogen.

Ich würde das eher als ein Messinstrument zur Bestimmung der Flughöhe und der Steiggeschwindigkeit im Kraftflug sehen. Dafür ist der BMP280
eine sehr kleine und kostengünstige Lösung. Mein analoger Drucksensor MPX 4115A alleine kosten schon um die 16 Euro und ist zudem auch recht groß.

Wünsche weiterhin viel spaß bei tüfteln.

Gruß
Micha
 

onki

User
Ich würde das eher als ein Messinstrument zur Bestimmung der Flughöhe und der Steiggeschwindigkeit im Kraftflug sehen. Dafür ist der BMP280
eine sehr kleine und kostengünstige Lösung. Mein analoger Drucksensor MPX 4115A alleine kosten schon um die 16 Euro und ist zudem auch recht groß.

Stimmt - daher verwende ich den auch in den (OXS-basierten) Flowmeter-Sensoren, die ich für meine Schlepp-Kumpels gebaut habe. Mich nervt es langsam, denen immer beim F-Schlepp die Höhe ansagen zu müssen:rolleyes:. Der X-Sensor mag den BMP280 leider nicht (mehr) sonst wäre das meine Wahl dafür.
Das reicht für eine vernünftige Höhenmessung und ggf. zur akustischen Überwachung des Steigfluges.

An Segler lasse ich nur den MS5611:D.

Gruß
Onki
 
Der X-Sensor mag den BMP280 leider nicht (mehr) sonst wäre das meine Wahl dafür.
Das reicht für eine vernünftige Höhenmessung und ggf. zur akustischen Überwachung des Steigfluges.

XSensor ist doch auch quelloffen und auf ATmega328p basis, oder? Dann wäre es ja eigentlich kein Hexenwerk die BMP280 library statt der MS5611 lib einzubinden.

An Segler lasse ich nur den MS5611:D.

Ja, der hat schon so seine Vorteile. Aber für Präzisionsvariometer ist der auch nicht wirklich geeignet.
Wie gesagt, nächsten Winter brauche ich ja auch nen Projekt, vielleicht wird es ja ein Präzisionsvario...

Grüße

Niko
 
XSensor ist doch auch quelloffen und auf ATmega328p basis, oder? Dann wäre es ja eigentlich kein Hexenwerk die BMP280 library statt der MS5611 lib einzubinden.



Ja, der hat schon so seine Vorteile. Aber für Präzisionsvariometer ist der auch nicht wirklich geeignet.

Ich kenne keinen Sensor in der Grösse der genauer und schneller ist und würde drauf wetten, dass das ws-tech Vario auch den MS5611 benutzt.

Meinen Quellcode hab ich im Jetiforum veröffentlicht (Esens). Ich werde ihn hier auch noch reinstellen, habe erst am Montag wieder Zugriff darauf.

Gruss Lukas
 
Ich kenne keinen Sensor in der Grösse der genauer und schneller ist und würde drauf wetten, dass das ws-tech Vario auch den MS5611 benutzt.

Hallo Lukas,

die Wette würdest Du verlieren. Ich besitze 5 wstech varios. Es ist der selbe analoge Drucksensor den ich in meinem DIY Vario verwende, nur mit
Schlauchanschluss für die TEK Düse.

Gruß
Micha
 
Ich nehme ein Rolling Average des Höhensensors (BMP280). Aktuell nutze ich dafür 3 Samples (definiert in ALTITUDE_SAMPLES). Diesen Durchschnittswert füttere ich in einen Tiefpass-Filter mit (momentan) 0,4Hz Grenzfrequenz.

Hallo Niko,

du könntest den Tiefpass-Filter nochmals mit dem Ergebnis vom TP1 berechnen. Dann hast Du ein TP 2. Ordnung mit 40 dB pro Dekade.
Dazu die Filterkoeffizienten halbieren. Dann ist der Filter etwas schneller bei Endwert. Im Anhang ist das Excel File als Beispiel, erstellt in OpenOffice.

Tiefpass1.jpg

Gruß
Micha
 

Anhänge

  • LowPass_Filter_1.xls
    15,5 KB · Aufrufe: 117
Hi Micha,

danke für den Hinweis, werde ich bei Gelegenheit ausprobieren.
Habe mir auch mal einen MS5611 bestellt, damit ich mit dem auch mal spielen kann. Evtl. muss ja ein neuer Satz Platinen her ;)

Da heute das Wetter so schön war, habe ich heute erste Werte im Flug sammeln können. Getestet habe ich in meiner Tundra, mein Arbeitstier.
Dabei lag der Fokus natürlich auf der Strom/Spannungsmessung. Leider verträgt sich mein Curralt auf GAM momentan nicht mit dem Unisens-E auf EAM. Woran das liegt muss ich noch herausfinden. Daher leider kein direkter Vergleich bzw. Referenz verfügbar.

Ergebnis:
Akku 1:
Curralt: 1950mAh; Nachgeladen: 1829mAh; Abweichung: + 6,6%

Akku 2:
Curralt: 1530mAh; Nachgeladen: 1449mAh; Abweichung: + 5,6%


Das sieht also gar nicht so schlecht aus. Die Abweichung ist beides mal ähnlich und sollte so durch Korrektur des Stromfaktors zu beheben sein. Die Temperatur im Rumpg (gemessen durch BMP280) war bei ca 16°C Außentemperatur bei 21-22°C. Das ist auch ungefähr die Temperatur, mit der ich kalibriert habe.

Ich hoffe, dass ich Curralt und Unisens-E gleichzeitig (EAM und GAM) ans laufen bekomme, dann werde ich mal einen direkten Vergleich machen und hier vorstellen.

Grüße

Niko
 
Ansicht hell / dunkel umschalten
Oben Unten