Einfache Jeti EX Telemetrie-Library für Arduino Mini Pro 328

Sepp62

User
Hallo Onki,

mit Strommessung habe ich keine praktische Erfahrung, ich habe in meine Turbinen-Telemetrie jedoch eine Integrationsfunktion der Spritpumpenspannung eingebaut, die den verbrauchten Treibstoff messen soll. Das Ganze ist noch nicht ausreichend in der Praxis getestet, ich sage Dir trotzdem mal, wie ich es gemacht habe:

1. In der Hauptschleife des Arduino versuchst Du so viele Analog-Messwerte (des Stroms) wie möglich zu bekommen. Je weniger CPU Deine anderen Programmteile (z.B. die Telemetrieübertragung) verbrauchen, desto mehr Messwerte wirst Du bekommen (natürlich limitiert durch die Konvertierungsrate des ADC). Über die so ermittelten Messwerte bildest Du später ein arithmetisches Mittel. D.h. Du summierst sie auf und zählst wie viele es sind. Mit dieser Methode versuchst Du "Spitzen" im Stromfluss zu erwischen. Die ACS7xx-Sensoren haben eine Filterfunktion, die den Messwert bereits ein wenig integrieren und so hast Du gute Chancen das Signal ausreichend abzutasten. Der Arduino-Wandler hat ein eingebautes Sample&Hold-Glied, so dass auch hier der Theorie genüge getan wird (Messsignal muss während des Konvertierungsvorgangs konstant bleiben --> Wandlerverfahren sukkzessive Approximation).

2. Nun musst Du über eine genau definierte Zeit messen. Bei der Turbinentelemetrie mache ich das über 5 Sekunden. Bei der Strommessung würde ich ein 1-2 Sekunden als Messintervall wählen. Über den "millis()"-Timer verzweigst Du in der Main-Loop nach z.B. einer Sekunde in die "Integrierfunktion". Dort bildest Du das arithmetische Mittel über Deine Samples aus Punkt1 (Summe durch Anzahl Werte). Dann hast Du die verbrauchte Kapazität in der letzten Sekunde ("Ampere-Sekunde"). Diese Werte summierst Du einfach auf (und konvertierst sie bei der Anzeige in mAh -> 1 mAh = 3.6 As).

3. Zurücksetzen der aufsummierten Kapazitätswerte:
Wenn Du Deinen Stromsensor über den Antriebsakku versorgst, fängst Du einfach nach dem Anstecken des Akkus neu an zu zählen (von 0 an). Ich bin skeptisch, dass Du es schaffst, dass die Messung den Akkuwechsel übersteht (das IISI-Cockpit merkst sich die Kapazität im Anzeigemodul, das gewöhnlich nicht ausgeschaltet wird). Du kannst natürlich die Kapazität nach jeder Messung in das EEPROM schreiben. Aber das kostet Zeit (bzw. erhöht die Latenz für das Sampling) und das EEPROM verträgt nicht unendlich viele Schreibvorgänge. Das Zurückschreiben beim "Power-Down" dürfte ebenfalls nicht so easy sein (großer Elko hinter Diode an den Arduino und messen, wann der Antriebsakku abgesteckt wird und hoffen, dass der Elko den Arduino so lange am Leben erhält, dass noch geschrieben werden kann ?).

Wenn der Stromsensor nicht vom Antriebsakku versorgt wird, misst Du einfach die Akkuspannung und wenn sie einen gewissen Wert überschreitet, setzt Du den Summenzähler zurück.

Leider habe ich dafür keinen fertigen Beispiel-Code. Meine Turbinentelemetrie ist auch kein gutes Beispiel, da die Spannungsintegration mit dem restlichen Code recht "verwoben" ist. Vielleicht hilft es Dir trotzdem.

Grüße
Bernd

PS: Stromsensoren mit I2C scheinen Exoten zu sein (ACS764). Die ACS7xx-Sensoren scheinen aber ansonsten ganz gut zur Aufgabenstellung zu passen. In den Sensoren des IISI-Cockpits sind sie auch verbaut (ACS758 im TXE 150).
 

onki

User
Hi Bernd,

