Signal RC Empfaenger einlesen

Halo zusammen,

wir sollten uns vielleicht erst mal kurz vorstellen :wink:
Wir sind eine SchuelerAG die an Wettbewerben mit Solarbooten teilnehmen.
Dieses Jahr versuchen wir eine Art MPP Tracker zu bauen.
Mit viel Optimismus, aber wenig Ahnung.
Deshalb haben wir uns fuer einen Arduino entschieden.
Da keiner Erfahrung mit dessen Programmierung hat suchen wir uns die Einzelteile im Internet zusammen, versuchen zu verstehen was da gemacht wird und fuer unsere Zwecke anzupassen.
Fuer Spannungs- und Stommessung hat das wunderbar funktioniert.

Jetzt wollen wir das Signal der Fernsteuerung einlesen und nach entsprecheder Verarbeitung wieder an den Fahrtregler weiter schicken.
Wie das Signal aussieht ist uns dabei so halbwegs klar.
Im Moment simuliert ein Messgeraet den Fahrtregler das die Impulslaenge in myS direkt anzeigen kann.

Wir nutzen die Servo Bibliothek des Arduino
Mit writeMicrosekonds() funktioniert das ausgeben des Signals wunderbar.
Aber einlesen?
Sowas wie readMicroseconds() gibt es da wohl nicht :frowning:

Was wir jetzt gefunden haben sind Loesungen mit eigenen Interrups, oder Capture Eingaengen (was immer das auch ist). Beides scheint fuer absolute Anfaenger eher garnicht geeignet :wink:

Kennt hier vielleicht jmd eine Bibliothek mit etwas in der Art wie wir es suchen?
Waere super wenn uns da jmd etwas auf die Spruenge helfen koennte.

Vielen dank schon mal

PS was wohl gehen koennte scheint pulseIn()
Wir fragen nur einen Eingang ab. Die Blockade waere somit maximal 20000+myS.
Vielleicht geht das schon ohne zu sehr zu bremsen.
Wobei wir sonst gute Erfahrungen mit Mittelwertbildung gemacht haben und das auch hier gerne machen wollten.

noch'n PS wir haben eine extra Spannungsversorgung fuer den Empfaenger.
Es waere vermutlich gut den Arduino mit der Masse des Empfaengers zu verbinden, oder?
Bei den Servo Beispielen die wir uns angesehen hatten war der Servo vom Arduino mit versorgt, deshalb ist dort wohl keine extra Masse benutzt worden. Richtig?

Auf einer deutschen Tastatur liegt das 'µ' auf der Taste 'm', also AltGr+m :slight_smile:

Masseleitungen müssen immer dann verbunden werden, wenn sie als Bezugspotential für Signale dienen. Ausnahmen also nur bei Stromschnittstellen, Optokopplern o.ä.

Messungen im µs Bereich gehen nur mit Interrupts einigermaßen zuverlässig. Dabei muß entweder eine gemeinsame Interrupt-Routine die zu überwachenden Eingänge abfragen, oder für jeden Eingang muß eine eigene PinChangeInterrupt Routine benutzt werden. Deshalb nützt eine Bibliothek dafür nicht viel, sie könnte allenfalls als Vorlage dienen, die dann an jeden abzufragenden Pin angepaßt werden muß.

Ein einziges RC Signal kann man auch mit pulseIn() pollen, wenn die Blockade den Rest des Programms nicht zu sehr stört.

Vor kurzem gab es schon eine Diskussion in die Richtung: http://forum.arduino.cc/index.php?topic=378784.0

so bekommt ihr den PWM Wert in µSec im Bereich von ca. 700-2400

Euer_PM_WERT = pulseIn(Pin, HIGH);

ihr müsst einen PWM Pin am Adurino dafür auswählen z.B. Pin 3 und diesen für INPUT definieren.

Die Messung wird bei der ersten HIGH Flanke des signals gestartet und beim abfallen des signals (negative Flanke) beendet.

Das Ergebnis wird in µs ausgegeben. so könnt ihr leicht die Eingangswerte weiter verarbeiten.

https://www.arduino.cc/en/Reference/PulseIn

Servo vom Arduino mit versorgt, deshalb ist dort wohl keine extra Masse benutzt worden. Richtig?

!!!!!!!

Nicht die Servos an den internen Anschluss 5V des Arduono anschließen ..... der Motorstrom wäre zu hoch für den Spannungsregler auf dem Board !!!!!!

Die versorgungspannung für die Servos müssen aus der gemeinsamen 5V Quelle stammen .....oder vom Reciver dort sind die 5V Pins verbunden.

DrDiettrich:
Auf einer deutschen Tastatur liegt das 'µ' auf der Taste 'm', also AltGr+m :slight_smile:

Tatsaechlich :wink:

