Jump to content

Meinolf Höhler

admGlobal
  • Content Count

    1,176
  • Joined

  • Last visited

About Meinolf Höhler

  • Rank
    Administrator

Freiwillige Angaben

  • Wohnort
    Düsseldorf

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Ich kann Achims Aussage aus eigener Erfahrung bestätigen. #1&2 hab ich genau so falsch gemacht und mich gewundert, warum ich die Litze nicht angelötet bekomme.
  2. So weiter im Tex...Programm. Das Programm im Arduino ist schwieriger zu erklären, daher versuche ich die wichtigsten Punkte abzudecken. Ich hoffe die Kommentierung des Quelltexts ist ausreichend. // Sensor definition to initialize telemetry FrSkySportSensorAss ass(FrSkySportSensor::ID14); //create a sensor Auch wenn das Programm funktioniert, ohne, dass der Sender in dem Arduino einen Sensor erkennt, muss trotzdem irgend einer der Sensoren instantiiert werden, damit die Telemetriebibliothek compiliert werden kann. Ich habe den Erstbesten genommen, und das ist der AirSpeedSensor ASS. // configure telemetry serial port telemetry.begin(FrSkySportSingleWireSerial::SOFT_SERIAL_PIN_4, &ass); Das Telemetrieobjekt bekommt zwei Parameter übergeben. Der Erste ist der Pin, an dem der S.Port angeschlossen ist. Hier hat sich anscheinend Pin 4 als am besten geeignet (so ist es in dem Beispiel von Pawelsky beschrieben). Der zweite Parameter ist der „Pseudo-Sensor“, der zu Anfang instantiiert wurde. if (telemetry.available && ((uiValue[0] != telemetry.aUiRxValue[0]) || (uiValue[1] != telemetry.aUiRxValue[1]) || (uiValue[2] != telemetry.aUiRxValue[2]) || (uiValue[3] != telemetry.aUiRxValue[3]))) { uiValue[0] = telemetry.aUiRxValue[0]; uiValue[1] = telemetry.aUiRxValue[1]; uiValue[2] = telemetry.aUiRxValue[2]; uiValue[3] = telemetry.aUiRxValue[3]; telemetry.available = false; bValuesUpdated = true; } Weiter oben wurde ja schon das available Flag beschrieben, und das kommt hier nun zu seinem Einsatz. Nur wenn Daten verfügbar sind, und sich eines der 4 Byte von den vorher empfangenen unterscheidet, genau dann werden die neuen Daten in den eigenen Puffer übernommen, und die Auswertung mit bValuesUpdated = true; freigegeben. Wichtig für die nachfolgende Auswertung ist nun die Beziehung zwischen den Empfangenen Bytes und den LEDs an den PWM Modulen. Für diese Beziehung habe ich eine Tabelle in LibreOffice gebaut, wo in den Spalten die 32 möglichen Schaltwerte stehen, und in den Zeilen die 32 Kanäle der PWM Module. Nebenbei, die LED sind gleichmäßig auf die PWM Module verteilt, damit nicht eines zu viel Last auf einmal hat. Wichtig ist nun, dass jedes der PWM Module einen Zwischenpuffer in Form eines Array aus 16 Booleanwerten bekommen hat, welcher den Zustand jeder LED speichert. bool module1onOff[16]; bool module2onOff[16]; Kommt z.B. über den Empfänger das Signal für die Beleuchtung „in Fahrt“ (Byte 1 = 0x01), sollen die folgenden LED eingeschaltet sein: - Topplicht (Modul 2, Kanal 0) - Hecklicht (Modul 1, Kanal 0) - Backbordlaterne (Modul 2, Kanal 2) - Steuerbord (Modul 1, Kanal 2) Um zu ermitteln, ob 0x01 in dem Signal des Empfängers vorhanden ist, anders ausgedrückt der gesendete Wert gerade oder ungerade ist, wird die Bitmaske 0x01 (binär 00000001) mit einem bitweisen UND auf den Puffer angewendet. Ist der Wert ungleich 0, ist der gewünschte Schalter an. Für die anderen Schaltzustände ist die Bitmaske entsprechend 0x02, 0x04, 0x08, 0x10 etc. //fahrt if ((uiValue[0] & 0x01) != 0) { module1onOff[0] = true; //heck module1onOff[2] = true; //navSB module2onOff[0] = true; //topp module2onOff[2] = true; //navBB } In den Arrays werden dann Wert 0 und 2 jeweils auf TRUE gesetzt. Soll zusätzlich noch das Schlepplicht an sein (Byte 1 = 0x02), werden die Werte von oben, und zusätzlich jeweils Wert 1 auch auf TRUE für Topp- und Heckschlepplicht gesetzt. Der Befehl, der die Werte in die Kanäle der PWM-Module schreibt benötigt als ersten Parameter die Nummer des Kanals. Da das Array genau so viele Werte hat, wie das Modul Kanäle hat, können die Werte über einfache for-Schleife geschrieben werden. //write ledState to PWM modules for (int i = 0; i < 16; i++) { if (module1onOff[i]) { pwmLed1.setPin(i, (uint16_t)pgm_read_word(&mappingModule1[i]), false); } else { pwmLed1.setPin(i, 0, false); } if (module2onOff[i]) { pwmLed2.setPin(i, (uint16_t)pgm_read_word(&mappingModule2[i]), false); } else { pwmLed2.setPin(i, 0, false); } }
  3. Ich habe die beiden Posts mal abgetrennt, weil die eigentlich nichts mehr direkt mit dem ursprünglichen Thema zu tun haben.
  4. Leider nicht, aber ist mal eine Idee, die ich die Woche testen kann. Warum sollte man nur 6 Schalter abfragen können? Der Schalter ist ja auch nur ein Wert von -100 - +100? Da müsste ich nochmal die Handbücher durchsuchen.
  5. cool, Infos über das Arduinoprogramm schreibe ich noch.
  6. Hab gerade einen Dauertest von über einer Stunde laufen und keine Probleme, und da sind in den S.Port ein Liposensor und der Drehzahlsensor mit eingeschleift. Mit der Adresse muss man wahrscheinlich mehr aufpassen, dass man nicht einen realen Sensor verwendet, sondern einen, der eben nicht im System aktiv ist.
  7. So gehen wir auf die Arduino-Seite. Wie eingangs geschrieben verwende ich eine Bibliothek von „Pawelsky“ (Link im ersten Post). Die verwende ich aber weitgehend dazu, die Kommunikation zum Empfänger herzustellen. In der Bibliothek ist in der Klasse FrSkySportTelemetry eine Funktion send(), die das Senden von Daten übernimmt, aber auch den Datenempfang. Da ich keine Daten senden möchte, sondern nur das, was nach Adresse 0x0D gesendet wird, empfangen, schreibe ich mir eine eigene Klasse, die Teile der send-Funktion verwendet. Die Klasse habe ich FrSkySportTelemetryReader getauft, und die einzige Funktion ist receive(). Die ersten Anweisungen stammen aus der S.Port-Klasse. Sie prüfen ab, ob der der Serielle Port zum Empfänger „offen“ ist, und überhaupt Daten vorhanden sind. Ist beides der Fall wird ein Byte eingelesen. uint8_t data= serial.port->read(); In der Datenübertragung vom Empfänger zu den Sensoren ist 0x7E das Startsignal, dass der Empfänger was zu sagen hat. if (data == FRSKY_TELEMETRY_START_FRAME) { dataCounter = 0; available = false; } Diese Anweisungen prüfen, ob 0x7E empfangen wurde, was in der Definition FRSKY_TELEMETRY_START_FRAME hinterlegt ist. Ist das Startsignal empfangen, wird ein Zähler zurückgesetzt, und der Marker available auf false gesetzt. Der Zähler dataCounter und der Marker available hängen mit der zu empfangenden Datenlänge ab. Es werden insgesamt 10 Byte mit Daten erwartet, in denen dann die 4 Byte Nutzdaten liegen. Solange ich nicht 10 Bytes in meinem Datenpuffer habe, macht es keinen Sinn, die Daten weiterzugeben. Daher available = false; Die korrekte Anzahl Daten kann ich nur feststellen, wenn ich vom Startsignal aus zähle. Daher wird bei Empfang von 0x7E der Zähler zurückgesetzt. dataArray[dataCounter] = data; dataCounter++; Dieser Teil schreibt die Daten in einen Puffer und zählt den Zähler um 1 hoch. if ((dataCounter == 10) && (dataArray[1] == 0x0D)) { aUiRxValue[0] = dataArray[5]; aUiRxValue[1] = dataArray[6]; aUiRxValue[2] = dataArray[7]; aUiRxValue[3] = dataArray[8]; available = true; } Jetzt geht es an eine erste Auswertung. Wenn 10 Bytes empfangen wurden, und das zweite Byte den Wert 0x0D hat, werden die 4 Byte Nutzdaten in einen Ausgabepuffer geschrieben, und der Marker für verfügbare Daten auf true.
  8. Die Schaltung sieht also so aus: X6R (S.Port) <-> ProTrinket Pin 4 /// I2C (Pin A4 und A5) <-> PWM Module 1&2 <-> OLED-Display Dann geht es ans Programmieren, zuerst der Sender, weil der am einfachsten geht. In die X9E wird ein Funktions-Script geschrieben. Ein Funktions-Script, weil Zugriff auf das Display erst einmal nicht nötig ist. Es soll „nur“ die Stellung der Schalter zum Empfänger geschickt werden. Apropos, was wird eigentlich übertragen? Wieviel und wie? Das Protokoll ist für uns nicht direkt interessant. Wir müssen nur wissen, wie die übertragenen Daten aussehen. Insgesamt werden 10 Byte übertragen. Byte 1 ist eine Art Startsignal, und ist immer 0x7E. Byte 2 ist die Zieladresse, in diesem Fall 0x0D. Byte 3 und 4 sind für uns uninteressante Daten, die bleiben auf 0x10 und 0x01 stehen. In Byte 5-8 steht der übertragene Wert, und Byte 9-10 sind Prüfsummen. Es stehen also 4 Byte/32 Bit zur Verfügung, in denen etwas sinnvolles übertragen werden kann. 32Bit = 32 Schalter bzw Schaltstellungen? Das ist mal eine Hausnummer, und die können theoretisch vollständig verwendet werden, da die X9E maximal 18 Schalter mit drei Positionen verarbeiten kann. 3 x 18 ist 54? Mathematisch ja, schaltungstechnisch nein, denn die AUS-Stellung aller Schalter, wie auch immer man die festlegt, wird durch die 0 übertragen. Das wird nachher aus der Logik etwas klarer werden. Meine X9E hat nur 6 3-Stellungsschalter eingebaut, was aber erst einmal völlig ausreichend ist. Ich lege für mich selber fest, dass die Mittelstellung der Schalter AUS oder 0 bedeutet, und jeweils „nach oben“ (+) oder „nach unten“ (-) einer EIN-Stellung ist. Jedem der Schalter wird nun eines der 32 Bit zugeordnet. Schalter SA bekommt im niederwertigsten Byte das Bit 1 und 2, SB Bit 3 und 4, SC Bit 5 und 6 etc etc. Ist Schalter 1 > 10 (SA+) wird Bit 1 auf 1 gesetzt, indem zu dem zu sendenden Wert 1 hinzuaddiert wird. Ist SA < 10 (SA-), wird dem Wert 2 hinzuaddiert. Bei SB sind es 4 und 8 etc etc. Ist ein Schalter 0, also weder + noch - wird nichts unternommen. Soweit zur Theorie, im Code sieht das dann so aus: Der zu übertragende Wert wird mit 0 überschrieben channelValue = 0 Schalter SA wird auf + abgefragt if (getValue('sa') > 10) then Wenn SA+ ist, addiere 1 zur Variablen channelValue = channelValue + 1 --0x01 00 end Schalter SA wird auf - abgefragt if (getValue('sa') < -10) then Wenn SA- ist, addiere 2 zur Variablen channelValue = channelValue + 2 --0x02 00 end Gleiches dann für SB mit den Additionen von 4 und 8 if (getValue('sb') > 10) then channelValue = channelValue + 4--0x04 00 end if (getValue('sb') < -10) then channelValue = channelValue + 8--0x08 00 end usw für alle Schalter, die man übertragen will. Im Anschluss an die Schalterauswertung wird dann mit sportTelemetryPush(0x0D, 0x10, 0x01, channelValue) der Wert zum Empfänger geschickt, der das auf dem S.Port weiterleitet. Um ein paar Schalter zu übertragen, die das Licht schalten, muss das Script nicht ständig so schnell wie möglich die Daten zum Empfänger schicken. Wenn man den Schalter betätigt darf ruhig bis zu einer Sekunde beginnen. Daher ist die Auswertung in eine Abfrage eingebettet, die prüft, ob seit dem letzten Durchlauf 500ms vergangen sind. Was steht nun in channelValue drin? Die Liste zeigt zur Vereinfachung nur die ersten zwei Byte der Variablen, und die zugehörigen Bits. Wichtig ist zu verstehen, wo die Daten nachher liegen. Byte 1 Byte2 ... Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 ... SD- SD+ SC- SC+ SB- SB+ SA- SA+ SG- SG+ SE- SE+ ... Das minderwertigste Byte wird zuerst gesendet, steht also ganz links, dann folgen Byte 2-4 in aufsteigender Reihenfolge. Die Bits innerhalb eines Byte stehen von rechts nach links.
  9. Die Bibliothek funktioniert entweder mit einem Arduino kompatiblen Teensy 3.0/LC, ESP8266, oder einem Board mit ATmega328P. Der Letztere ist für mich erst einmal die interessante Variante, da ich davon ein paar zu Hause rumfliegen habe. Die Idee war dann zuerst, alles auf einen anderen Microcontroller zu portieren, nämlich den ATMEL SAMD21. Mehr Speicher, mehr Leistung? Warum nicht, kann doch nicht all zu schwer sein. Leider dann doch, weil eine wichtige Information erst durch tieferes graben ans Licht kam. Man braucht einen Chip, der die folgenden Eigenschaften erfüllen sollte: - der UART muss im Halbduplex laufen können - der Chip muss idealerweise mit einem invertieren UART-Signal sofort zurecht kommen Laut Datenblättern kann man die UART des SAMD21 zwar in den Halbduplex-Modus umschalten, aber dazu muss man einiges in den Kernkomponenten der Arduino IDE umschreiben. Der zweite Punkt ist mit dem SAMD21 gar nicht zu machen, ohne zusätzlich eine Schaltung zwischen Empfänger und Microcontroller zu setzen. Pläne sind dazu da, um sie zu ändern, also zurück zum ursprünglichen Plan, zu einem Board mit dem 328P, was auf 3,3V läuft. Ausgewählt habe ich für das Sensorreplikat von Adafruit den Pro Trinket 3V ( https://www.adafruit.com/product/2010 ). Der läuft mit 12 MHz Takt ausreichend schnell, hat allerdings den Nachteil, dass ein paar KB des Speichers von einem Bootloader belegt sind, der auch die Kommunikation über USB regelt. Dafür ist die Bauform schön kompakt. Es soll ja was geschaltet werden, vorzugsweise LED. Da der ProTrinket nur relativ wenige Ausgänge besitzt, muss eine andere Lösung her, wie man externe Geräte schaltet. Da das meiste LEDs sein werden, nehme ich ebenfalls von Adafruit einen, bzw mehrere 16 Kanal-PWM Module mit dem PCA9685 ( https://www.adafruit.com/product/815 ). Dieser Chip wird über I2C-Bus angesteuert und behält den Befehl für einen Ausgang so lange bei, bis ein neuer Befehl kommt, oder der Strom abgeschaltet wird. Das charmante an dem Board ist die eingebaute Konstantstromquelle, die Ideal für die LED ist. Außerdem kann man einen Kanal von ganz aus bis ganz an in 4096 Stufen sagen, wie hell man die LED haben will. Damit wird nachher die Beleuchtung so eingestellt, dass sie einigermaßen realistisch aussieht, und nicht die Positionslaternen mit der Helligkeit eines Suchscheinwerfers leuchten. Den „Sensor“ haben wir, einen Baustein, der was schaltet haben wir, der Empfänger, der den S.Port abgibt ist ein X6R, 6 Kanal PWM + 16 Kanal SBUS mit Telemetrie. Um den ganzen Kram mit Strom zu versorgen, brauchen wir noch ein paar Dinge. Der ProTrinket kann 16V DC ab, weil der einen eigenen Spannungsregler eingebaut hat. Da der Regler aber nur 150mA extern liefern kann, werden die PWM Module mit einer eigenen 3,3V Versorgung bedacht. Dafür verwende ich einen einfachen StepDown Regler von Pololu. Im Modell wird der Empfänger über das BEC des Fahrmotors versorgt. Da der Testaufbau eh an einem Labornetzteil hängt, will ich mir da den Aufwand erst einmal sparen und verwende ein 5V BEC, was direkt im Empfänger eingesteckt ist. Alle Spannungsquellen sind über eine gemeinsame Leitung von - und GND zusammengeschaltet. Die Schaltung ist damit fast komplett. Weil der ProTrinket über die USB Schnittstelle keine Debugausgabe, wie die anderen Arduinos, bereitstellen kann, muss ich das anders machen. Da ich noch von Adafruit ein OLED-Display habe, was ebenfalls über I2C angesteuert wird, hänge ich das auch noch an den Bus dran und gebe mir bestimmte Daten darüber aus.
  10. Für die Taranis Steuerungen mit OpenTX gibt es leider keine Multiswitche, wie z.B. von IMTH für die Graupner Anlagen. Dafür kann man aber die X9E mit selbst geschriebenen Programmen füttern, und ein Befehl in der API sah verdächtig danach aus, Daten über den Telemetriekanal vom Sender zum Empfänger zu schicken: sportTelemetryPush() Wenn FrSky-Empfänger oder Sensoren darüber Daten empfangen können, müsste es doch auch gehen, dass man einen Sensor mit einem Arduino ähnlichen Gefährt soweit zu emulieren, dass man das Signal darüber zweckentfremdet und für die eigenen Dienste nutzen kann. Eine Internetrecherche ergab, dass ich nicht der Einzige mit dem Vorhaben war, und es schon eine Bibliothek gibt, mit der man einen „beliebigen“ Sensor darstellen kann (https://www.rcgroups.com/forums/showthread.php?2245978-FrSky-S-Port-telemetry-library-easy-to-use-and-configurable ). Von der werden also die weiteren Bemühungen ausgehen. FrSkyMultiswitch.zip MtSw.zip
  11. Daher ist ein Baubericht doch gerade interessant. Anfänger hin oder her, angefangen hat jeder mal, deswegen wird keiner zerrissen.
  12. @snipy79 Vorschlag: wir haben den Bereich "Bauberichte". Scheint so als fängst du gerade einen schön bebilderten Bericht an. Mach doch da einen neuen Baubericht auf, mit einem Kommentarthema dazu, und berichte uns von den Erfahrungen, und auch, wie die Sprößlinge damit klar kommen. In dem Kommentarthema kann dann gezielter auf Fragen zu den Modellen eingegangen werden.
  13. Ich habe dafür Uhu Plus Endfest 90 Minuten genommen. Man muss nur gut abkleben, weil das Zeug zäh wie Honig ist, aber trotzdem die kleinsten Lücken findet.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.