Posts mit dem Label Frsky werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Frsky werden angezeigt. Alle Posts anzeigen

Montag, 18. April 2022

Crawler - LUA Skript für Lipo Sensor


Wie voll ein Lipo Akku ist, kann an der Spannung der einzelnen Zelle oder an der Gesamtspannung erkannt werden. Der Umstand ist immer, dass wir in unserem Kopf umrechnen, wie viel uns noch vom Akku an Kapazität bleibt.

Bei unseren Geräten wie dem Smartphone oder Tablet gibt es eine Prozentanzeige und dieses will ich hier nun umsetzen.

 

Benötigt

  • Frsky X-Lite oder Fernsteuerung mit OpenTX
  • Frsky Lipo Sensor

 

Ziel

Der Akkustand soll in Prozent ausgegeben und graphisch mit einem Ladebalken angezeigt werden. Wenn die verbrauchbare Akkuladung sich dem Ende nährt, soll außerdem eine Warnung ausgegeben werden.

 

Auslesen der Telemetrie

Anders als bei dem Arduino Projekt wird das Ergebnis nicht als einzelner Wert ausgegeben. Genau genommen ist der verwendete Typ eine Tabelle, das wie ein Dictionary verwendet wird. Mit einem Schleifendurchgang kann der Index und der Wert gelesen werden.

 local mCellId = nil  
 local mField = nil  
 -- read from telemetry pool by name  
 local function getTelemetryId(name)  
   mField = getFieldInfo(name)  
   if mField then  
    return mField.id  
   else  
    return -1  
   end  
 end  
 local function init()  
      mCellId = getTelemetryId("Cels")  
 end  

 

Spannungen umrechnen

Im Grunde ist es keine große Sache, die Spannung in Prozent umzurechnen. Wir wissen, dass eine Lipo-Zelle eine Lagerspannung von 3,7 Volt hat und bei ca. 4.2 Volt voll ist. Praktisch darf der Akku nur 0,5V an Spannung verlieren, um dann als verbraucht zu gelten. Einige haben 3,6V als Grenze, aber weiter runter sollte man hier nicht gehen, wenn der Akku keinen Schaden nehmen soll.

 

Gesamtspannung = 8,4 V

Lagerspannung = 7,4 V

Verbrauchbare Differenzspannung = Gesamtspannung - Lagerspannung

1,0 V = 8,4 V - 7,4 V

 

Messspannung = 8,1 V

Rest Differenzspannung = Messspannung - Lagerspannung

0,7 = 8,1 V - 7,4 V

 

Kapazitätswert in Prozent = Rest Differenzspannung / Verbrauchbare Differenzspannung * 100

70 % = 0,7 / 1,0 * 100

 

Genauer wird dies, wenn die Spannungen der einzelnen Zellen berechnet werden. Zudem bleibt die Möglichkeit die Zellen einzeln zu betrachten, um bei Bedarf den nicht-balancierten Zustand zu erkennen.

 -- Lipo total  
 local mLipoTotalFull = 8.4  
 local mLipoTolalLow = 7.4  
 -- lipo cell  
 local mLipoCellVoltage = 4.2  
 local mLipoCellVoltageLow = 3.7  
 -- results  
 local mTotalResult = 0  
 local mCellResult1 = 0  
 local mCellResult2 = 0  
 local mTotalCellsResult = 0  
 local mCells = 0  
 local mCell1 = 0  
 local mCell2 = 0  
 local function calculateCellsState()  
      if mCellId == -1 then  
           return 0  
      end       
      mCells = 0  
      local cells = getValue(mCellId)  
      if(type(cells) == "table") then  
           for index, voltage in ipairs(cells) do  
                mCells = mCells + voltage  
                if index == 1 then  
                     mCell1 = voltage  
                end  
                if index == 2 then  
                     mCell2 = voltage  
                end  
           end  
      end  
      -- total voltage   
      local totalFull = mLipoTotalFull - mLipoTolalLow  
      local totalState = mCells - mLipoTolalLow  
      mTotalResult = math.ceil(totalState / totalFull * 100)  
      -- cell  
      local cellFull = mLipoCellVoltage - mLipoCellVoltageLow  
      -- cell 1 voltage  
      local cellState1 = mCell1 - mLipoCellVoltageLow  
      mCellResult1 = cellState1 / cellFull * 100  
      -- cell 2 voltage  
      local cellState2 = mCell2 - mLipoCellVoltageLow  
      mCellResult2 = cellState2 / cellFull * 100  
      -- total result  
      mTotalCellsResult = math.ceil((mCellResult1 + mCellResult2) / 2.0)  
      return 1  
 end  

 