Masseleitungen müssen immer dann verbunden werden,

erledigt

Ein einziges RC Signal kann man auch mit pulseIn() pollen, wenn die Blockade den Rest des Programms nicht zu sehr stört.

was herauszufinden gilt.
pulseIn funktioniert schon mal. Damit werden wir einfach mal weiter machen und (versuchen) den Rest zu programmieren. Wenn alles funktioniert koennen wir uns ja immer noch Gedanken ueber Optimierungen machen. Notfalls naechstes Jahr.

pulseIn wollte zuerst nicht so recht. Wir hatten einen TimeOut von 24000 genommen (stand irgendwo als Empfehlung) Damit gab es immer wieder 0 als Rueckgabe.
Mit 27000 funktioniert es (irgendwo steht auch was passiert, wenn bereits HIGH anliegt, da sollten wir nochmal nachrechnen). Default ist wohl 1Sekunde. Das muss ja nicht sein.
Bei einer Mittelwertbildung ueber 25 Messungen dauert es fast 1 Sekunde bis der Ausgang auf Gashebelaenderungen am Sender reagiert.
Die ausgegebenen Werte schwanken um die 2 bis 3. Allerdings tun sie das bei Einzelmessungen fast genau so weit wie bei 25 summierten Messungen. Eventuell sollten wir es mit 3 oder 4 Messungen gut sein lassen.

Den anderen Beitrag hatten wir schon gesehen.
Irgendwie erscheint die Sache mit den Interrupts aber wohl ein wenig zu hoch fuer uns :wink:
Erst mal so probieren.
Vielen Dank an alle fuer's mitdenken.
Wir tauchen sicher noch oefter hier auf :wink:

Dumpfbacke:
so bekommt ihr den PWM Wert in µSec im Bereich von ca. 700-2400

ja genau so funktioniert es jetzt auch.
Bei pulseIn kann man noch einen timeout mit angeben.
Sonst kommt der Arduino im Zweifelsfall wohl erst nach 1Sekunde zurueck.

ihr müsst einen PWM Pin am Adurino dafür auswählen z.B. Pin 3 und diesen für INPUT definieren.

Oh... wir hatten zuerst ein Servoobjekt dafuer genommen und das an Pin9 gehaengt.
Den Pin haben wir der Einfachheit ma lgelassen.
Funktioniert wohl trotzdem :wink:

Servos haben wir gar keine :slight_smile:
Da Fahrtregler ja mit der gleichen Signalart angesteuert werden, hatten wir uns nur an einem Beispiel fuer ein Servo orientiert. Doert wurde das Servo direkt an den Arduino gehaegt und damit war die Masseverbindung sowieso da.
Wir haben heute Mittag die Massen von Arduino und dem Empfaengerakku ueber das Steckbrett verbunden.
Das wird spaeter sowieso anders gemacht. Es ist eine eigene Platine zum aufsteken auf einen Nano geplant.

Gruesse

Jo0815:
Irgendwie erscheint die Sache mit den Interrupts aber wohl ein wenig zu hoch fuer uns :wink:

So geheimnisvoll ist das auch nicht. Ein Beispiel (ungetestet):

const byte messpin = 2;
volatile unsigned long zeitHigh, zeitLow, zaehler;
volatile bool statistik;
unsigned long aktMicros, altMicros, mittelHigh, mittelLow;
bool auswertung;

void setup() {
  Serial.begin(9600);
  Serial.println("Programmanfang");
  pinMode(messpin, INPUT);
  pinMode(13, OUTPUT);
  attachInterrupt(0, messung, CHANGE);
}

void loop() {
  if (statistik) {
    statistik = false;
    mittelLow = (mittelLow * (zaehler - 1) + zeitLow) / zaehler;
    mittelHigh = (mittelHigh * (zaehler - 1) + zeitHigh) / zaehler;
  }
  if (zaehler > 100) {
    zaehler = 0;
    mittelLow = 0;
    mittelHigh = 0;
    Serial.print("  zeitLow: ");
    Serial.print(zeitLow);
    Serial.print("  mittelLow: ");
    Serial.print(mittelLow);
    Serial.print("  zeitHigh: ");
    Serial.print(zeitHigh);
    Serial.print("  mittelHigh: ");
    Serial.print(mittelHigh);
    Serial.println();
  }
}

void messung() {
  if (digitalRead(messpin)) {
    digitalWrite(13, HIGH);
    zaehler++;
    statistik = true;
    zeitLow = micros() - altMicros;
  } else {
    digitalWrite(13, LOW);
    zeitHigh = micros() - altMicros;
  }
  altMicros = micros();
}