danke für deine Hinweise. Ich werd mir vermutlich einen Teensy 3.2 für die Versuche besorgen, weil mir der am ausgereiftesten aussieht und schön kompakt ist. Nicht gerade günstig aber egal.
Als Sensor nehme ich den hier, weil der mir auch 5V liefert:
http://www.amazon.de/gp/product/B01...ue&ref_=ox_sc_act_title_2&smid=A2K1VKIT5OUK8Z
Zudem hat der Teensy einen 16 Bit ADC (13 Bit Netto) was sicher kein Fehler ist.
Mich reizt halt diese automatische Rücksetzung, sonst könnt ich mir gleich einen MUI zulegen. Aber es geht um das experimentieren, zumal ich bisher damit keinerlei Erfahrung hab.
Aber es ist noch Zeit bis zum nächsten Flieger, daher kann ich die so nutzen. Wenn es klappt hab ich meinen Homemade Sensor für mein kleines Bootchen, falls nicht kann ich immer noch nen UniSens oder den nicht ganz fertig gedachten MUI nehmen:cool:.

Gruß
Onki
 

onki

User
Hallo,

die Sachen sind soweit angekommen und ich hab die Teensy Erweiterung in meine IDE installiert. Der Blink Test geht prima, nur bekomme ich den Beispielcode nicht kompiliert:
Arduino: 1.6.7 (Windows 10), TD: 1.27, Board: "Teensy 3.2 / 3.1, Serial, 72 MHz optimized, German"

Build-Optionen wurden verändert, alles wird neu kompiliert
C:\Users\onki\Documents\Arduino\libraries\JetiExSensor\src\JetiExSerial.cpp: In member function 'virtual void JetiExTeensySerial::Init()':
C:\Users\onki\Documents\Arduino\libraries\JetiExSensor\src\JetiExSerial.cpp:49:28: error: 'SERIAL_9O1' was not declared in this scope
HWSERIAL.begin( 9600, SERIAL_9O1 );
^
exit status 1
Fehler beim Kompilieren.

Hat jemand einen Lösungsansatz?

Die INO-Datei ist ja quasi nur das "Frontend". Die Datensammlung geht ja in den CPP-Dateien von Statten, wenn ich das miot meinen geringen Programmierkenntnissen so peile.
Mein Sensor liefert mir eine Spannung (1/10) für die Spannung des Fahrakku und eine Spannung für den Strom (ca. 1/20 V bei 1A). Das müsste ich in der Beispieldatei ja nur anpassen.

Gruß uind Dank vorab
Onki
 

Sepp62

User
Es ist eine Readme-Datei im Archiv (ZIP) der Library enthalten, die anzeigt, was für Teensy in den "Core"-Quellen getan werden muss:

Changes in Teensy libraries
===========================

Activate 9 Bit UART support
---------------------------
...\Arduino\hardware\teensy\avr\cores\teensy3\HardwareSerial.h

// uncomment to enable 9 bit formats

#define SERIAL_9BIT_SUPPORT
 

Sepp62

User
Generell zum empfohlenen Aufbau eines Sensor-Projekts:

- Die JetiEX-Library sollte nicht "sensorspezifisch" verändert werden. Im Moment muss man (bei Teensy) dort noch die serielle Schnittstelle ändern, wenn man mit "Serial2" nicht leben will. Auch Device-ID und Manufacturer-ID stehen heute hart in der Library (was aber bei einem "Erstlingsprojekt" auch funktioniert). Ich werde die Library an dieser Stelle noch erweitern.

- Die INO-Datei ist das "Herz" des Ganzen. Wenn man nur einfache Sensoren hat (wie z.B. für Spannungsmessung) kann man den kompletten Code dort verwalten. Im beigefügten Beispiel sieht man, wie der DemoSensor seine Daten in die JetiEx-Library einfügt. Statt die Daten aus dem Demo-Sensor zu holen, trägt man einfach die Messwert-Variablen der eigenen Sensoren ein (der Datentyp ist meist "long").