Werte und Balken als Zustandsanzeige

Anstatt nur Zahlen zu lesen, kann ein Balken gezeichnet werden. Damit man sehen kann, wo die 100 % liegen, wird zusätzlich ein Rahmen angelegt.
Anders gesagt wird es wie ein Ladebalken angezeigt, der als haptische Füllstandsanzeige verwendet werden soll.

 local function drawTextAndBars()  
      -- lipo accu state calculate to percentage  
      -- title  
      lcd.drawText(0, 0, "Accu State", MIDSIZE)  
      -- total lipo voltage  
      lcd.drawText(2, 12, "Lipo Accu:", SMLSIZE)  
      lcd.drawText(46, 12, mTotalResult.."%", SMLSIZE)  
      -- sum of cells lipo voltage  
      lcd.drawText(64, 12, "By Cells", SMLSIZE)  
      lcd.drawText(102, 12, mTotalCellsResult.."%", SMLSIZE)  
      -- Cell voltage  
      lcd.drawText(2, 20, string.format("%.2f", mCells).."V", SMLSIZE)  
      lcd.drawText(32, 20, string.format("%.2f", mCell1).."V", SMLSIZE)  
      lcd.drawText(62, 20, string.format("%.2f", mCell2).."V", SMLSIZE)  
      -- screensize  
      -- 128 x 64  
      -- cells  
      lcd.drawRectangle(5, 28, 118, 5)  
      lcd.drawLine(7, 30, math.ceil(mTotalResult * 1.18), 30, SOLID, FORCE)  
      -- cell 1  
      lcd.drawRectangle(5, 34, 118, 5, SOLID)  
      lcd.drawLine(7, 36, math.ceil(mCellResult1 * 1.18), 36, SOLID, FORCE)  
      -- cell 2  
      lcd.drawRectangle(5, 41, 118, 5, SOLID)  
      lcd.drawLine(7, 43, math.ceil(mCellResult2 * 1.18), 43, SOLID, FORCE)  
      return 0  
 end

 

Alternativ kann die Füllstandsanzeige mit lcd.drawGauge(x1, y1, w, h, maxfill) gezeichnet werden. Jedoch habe ich noch nicht die Option gefunden, eine vertikale Darstellung zu zeichnen. Ist deshalb in dem von mir hier erstellten Skript noch nicht der Fall.

 

Skript ausführen

Das Skript muss in den Ordner SCRIPTS/TELEMETRY und die Bezeichnung des Scripts darf hier nicht mehr als 5 Zeichen lang sein, da sonst das Skript nicht für das Display ausgewählt werden kann.

Nun habe ich da noch ein Problem mit der Darstellung auf dem Bildschirm. Obwohl das Skript im Menü eingebunden wurde, wird mir auf der Telemetrie Ansicht gemeldet, dass keine Telemetrie Screens verfügbar sei.


 

Am Ende offen

Den Fehler konnte ich noch nicht herausfinden und starte daher alternativ das Skript direkt aus dem Ordner heraus. Eine weitere Störung tritt auf, wenn man den Crawler ausschaltet, dann scheint die Fernsteuerung im Zustand des Betriebs zu springen und hier kann man nur noch ausschalten.

Aktuell ist die Darstellung nur sehr einfach und nicht sehr stylisch, weshalb ich ein Screen zusätzlich designe.

 

Handling Lipo Sensor Data - OpenTX 2.3 Lua Reference Guide (open-tx.org)

OpenTX 2.2 Lua Reference Guide (schorse-video.de)

Taranis-XLite-Q7-Lua-Dashboard/farl.lua at master · AndrewFarley/Taranis-XLite-Q7-Lua-Dashboard (github.com)

 

Sonntag, 12. September 2021

Sensor Daten über Smart Port versenden mit dem Arduino