Gut, das sieht schon mal bedeutend besser aus als das was wir uns so angesehen hatten.
Das sah irgendwie nach was ganz anderem aus. Vermutlich Assembler Befehle. Sowas ist in dem Arduino Buch hier garnicht drin :wink:

Andererseits brauchen wir Interrupts ueberhaupt?
Das macht man doch nur wenn man in der Zwischenzeit was anderes zu tun hat.
Haben wir das?

Manchmal macht nachdenken Sinn :wink:
So wie wir das verstanden haben kommt alle 20mS ein Impuls von der Fernsteuerung.
Darin sind dann zwischen 1000 und 2000µS High, der Rest jeweils Low.
1000 bedeutet voll rueckwaerts, 1500 Stillstand und 2000 voll vorwaerts.
Ist es jetzt gut irgendwelche langwierigen Mittelwertbildungen zu veranstalten?
Wenn man z.B 50 Messungen fuer den Mittelwert machen wurde und gleichzeitig in dieser Zeit den Gasknueppel von Mittelstellung auf voll vorne bewegt, ist der Mittelwert doch irgendwie nicht wirklich aussagekraeftig :wink:

Wir hatten uns die Funktion unseres Programms so vorgestellt.
Die loop Funktion liest zuerst das Signal von der Fernsteuerung ein.
Liegt es in der Naehe von 1500 geben wir es einfach weiter zum Fahrtregler. Stillstand.
Liegt es unterhalb von 1500 geben wir es ‘abgeschwaecht’ weiter. Rueckwaerts wollen wir ohne Tracking des MPP der Solarzellen fahren, aber nur eher langsam. Das hat einen Grund.
Liegt das Signal oberhalb 1500 verzweigen wir nochmal.
Bis z.B. 1700 geben wir das Signal einfach weiter. Da soll zum langsamen fahren dienen.
Oberhalb dieser Schwelle (die genauen Grenzen muessen wohl im Fahrversuch ermittelt werden) wollen wir mit der Software den Punkt der maximalen Leistung anfahren.
Das bedeutet, dass unser Fahrzeug in dem Bereich immer mit maximaler Geschwindigkeit (entsprechend er Leistung die die Solarzellen bei der Wetterlage hergeben) unterwegs ist. Und zwar unabhaengig von der Gashebelstellung an der Fernsteuerung. Erst wenn der Grenzwert wieder unterschritten wird hat wieder die Fernsteuerung das Kommando.

Tracking wird vorerst ganz einfach realisiert.
Spannung und Strom messen, Leistung berechnen und merken. Dann z.B. etwas mehr Gas geben.
Dann wieder messen und rechnen. Ist die Leistung jetzt hoeher wird weiter Gas gegeben.
Faellt die Leistung ab, wird Gas zurueck genommen.
Die meiste Zeit werden wir wohl in dem Tracking Bereich unterwegs sein.
Mit jedem Durchlauf von loop wird dann ‘nachgesehen’ ob sich eventuell was an dem Signal von der Fernsteuerung geaendert hat. Einzelwert, oder eventuell 3 oder 4 Messungen wuerden da ja reichen.

Interrupt wuerde ja bedeuten, dass alle 20mS gestoppt wird um das Signal auszuwerten.
‘Machen’ koennen wir in der Zeit ja eigentlich nix anderes
Das erscheint irgendwie nur sinnvoll, wenn man viele Eingaenge abfragen muss wo meistens nix passiert.
Es sich also nicht lohnt jedes mal alle nachzuschauen wenn man vorbei kommt :wink:
Andererseits… 20mS sind ja eigentlich sehr lange aus Sicht eines Rechners, auch aus der eines ‘langsamen’ Arduinos.
Hmmm… vermutlich sollten wir wirklich erst mal ohne probieren und dabei mal genau nachdenken was so ein Interrupt ist und wofuer man sowas sinnvoll verwendet :wink:

Kann man eigentlich ‘messen’ wie lange eine Programmsequenz bei der Verarbeitung braucht?
Vielleicht kann man sogar den Trackingalgorithmus mehrfach durchlaufen lassen bevor man wieder nach dem Fernsteuersignal schaut.

Sorry fuer den langen Text, das war irgendwie alles nur laut gedacht. Anfaenger halt :wink:
Uns ist wohl noch vieles unklar.

Die von mir benutzte Syntax ist in der Referenz beschrieben. Natürlich geht auch das schnellere Inline-Assembler (Quelle)

static inline bool getPin(volatile UNUSEDVAR uint8_t * DDR, volatile UNUSEDVAR uint8_t * PORT, volatile uint8_t * PIN,uint8_t pin)
{
 return (bool) *PIN & (1<<pin);   
}

Ob Ihr das braucht, wird sich zeigen, wohl eher nicht. Diese Zeilen ersetzen digitalRead.