- Wenn die Sensoren dann etwas komplexer werden oder wenn man Libraries verwendet (z.B. TinyGPS), lagert man den Code in eigene Funktionen oder besser C++-Klassen aus und programmiert (wie der DemoSensor) eine "Get"-Funktion, die den aktuellen Messwert zurückliefert. Die Arduino-IDE macht es einem jedoch nicht gerade einfach, mit mehreren Klassen zu arbeiten. Wer damit nicht vertraut ist, haut seinen eigenen Code einfach in seine .INO-Datei rein.

Ich hoffe, das hilft weiter.

Grüße
Bernd
 

onki

User
Hallo,

so der Beispielcode wird kompiliert und übertragen.
Am Teensy muss ich dann ja noch RX und TX mit Diode brücken und Signalleitung an RX (wie beim Jeti Programmieradapter).
Teste ich dann in Kürze aus.
Update: Der Beispielcode läuft und ich seh das Menü auf der Jetibox am Schülersender (mc22s mit Modul und Box).
Nächster Schritt wird sein, den Wert vom Sensor für Spannung und Stom von A0 (Spg) bzw. A1 (Strom) vom Teensy auszulesen, mit Korrekturfaktor multiplizieren und an die Box zu senden.
Ich denke das WE bietet sich dafür an.

Gruß und Danke für die Hilfe einstweilen

Onki
 

Sepp62

User
Hallo Onki,

die Brücke zwischen RX und TX brauchst du nur, wenn Du Tastendrücke für das "Jeti-Box-Menü" empfangen willst. Du kannst eine Diode nehmen oder einen "Angstwiderstand" von ca. 100 Ohm (das mach ich immer).

Zudem musst Du dann noch den unteren Teil aus der TeensyReadme.txt-Datei berücksichtigen.

Wie ich oben schon mal geschrieben habe: Das mit den Tasten funktioniert nicht 100% bei mir.

Ansonsten: Nur Tx verbinden und auf die Tasten (=Menü) verzichten.

Grüße
Bernd
 

Eckehard

User
"Jeti Expander" Sketch in Sensor integrieren....

"Jeti Expander" Sketch in Sensor integrieren....

Hallo Zusammen,

so mein Teensy3.2 / SD Card Adapter ist auch gekommen...
Da ich außerdem noch einen Unisens besitze, stellt sich die Frage nach der Integration eines Expanders in das EigenbauSensorProjekt....
Neben dem eigentlioch Sensor Code mit Telemetie sollte ein Teensy3.2 es auch noch schaffen die Funktion eines Expanders zu erledigen. Den Unisens würde man dann an den EigentbauSensor_mit_Expander_Funktionalität anschließen...

Gibt es dazu vielleicht schon Pojekte?

Grüße
Eckehard
 

Sepp62

User
Ich kenne kein Projekt dazu.

So ein Expander muss wohl Folgendes tun:

1. "Sensorpakete" von verschiedenen Sensoren empfangen
2. Pakete in einer Warteschlange puffern und sie an den Empfänger weiterreichen
3. Wenn mehr Pakete kommen, als er loswerden kann --> Bestimmte Pakete wegwerfen

Seit es die REX-Empfänger gibt, dürfte der Bedarf an Expandern nur noch für alte Empfänger bestehen.

Grüße
Bernd
 
Jeti Sensor + NFC

Jeti Sensor + NFC

Liebe Jeti-Sensor-Experten,
ich habe endlich wieder etwas Zeit, an meinem Akku-Pack-Sensoren weiterzuprogrammieren.
Die Idee ist, dass ich NFC-Tags auf meine Akkus klebe, die ausgelesen werden, sobald das Pack im Flieger montiert wird.
Die ID des Akkus (momentan: Kapazität.Nummer - also z.B. 4500.09) wird aufgezeichnet und nach jedem Flug wird der "Betriebszähler" des Akkus um ein erhöht (da der Wert auf den Tag geschrieben). Damit erspare ich mir die doofen Strichlisten auf den Akkus und kann nachträglich für jedes Pack auswerten, wie viel Kapazität tatsächlich entnommen wurde.
Zusätzlich zur Akkuidentifikation möchte ich noch die Temperatur der Akkus (F3A Maschine mit 2 Packs) und des Motors erfassen.