Der Empfänger, den ich für meinen FPV RC Crawler verwende, hat einen Smartport an dem z.B. Sensoren angeschlossen werden können. Die Anzahl der verfügbaren Sensoren von Frsky ist übersichtlich, aber speziell für meinen Bedarf war keiner dabei. Wie gut, dass hier bereits eine Lösung mit dem Arduino vorhanden ist und ich dazu auf den Arduino Webseite den Eintrag "S.Port sensor library for FrSky" gefunden habe.

Verwendet

  • Arduino Mini
  • Temperatur Sensor
  • Diode
  • FrSky Empfänger mit Smartport
  • Fernsteuerung mit OpenTX

 

Ziel

Die erfasste Temperatur des Sensors soll auf der Fernsteuerung umgerechnet und auf dem Display angezeigt werden.

 

Funktioniert das wirklich?

Wie bei jeder neuen Sache, prüfe ich mit wenig Aufwand, ob das Zielvorhaben erreichbar ist. Praktisch ein PoC. Im Grunde formuliere ich meine Blogeinträge anfangs als "Proof of Concept", bevor daraus ein Beispiel wird und das gilt auch wieder für diesen Eintrag. Nur diesmal beschreibe ich das Testen mit.

In den Sourcen zur Bibliothek für den SmartPort, sind, wie auch bei den anderen Beispiele Codes vorhanden. Für mich ist der ein feststehender Wert zu wenig und deshalb ändere ich den zu sendenden Wert in der Loop Methode.

 #include <SPort.h>  
 SPortHub hub(0x12, 3);  
 CustomSPortSensor sensor(getSensorData);   
 int mSendingValue = 0;  
 int mCurrentMillis;  
 void setup() {  
  hub.registerSensor(sensor);  
  hub.begin();                
 }  
 void loop() {  
  hub.handle();   
  int current = millis();  
  if(current - mCurrentMillis < 100) {  
    return;  
  }  
  mCurrentMillis = current;  
  mSendingValue++;    
 }  
 sportData getSensorData(CustomSPortSensor* sensor) {  
  sportData data;   
  data.applicationId = 0x5900;        
  data.value = mSendingValue;  
  return data;  
 }  

Ist der Code auf dem Arduino geschrieben, muss eine Verkabelung zum Smartport hergestellt werden. Hierfür soll die Diode verwendet werden, aber vielleicht sollte ich die Beschreibung nochmal durchgehen, wofür die Diode gut ist. (Später habe ich die Diode doch nicht verwendet)

 

 

Sensor einbinden

Die Fernsteuerung mit dem OpenTX Betriebssystem kann nun eingeschaltet werden. Im Menü TELEMETRY (Abschnitt 11 auf der Xlite pro) für Sensoren, kann nun die Suche gestartet werden. Wenn der Arduino mit dem Code als Sensor funktioniert, sollte schon nach wenigen Sekunden der Sensor in OpenTX  gefunden werden.

 


 

Display Wiedergabe

Für den Bildschirm können mehrere Seiten eingerichtet werden, auf denen die Sensor Ergebnisse ausgegeben werden. Dazu muss über das Menü DISPLAY (Abschnitt 12 auf der Xlite pro) der Screen auf "Nums" eingestellt werden und dann muss darunter ein Feld mit "---" auf den neuen Sensor eingestellt werden.

 


Ist die Fernsteuerung auf den Hauptbildschirm geschaltet, muss man in meinem Fall den Stick für eine Sekunde nach unten ziehen, damit das eingerichtete DISPLAY gezeigt wird.

 

 

Echten Sensor anschließen

Das war schon alles, um sich an den SmartPort ran zuhängen. Natürlich macht der Anschluss nur Sinn mit einem echten Sensor.

Für dieses Beispiel verwende ich einen Temperatur Sensor, der über die I²C Schnittstelle angesprochen wird. An der Stelle hätte ich auch einen interessanteren Sensor nehmen können, dennoch soll das Beispiel schlicht bleiben. Und der Code für den Temperatur Sensor lässt sich in wenigen Zeilen eingeben.

 #include <SPort.h>  
 #include <Wire.h>  
 SPortHub hub(0x12, 3);  
 CustomSPortSensor sensor(getSensorData);  
 #define TMP102_ADD 0x48  
 void setup() {  
  Wire.begin();  
  hub.registerSensor(sensor);  
  hub.begin();                
 }  
 void loop() {  
  hub.handle();  
 }  
 sportData getSensorData(CustomSPortSensor* sensor) {  
  sportData data;   
  data.applicationId = 0x5900;  
  int raw = getTemperatureValue();  
  float result = raw * 0.0625;  
  data.value = raw;  
  return data;  
 }  
 int getTemperatureValue() {  
  Wire.beginTransmission(TMP102_ADD);  
  Wire.write(0x00);  
  delay(100);  
  Wire.endTransmission();  
  Wire.requestFrom(TMP102_ADD, 2);  
  while(Wire.available() < 2) { }  
  return ((Wire.read() << 8) | Wire.read()) >> 4;  
 } 