Beim Messen von Signalen halte ich Interrupts schon für sinnvoll, würde ich Euch unbedingt ans Herz legen.

Mittelwertbildung ist nicht der richtige Weg, das sehe ich auch so, man kann einen Wert aber beruhigen mittels alterWert + 5 * neuerWert, also eine Gewichtung.

Wichtiges Stichwort ist noch Hysterese für die Bereichsunterscheidung.

agmue:

static inline bool getPin(volatile UNUSEDVAR uint8_t * DDR, 

volatile UNUSEDVAR uint8_t * PORT, volatile uint8_t * PIN,uint8_t pin)

Oh ja, genau sowas war gemeint mit 'verstehen wir ueberhaupt nicht' :slight_smile:

Hysterese und Gewichtung ist notiert.
Vielen Dank fuers mit denken

Hallo,

falls Euer Schwerpunkt mehr auf dem MPP-Tracker liegen sollte, und Ihr Euch nicht so viel mit dem Decodieren eines Fernsteuersignals herumschlagen wollt, dann könnt Ihr dafür auch Bibliotheken nehmen.
In diesem Thread von vor 2 Jahren wurden mir ein paar gute Hinweise gegeben:

Ich bin dann letztlich bei der Auswertung eines seriellen Summensignals gelandet, habe also nicht mehr ein PPM-Signal dekodiert. Aber es ist nicht die Standard, daß Empfänger sowas ausspucken.
Lg,
Tütenflieger

der Link auf http://www.rcarduino.tk/ fuehrt mittlerweile auf eine Seit mit den Bildern sehr armer Maedchen.
Die haben so wenig Geld, dass sie sich nix gescheites zum anziehen kaufen koennen :wink:

Aber unter dem Stichwort RCArduinoFastLib fand sich ein schoener Blog.
Speziell ist da mal was zu den Zeiten und der Arbeitsgeschwindigkeit des Arduinos erklaert.
Prima. Interrupts lohnen also doch :wink:
Die Verarbeitungsgeschwindigkeit des Arduinos ist gemessen an den 50Hz ja gewaltig :wink:
Das war uns nicht so bewusst.
In der Zeit zwischen 2 Impulsen von der Fernsteuerung kann man vermutlich jede Menge Tracking Durchlaeufe veranstalten.
Mal sehen. Das wuerde auch bedeuten, dass man vermutlich nicht bei jedem Durchlauf von loop() nach dem Signal sehen muss.
Zeiten lassen sich ja auch messen. Also genug Moeglichkeiten zu 'spielen'
Erst mal simpel. Ziel ist es zum Termin was fertig zu haben. Es gibt auch sonst noch jede Menge Arbeit im Bereich der 'Hardware'
Falls wir was halbwegs brauchbares zustande bekommen und noch Zeit ist, koennen wir ja immer noch ueber Interrups und verbesserte Trackingalgorithmen nachdenken.
Notfalls ist dafuer ja auch Zeit im naechstens und uebernaechsten und ueberueber.... Jahr :wink:

Gruesse

Jo0815:
Mal sehen. Das wuerde auch bedeuten, dass man vermutlich nicht bei jedem Durchlauf von loop() nach dem Signal sehen muss.

In meinem kleinen Beispiel #7 wird daher in der ISR void messung() ein Flag statistik = true; gesetzt, damit im nächsten loop() die Auswertung stattfinden kann.

erwischt...
Da hat noch niemand so genau rein geschaut :wink:
Wird aber noch gemacht.

das Leben kann so einfach sein :wink:
Aus www.rcarduino.tk wurde www.rcarduino.de
RCReceive.h ist bei der Arduino IDE mittlerweile auch schon mit dabei.
Unter Vorbehalt (wie gesagt wenig Ahnung davon) bindet man die Bibliothek ein und kann dann mit einfachen Befehlen genau das tun was wir wollen.
Pin verbinden, Interrupt starten, Werte in mS holen…
Richtig anfaengerfreundlich
Vielleicht kriegen wir es damit hin
Vielen Dank nochmal an alle fuer’s mitdenken

einfach genial :wink:
Vielen Dank an den uns voellig unbekannten Wilfried Klaas fuer die geniale library.
Die Sache war heute in wenigen Minuten erledigt.
Naja, ein wenig laenger hat es schon gedauert, hat aber auf anhieb funktioniert.
Wir koennen jetzt Sendersignale einlesen :wink:
Das Problem das uns am meisten Bauchschmerzen gemacht hat ist geloest.
Jetzt kann es weiter gehen.

Mittelwertbildung aus 10 Messwerten ist, wenn wir die Beschreibung richtig verstanden haben, schon mit eingebaut.
Daneben gibt es noch diverse Methoden zur Fehlererkennung und Behandlung.
Mal sehen was wir davon noch gebrauchen koennen.