Die Komponenten sind:
NFC: PN532 Breakout board: http://www.play-zone.ch/de/dk-pn532-nfc-rfid-mini-breakout-board.html
IR Temperaturmesser: http://www.play-zone.ch/de/adafruit-kontaktloses-temperatur-sensor-breakout-tmp007.html
Motortemperatur: DS18B20 digital thermometer

Auf einer Steckplatine kann der Teensy mit den Sensoren schon mal reden.
Der Demosensor funktioniert auch schon.

Allerdings habe ich mit dem Arduino noch nie so "richtig" mit Klassen und Libraries programmiert und einige Teile des Sensorcodes hab ich auch nicht wirklich verstanden :confused:

Ich bräuchte daher ein wenig Nachhilfeunterricht...

In Demosensor.ccp:

Was passiert hier genau und was macht vor allem die for-Schleife mit "memset" ?
Code:
DemoSensor::DemoSensor() : volt( 81 ), tiVolt( 0 ), alt( 250 ), tiAlt( 0 ), temp( 300 ), tiTemp( 0 ),
                           climb( 153 ), tiClimb( 0 ), fuel( 80 ), tiFuel( 0 ), rpm( 0 ), tiRpm( 0 ) 
{
  for( int i = 1; i <= NVALS; i++ )
    vals[i-1] = 10*i;
  memset( tiVals, 0, sizeof( tiVals) );  
}

Die IR Sensoren liefern nur alle 4 Sekunden einen neuen Wert.

Würde da so etwas funktionieren?

Code:
long DemoSensor::GetTemp()
{
  if( ( tiTemp + 4000 ) <= millis() )
  {
    tiTemp = millis();    // ti = Timestamp ?
    temp = GetIRSensorTemp();
  }
  return temp;
}

Bleibt der Wert von temp bei jedem Funktionsaufruf erhalten?
Die Hauptschleife läuft ja mit der vollen Geschwindigkeit, aber der Temp Sensor liefert nur alle 4 Sekunden neue Werte.

Vielen Dank für Eure Hilfe
Wolfgang
 

Sepp62

User
Hallo Wolfgang,

du hast den Konstruktor des Demosensors Klasse zitiert, in der die Membervariablen initialisiert werden. Der memset-Aufruf schreibt "0" in die Timerwerte. Du kannst genauso alle Membervariablen im Konstruktor einzeln hinschreiben per "=" mit einem Wert versehen. Die for-Schleife verpasst allen Variablen einen andern Startwert. Der memset-Befehl ist außerhalb der Schleife, da bei C/C++ ohne geschweifte Klammer nur eine Zeile in einen Block kommt.

Deine GetTemp-Funktion sieht so ganz gut aus (sofern tiTemp und temp als Membervariablen der Klasse deklariert sind).

Du kannst es auch so machen:

long DemoSensor::GetTemp()
{
if( ( tiTemp + 4000 ) <= millis() )
{
tiTemp = millis(); // ti = Timestamp ?
return GetIRSensorTemp();
}
return -1;
}

Wenn ein Sensor ein Wert von -1 hat, überträgt ihn die Library nicht, d.h. Du sparst Dir den "Sendeslot" für diesen Wert und kannst in der Zeit andere Werte übertragen.

Grüße
Bernd
 
Hallo Bernd,
die DS18S20 Temp Sensoren funktionieren jetzt mal mit der DallasTemperature Library:

Code:
[B]Sensors.h:[/B]

#include <DallasTemperature.h>

class Sensor
{
public:
  Sensor();