Wert-Ausgabe nur Ganzzahl

Nun haben wir einen Rohwert, der einem so nichts sagt. Eigentlich könnte der Wert am Arduino umgerechnet werden, aber ich hatte aus den Source Code gelesen, dass nur Ganzzahlen übermittelt werden.

 

LUA Script

Die Antwort für das Umrechnen der Ganzzahlen in einen Wert mit Nachkommastellen ist die Unterstützung von Lua Script auf OpenTX. Statt den Rohwert auf dem Display auszugeben, kann dieser durch einen Script umgerechnet werden und dann auf dem Display als lesbaren Wert ausgegeben werden.

Aber kommen wir zunächst zu dem Teil, was eigentlich ein LUA Script haben muss. Im Wesentlichen hilft hier die Dokumentation Telemetry Scripts.

 

Vorraussetzung

  • Das Lua Script muss auf der SD Karte in das Unterverzeichnis "SCRIPTS\TELEMETRY\".
  • Das Script muss die Namenserweiterung ".lua" haben.
  • Der Name des Lua Script darf nicht länger als sechs Zeichen lang sein, ansonsten wird das Script in der DISPLAY Einrichtung nicht angezeigt. Die Namenserweiterung ".lua" wird an der Stelle nicht mit gezählt.

Im Grunde sollte das Script mindestens die 'local function run' enthalten. Die "Init" Funktion ist optional und eigentlich sollte das auch ohne eine Background-Funktion funktionieren. Wichtig ist, dass die Methode am Ende einen Return-Wert ausgibt.

 local function run_func(event)  
      lcd.clear()  
      local receivedValue = getValue('TEMP')  
      local toDecValue = receivedValue * 0.0625;  
      lcd.drawText(10, 10, "Temperature", MIDSIZE)  
      lcd.drawText(10, 25, string.format("%.2f", toDecValue), MIDSIZE)  
      return 0  
 end  
 return { run=run_func }   


Einbinden des Scripts

Nun kann das Script auf die SD Karte und in die Fernsteuerung mit OpenTX gesteckt werden. Nach dem Einschalten kann über das Menü DISPLAY (auf der Xlite Pro befindet sich dieses in Abschnitt 12), auf Screen 1 von Nums gewechselt werden. Rechts von der Script Einstellung, kann man nun das Script myVal.lua auswählen.


 

Anschließen geht’s zurück auf den Hauptscreen. Mit dem 1 bis 2 Sek nach unten gezogenen Stick kann man vom Hauptdisplay auf den gescripteten Bildschirm (Display) wechseln. Fertig!

 

 

Schlusswort

Irgendwie habe ich im Internet keine Beschreibung gefunden, die in wenigen Schritten aufzeigt, was zu tun ist, um einen Wert auf dem Display anzuzeigen. Am Ende ist der Aufbau sehr übersichtlich, aber die kleinen Details, die man wissen muss, halten einen auf.

Natürlich werde ich an den Sensor mehr als nur ein Temperatur Sensor anschließen, schließlich kann man die Lage noch ermitteln und Abstände messen.

Was ich vermisse, ist ein Designer für die Bildschirm Ausgabe. Entweder habe ich den nicht gefunden oder für diesen Zweck gibt’s einfach keinen. Dabei wäre ein Designer nicht schwierig, aber es wäre zeitaufwendig diesen zu entwickeln (womit ich mir praktisch die Frage selbst beantworte).

 

Eintrag zu meinem Repository:

GitHub - ExampleFrskySensor

 

Sourcen

Ameisen Simulation und andere Dinge

Wer lange sich schon mit C# beschäftig, hat sicherlich schon mal was von AntMe gelesen oder gehört. Diese Idee hatte ich aufgegriffen und mi...