  long GetTempDS1();
  
private:
  OneWire oneWire;
  DallasTemperature DSsensors;
....

[B]Sensors.ccp:[/B]

Sensor::Sensor() : oneWire(ONE_WIRE_BUS), DSsensors(&oneWire), tempIR1(1), tempIR2(2),tempDS1(3)  {

  timeStampIRsensor1 = 0;
  timeStampIRsensor2 = 0;
  timeStampDSsensor1 = 0;
  
  // Dallas temperature sensors connected to OneWire Bus
  DeviceAddress tempDeviceAddress;
  DSsensors.begin();
  DSsensors.getAddress(tempDeviceAddress, 0);
  DSsensors.setResolution(tempDeviceAddress, 10);
  DSsensors.setWaitForConversion(false);
  DSsensors.requestTemperatures();

  // Texas Instruments TMP007 IR Sensor connected to the I2C bus

}

...

long Sensor::GetTempDS1()
{
  if ((timeStampDSsensor1 + delayDSsensor) <= millis() )
  {
    timeStampDSsensor1 = millis();
    DSsensors.requestTemperatures(); 
    tempDS1 = (DSsensors.getTempCByIndex(0));
  } 
  return tempDS1;
}

die Library für den IR Sensor wehrt sich (noch) ...

https://github.com/adafruit/Adafruit_TMP007_Library

Das Beispiel funktionert, aber den Einbau in die Sensor Klasse hab ich noch nicht geschafft...

Gruss & Dank,
Wolfgang
 

Sepp62

User
Hallo Wolfgang,

lass' die Sensorklasse doch einfach weg. Die ist wirklich nur dafür gemacht, dass sich "out of the box" Zahlen auf dem Sender-Display ändern und der essentielle Teil des Codes ("SetSensorValue") lesbar bleibt. Sie enthält zuviel Kram, den man für andere Zecke nicht braucht.

Einfacher ist es, wenn Du den Code so baust, dass es eine "Get"-Funktion oder eine Variable mit dem aktuellen Sensorwert gibt.

Die Funktion oder die Variable setzt Du einfach in der Hautptschleife in die "SetSensorValue"-Funktion ein.

Also so (hier mit Variable, die natürlich an anderer Stelle deklariert und befüllt werden muss): jetiEx.SetSensorValue( ID_TEMP, myTempSensorValue );


Grüße
Bernd
 

Sepp62

User
Noch ein genereller Hinweis zur Initialisierung von Klassen/Variablen:

Wenn man Klassen statisch verwendet, d.h. wenn sie außerhalb der setup() oder loop()-Funktion (oder untergeordneten Funktionen/Methoden) stehen, ist die Reihenfolge der Konstruktor-Aufrufe nicht definiert. Bei Deinem Dallas-Sensor ist alles in Ordnung, da die Sensor-Klasse von der Dallas-Sensor-Klasse abgeleitet ist.

Wäre der Dallas-Sensor eine eigene Klasse und er würde "neben" der Sensor-Klasse stehen, wäre es nicht klar, welcher Konstruktor zuerst aufgerufen wird. Dies ist generell zu beachten, wenn Libraries/Klassen verwendet werden. Ein Heilmittel ist, dass man die Initialisierung nicht in den Konstruktor steckt, sondern eine eigene "Init"-Funktion schreibt, die dann aus setup() heraus in der gewünschten Reihenfolge aufgerufen wird.

Grüße
Bernd
 
Hallo Bernd,
ein einfaches ".ino-only" Beispiel für Deine Library wäre echt super. Ich denke, die Mehrheit der Arduinoprogrammierer hätte grosse Freude daran :D

Viele Grüsse & herzlichen Dank für Deine Hilfe
Wolfgang
 

Sepp62

User
Ich habe hier nochmals alles weggenommen, was man wegnehmen kann.

Die Werte werden konstant belegt, die Funktion GetSensorValues() muss also so modifiziert werden, dass die eigenen Sensorwerte in die Variablen geschrieben werden. Die Nachkommastellen werden durch das Precision-Attribut in der Sensortabelle bestimmt.

Code:
/* 
  Jeti EX Sensor Simple Demo
**************************************************************/

#include "JetiExProtocol.h"

JetiExProtocol jetiEx;

enum
{
  ID_VOLTAGE = 1,
  ID_ALTITUDE,
  ID_TEMP,
};

long myVoltage = 0;
long myAltitude = 0;
long myTemp = 0; 

JETISENSOR_PTR sensors[] = 
{
  //              id             name        unit         data type             precision = 0 --> 0, precision = 1 --> 0.0, precision = 2 --> 0.00
  new JetiSensor( ID_VOLTAGE,    "Voltage",  "V",         JetiSensor::TYPE_14b, 1 ),
  new JetiSensor( ID_ALTITUDE,   "Altitude", "m",         JetiSensor::TYPE_14b, 0 ),
  new JetiSensor( ID_TEMP,       "Temp",     "\xB0\x43",  JetiSensor::TYPE_14b, 1 ), // �C
  0 // end of array
};

void setup()
{
  jetiEx.Start( "MySensor", sensors );
}

void loop()
{
  GetSensorValues();
  
  jetiEx.SetSensorValue( ID_VOLTAGE,  myVoltage );
  jetiEx.SetSensorValue( ID_ALTITUDE, myAltitude );
  jetiEx.SetSensorValue( ID_TEMP,     myTemp ); 

  jetiEx.DoJetiSend(); 
}

void GetSensorValues()
{
   myVoltage = 74;    // 7.4V 
   myAltitude = 120;  // 120 m
   myTemp = 315; 	  // 31.5 Grad Celsius	
}
 
Hallo Bernd,
SUPER :D:D:D , vielen Dank !

Das ist für einfache Anwendungen und für Entwickler, die nicht so mit der objektorientierte Programmierung a la Arduino vertraut sind, ein grosser Segen !!!

Herzliche Grüsse,
Wolfgang
 

Sepp62

User
Es gibt eine neue Version der Library (V0.96) mit ein paar kleinen Verbesserungen:

1. Für den Teensy kann man optional die ComPort-Nummer (Serial1...3) angeben. So muss man bei unterschiedlichen Verdrahtungen nicht mehr die Library anpassen.

2. Auch die DeviceID des Sensors kann man nun "von außen" setzen. Hängt man mehr als einen Sensor (im Sinne eines Arduino oder Teensy) an einen Jeti-Empfänger, kann man nun unterschiedliche IDs vergeben. Verwendet man eine Droidbox, so ist es sinnvoll pro Sensor und Modell eine unterschiedliche ID zu vergeben.

3. In den Beispielen findet sich ein auf das Allerwesentlichste reduzierter Sketch.
 

onki

User
Hallo,

das miese Wetter heute und die Tatsache, das ich zu meiner einzigen Aufgabe derzeit (Rumpf vorschleifen zum Lackieren) keine Lust hatte:rolleyes:, hat mich dazu bewogen, mal etwas mit dem Teensy und dem Stromsensor zu experimentieren.
Ich verwende als Stromsensor dieses Teil hier:
http://www.amazon.de/gp/product/B011KV08V8?psc=1&redirect=true&ref_=oh_aui_detailpage_o02_s00

Den Spannungseingang hab ich an A0, den Stromeingang an A1 angeschlossen.
Nach etwas Experimentieren mit den Multiplikatoren hab ich nun diese erste Lösung zur Messwerterfassung mit Ausgabe an die ser. Konsole:

Code:
void setup()
{                
  Serial.begin(38400);
}

float vcode;
float acode;
float Volt;
float Strom;
float Kapazitaet;

void loop()                     
{
  analogReadRes(12);
  vcode = analogRead(A0);
  acode = analogRead(A1);
  Volt = (vcode / 123);
  Strom = (acode / 67.5);
  Kapazitaet = Kapazitaet + (Strom / 14400);
  Serial.print(" Spannung: ");
  Serial.print(Volt);
  Serial.print(" Volt, ");
  Serial.print(" Strom: ");
  Serial.print(Strom);
  Serial.print(" Ampere ;");
  Serial.print(" verbrauchte Kapazitaet: ");
  Serial.print(Kapazitaet);
  Serial.print(" Ah ");
  Serial.println();
  
  
  delay(250);
}

Das funktioniert soweit, zumindest sind die ausgegebenen Messwerte mit den Messwerten am Multimeter vergleichbar.
Nächster Schritt ist nun den zuvor geposteten. Jeti-Beispielcode zum laufen zu bekommen und statt der Festwerte meine Messwerterfassung einzubauen.
Ich hoffe das bekomme ich noch hin.
Ich verzweifel noch an der Syntax. Ich werd das mit dem Semikolon am Zeilenende nie kapieren:rolleyes:.

Gruß
Onki
 
Ansicht hell / dunkel umschalten
Oben Unten