Problem mit der Erkennung von Servosignalen - setzt jemand "ReadReceiver" ein ?

Hallo,

ich möchte die Servosignale aus einem RC-Empfänger detektieren, und die Daten mit einem Arduino weiterverwursten.
(Die Standard Servosignale sind 500-2500 µS langes digitalen HIGH Signale im 20 ms Abstand. Die Impulslänge bestimmt den Setpoint des einzustellenden Winkel des Servos, 1500 µS Pulslänge ergibt die Mittenstellung.)
Meiner erster Ansatz war mit der Nutzung des pulseIn Befehls. Das funktioniert auch gut, solange in loop() keine großen weiteren Aktivitäten stattfanden.
Wenn ich in meinem Progamm aber via I2C ein Display ansteuere, sowie via I2C eine 10DOF Sensoreinheit abfrage und einen PID Regler füttere, dann verliere ich mit dem pulseIn Befehl jede Menge Signale über Timeouts, das GesamtSystem reagiert damit sehr träge, auch wenn kein Delay in loop() auftaucht.

Pulslaenge = pulseIn(ServoSignalEingang, HIGH, 2600)
ServoWert = constrain(map(Pulslaenge, 500, 2500, -127, 127), -127, 127); //Abbildung des PWM Signals auf -127 bis +127

In meinem Testskript mit einer Loop-Durchlaufzeit bei Anzeige auf einem 20x4 Display von ca. 160 ms habe ich bei ca. 2 von 3 Schleifendurchläufen ein Timeout bei pulseIn, also nur ca. alle 0,5 Sec wird ein gültiger Wert erkannt, was für meine später gewünschte Lageregelung eines Flugmodells unbrauchbar ist.
Ich vermute, daß sich Interrupts vom I2C Bus mit pulseIn beissen ? Ich hatte irgendwo gelesen, daß pulseIn bis zum Timeout einem Delay entsprechen würde, und alles andere blockieren,
Ich habe nun pulseIn durch den timer1 basierten Code von **Arduino Playground - HomePage ersetzt.
Auch bei einem nur leicht von mir modifizierten Testcode (siehe Anhang) basierend auf "ReadReceiver" stellte sich aber heraus, daß nach ca. 10-100 Sekunden sich der Code aufhängt. Der jeweilige Zeitraum bis zum Aufhängen ist unterschiedlich, ich finde kein System heraus zb. keine zeitliche Regelmäßigkeit aufgrund eines Timervariablenüberlaufs etc.

Fragen:

  • Hat jemand eine Idee, woran das Aufhängen nach einem variablen Zeitraum liegen kann ?
  • Setzt jemand den ReadReceiver Code ein, und es funktioniert dauerhaft ?
  • Hat jemand eine andere brauchbare Lösung für die zuverlässige Dekodierung eines RC-Signals für Servos ? (letztendlich möchte ich 3-4 Servosignale verarbeiten).
    (Das Summensignal meines Mulitplex-Empfängers möchte ich nur im Notfall abgreifen, da die Schaltung auch später für Spektrum-Empfänger eingesetzt werden können soll)

Testbetrieb aktuell mit Arduino Uno rev. 3 sowie 2004 I2C Display, I2C 10DOF Einheit mit ITG3200 Gyro. Soll später auf einem Pro Mini Clone 328 / 16 MHz laufen.

Danke für Anregungen !
Tütenflieger

ReadRC_Signal_Test.ino (5.63 KB)

Ja, es gibt ne bessere Lösung.
Diese: http://www.rcarduino.tk/

Der Haken: die wirklich schnelle Methode (Interrupt-Methode) schafft mitm Uno lediglich zwei RC-Kanäle-aber sechse mitm MEGA 3560!
Läuft inzwischen wirklich hervorragend.
PulseIn hatte ich auch probiert- unbrauchbar, wenns auf Schnelligkeit ankommt.
Irgendeine andere RC-Empfänger-Bibliothek (weiss nicht, ob die Gleiche wie du benutzt) war ebenfalls entschieden zu lahmarschig.
Die von Willi dagegen tuts echt super. Da ich Megas für die beiden RC-Modelle benutze, hab ich genug Kanäle..

Hi,
Ich weiß jetzt nicht ob ich euch Modellbaufreaks was poste das schon bekannt ist. (Habe da zu wenig Ahnung)
Ein Bekannter von mir ist auch so einer, er benutzte für seinen Quadro das multiwii Projekt auf Arduino Basis. (Mega 2560)
Hier funktioniert die Erkennung der Servosignale via PWM ohne Probleme (Glaube es waren 9 Kanäle)

Ich habe dort auch das Summensignal seines Mulitplex-Empfängers eingebaut, ist fast einfacher als die PWM Signale zu handeln.
Kommt über die Serielle und via CRC lassen sich Fehler ausfiltern.

Inzwischen benutzt er das MegaPirateNG Projekt, da er dort auch das Digitale Mulitplex Signal eingebaut haben will.
habe ich diesen umpfangreichen Code versucht zu verstehen.
Hier sind mehrere Klassen voneinander abhängig vererbt, mein ++ Wissen reicht hier nicht aus. (Werde dafür aber einen eigenen Thread aufmachen)

Mein Verständnis nach lässt das MegaPirateNG Projekt für viele Modelle anpassen ?
Wenn es so ist, warum das Rad neu erfinden ?

Hallo,
der Tip von Rabenauge war gut, ich habe den RC Receiver von aus rcarduino.tk in meinem Testaufbau installiert, und er folgt tadellos den Servosignalen. Bisher habe ich nur das Verfahren aus RC_Template angetestet, nicht das aus RC_Int_Template.
Interessanterweise führt der Autor Klaas aus, daß das Standardverfahren auch auf PulseIn beruht (was bei mir ja nur fehlerhaft lief), und nur das RC_Int_Template auf Interrupts basiert. Muß ich mir noch genauer anschauen, evtl. ist ja ein Mischbetrieb möglich.
Ich habe halt gleichzeitig zeittkritische Anwendungen (Querruder, Seitenruder), und nicht zeitkritische (Schaltkanal), und möchte bei meinen kleinen Pro Minis mit 328ern mit nur zwei interruptfähigen Eingängen bleiben , statt auf einen großen Mega2560 ausweichen zu müssen.

@rudirabbit:
Die Flyduino-Projekte etc. erscheinen mir als relativer Anfänger recht komplex, in den Foren sehe ich eher die Diskussionen über die richtige Konfiguration, weniger über die internen Hintergründe. Ich möchte meine geplante Modell-Lageregelung aber gerne tatsächlich verstehen und anpassen können, und die einfache PID-Bibliothek etc. ist noch schön einfach durchblickbar. Aber Du hast recht, das man sich einzelne Module der ausgearbeiteten IMU und Flightcontroller Software dort mal an- und ggf. auch abgucken sollte.
Was mich aber doch echt interessieren würde: Hast Du konkreten Beispielcode für die Auswertung des Multiplex-Summensignals ?
Wenn es einfacher und ggf. auch "genauer" ist als die PPM Decodierung der einzelnen Servosignale, bzw. mehr als 2 Signale mit meinen 328ern damit bearbeitbar sind sollte ich mir das wohl wirklich anschauen.

Danke & Gruß,

Tütenflieger

P.S.: Tip evtl. interessant für weitere Interessenten,. ich habe das aber noch nicht getestet.
Hier wird eine Servobibliothek vorgestellt, die eine genauere zeiltiche Auflösung bietet als die Standard-Servo lib,

@Tütenflieger: Ja das geht mir auch so, das Flyduino-Projekt ist sehr Umpfangreich und viele Klassen sind ineinander Verschachtelt.
Aber wie du schon sagst, man kann in dem Code schon etwas spicken wenn es z.b um die PWM Signale der Empfänger geht.
z.b. in RCInput_MPNG.cpp.
Aber auch im Multiwii Projekt das deutlicher einfacher ist, kann man sich diesbezüglich Ideen holen

Zum Multiplex-Summensignal (Digital) :
Es gibt 2 Versionen eine mit Startbyte 0xA1 und eine mit 0xA2, dananch unterscheiden die sich nur in der Anzahl der Kanäle.
Am Ende wird noch die CRC geschickt Highbyte und dann Lowbyte.
Die Servostellungen auch erst High und Lowbyte. Wobei beim Higbyte nur das untere Nibble benutzt wird (Die Servowege sind also 12 Bit breit)
Servoinformation in 4095 Schritten:
800?s 0x000
1500?s 0x800
2200?s 0xFFF

Die Serielle musst du mit den Parametern 115200Kbit/s, 8 Datenbits, keine Parität, 1 Stopp-Bit. öffnen.

Den Beispiel Code den ich ins Multiwii Projekt eingebaut habe, und auch funktionierte.

#if defined(SRXLBUS)

uint16_t CRC16(uint16_t crc, uint8_t value)
{
uint8_t i; 
crc = crc ^ (uint16_t)value<<8;
for (i=0; i<8; i++)
    {
      if (crc & 0x8000)
          crc=crc << 1 ^0x1021;
          else
           crc = crc << 1;
    }
    return crc;
}


void  readSRXL(){
  #define SRXL_SYNCBYTE 0xA1 
  static uint16_t SRXL[26]={0};
  uint8_t i;
  uint16_t crc=0;
  uint16_t checkcrc;
  uint8_t po = 0;    
 
  while(Serial1.available()){
    int val = Serial1.read();
    if(SRXLIndex==0 && val != SRXL_SYNCBYTE)
      continue;
    SRXL[SRXLIndex++] = val;
    if(SRXLIndex==27){
      SRXLIndex=0;
         SRXL[0] = SRXL_SYNCBYTE;  
       crc=0;
       for(i=0; i<=24; i++)                     
                        crc=CRC16(crc,SRXL[i]);  
                          
       checkcrc=(SRXL[25]<<8|SRXL[26]);                 
     
     if (checkcrc==crc)
     //if (true)
       {
        po=1;
      for(i=0; i<=8; i++)    
         {      
         rcValue[i]  = (SRXL[po]<<8|SRXL[po+1])/2.3+614; 
        po=po+2;
         }
      } 
    }
  }        
}
#endif

Im array rcValue erwartet das Projekt die Servowege, ich habe das mit /2.3+614 so "gemappt" das es wieder passt.
Hier wird das obere Nibble des Highbyte nicht ausmaskiert, war immer 0x0 außerdem wird das ganze sowieso via CRC
geprüft.

Parallel dazu habe ich noch zwei kleine Windows Programme gebaut um damit lesen und komfortabel anzeigen zu können was von Empfänger kommt.

Mutiplex_Logger.rar (942 KB)

Kleiner Nachtrag:
Nach weiteren Tests des RC Receiver von aus rcarduino.tk mit nun 2 Kanälen auch mit der Version mit Interruptroutine läuft das auch noch nicht ganz rund.
Es dauert manchmal auch ein paar Sekunden, bis ein neuer Input (geändertes RC-Signal) richtig erkannt wird. Kennt das irgendjemand ? Ich sollte nochmal mit dem Oszi prüfen, ob ich hier vielleicht einfach Signalstörungen an den Eingängen des Arduino habe, ich kann mir nicht vorstellen, daß ein einfacher I2C Bus mit 5 Clients (10DOF mit 4 Sensoren, + LCD) die Interrupts der RC-Signaleingänge für ca. 3-5 Sekunden blockiert. Oder muß ich mir generell die Kombination I2C und akkurate Interruptbehandlung abschminken ?

Den Code von rudirabbit zur Dekodierung des Multiplex-Summensignals muss ich noch richtig durcharbeiten, für meine Programmierkenntnisse ist das nicht trivial....

Danke für den Code,
Tütenflieger

Ne-sekundenlange Verzögerungen darf es nicht geben. Das spielt sich alles im einstelligen Millisekundenbereich ab, bei der Interrupt-Version.
Aber: es kann da unter Umständen schon Konflikte geben- teste einfach mal ohne den I2C zu aktivieren.

Hi,
bin der Autor von RCArduino.
Die Interruptroutine sollte eigentlich ohne zus. Verzögerung funktionieren. Intern verwende ich einen Speicher, der die letzen 10 Signale überprüft und dann mittelt. d.h. bei den üblichen Empfängern kann es bis zu 200ms dauern bis ds Signal vollständig da ist. Der Puffer ist aber einstellbar. (Steht in den Quellen beschrieben.)
Mischbetrieb würde ich dringend abraten. Denn der pulsIn Befehl stoppt quasi die Verarbeitung. Damit wird nicht nur der Switch langsam, sondern das gesamte Programm. Da du 3 Kanäle verwenden willst, wäre da der Leonardo der richtige. Der hat 4 Interrupteingänge...
Die FlyDunio und andere Multicoptersteuerungen haben natürlich auch gute Bibliotheken. Man muss eben schauen, welche für seinen Anwendungszweck ideal ist. An das Summensignal hab ich mich mangels Empfänger noch nicht ran gewagt...

Hallo,

ich habe nun weiter meinen Code getestet und entschlackt.
Auch bei einer Basisroutine: Servosignale über die Lib RC Receiver von rcarduino.tk einlesen und dieser wieder über die Standard Servo-Lib ausgeben gibt es manchmal erratische lange Verzögerungen.
Ich rühre mit einem Poti meines Servotesters herum, und die Servos funktionieren erstmal auch prima. Plötzlich steht die ganze Kiste für eine halbe bis zu 10 Sekunden, und nimmt dann erst den neuen Wert an.
Das Signal des Servotesters (ein anderer Arduino) habe ich mit einem Oszi überprüft, das ist OK. Das Signal an die Servos habe ich auch mit dem Oszi geprüft, es entspricht auch dem, was ich erfahre: Zuweilen Stillstand, es scheint also kein Problem der Servo(Strom&Signal)versorgung zu sein.

Ich habe alles andere aus meinem Code herausgeworfen, also nix mehr mit I2C Bus, LCD oder 10DOF Treiber aus dem ursprünglichem Projekt.
Falls da noch ungenutzte Variablen deklariert sein sollten, dann liegt es daran, daß ich hier ein Excerpt aus einem größeren Code mit PID Regler, LCD, Gyrosensor etc. erstellte, um auf des Pudels Kern zu kommen.
Das zwischenzeitliche Ummappen der Servowerte auf +/- 2^10-1 ist Absicht, um Rundungsfehler einer geplanten weiteren Berechnung mit PID Regler etc. zu minimieren.

/*
Testroutine, reicht einfach Servosignale die über die Bibliothek RCReceiver empfangen wurden an die 
 Standard Arduino Servo-Bibliothek weiter.
 Zwischendurch Mapping der Servowerte 0 bis 255 der RC Receiver Lib auf -1023 bis +1023, um  bei späteren Berechnungen
 mit einem PID Regler Spielraum ohne zuviele Rundungsfehler zu haben.
 Am Ende Mapping der Servosignale auf die 0 bis 180 Grad der Servo Lib.
 */
#include <Servo.h>
#include "makros.h"
#include "debug.h"
#include "RCReceive.h"

//---------- SERVO----------------------
Servo myservo1;  // create servo object to control a servo
Servo myservo2;  // create servo object to control a servo

#define ServoSignalAusgang1 9  // Das Signal für den Ausgangsservo 1
#define ServoSignalAusgang2 10  // Das Signal für den Ausgangsservo 2

int ServoWert1 = 0;  // variable to store the value coming from the sensor
int ServoWert2 = 0;  // variable to store the value coming from the sensor

// ********************** Code für das Auslesen des RC-Signals *****************************
// Code aus http://www.rcarduino.tk/
RCReceive rcReceiver1; // Der Empfänger: QR-Signal
RCReceive rcReceiver2; // Der Empfänger: Schaltkanal
boolean KeinRCSignal1 = true;
boolean KeinRCSignal2 = true;
byte Servovalue1;
byte Servovalue2;
boolean   QR_Stabi_AN = false;
#define RC_QR 2    //arduino pins attached to the receiver Die Interrupts gehen nur für Pin 2 und 3
#define RC_SCHALT 3

void setup() // #################### SETUP ##################################################
{
  myservo1.attach(ServoSignalAusgang1);  // attaches the servo on pin 9 to the servo object 1
  myservo2.attach(ServoSignalAusgang2);  // attaches the servo on pin 10 to the servo object 2
  pinMode(RC_QR, INPUT);  //Querruder-Signal
  pinMode(RC_SCHALT, INPUT); // Das Schaltsignal, daß mal die PID-Regelung ausschalten soll

  // ********************** Code für das Auslesen des RC-Signals *****************************
  // Für die Signalanalyse via Interrupts, geht nur an Pin 2 und 3
  rcReceiver1.attachInt(RC_QR);
  rcReceiver2.attachInt(RC_SCHALT);

}

void loop()  // #################### LOOP ##################################################
{
  // ********************** Code für das Auslesen des RC-Signals über Interrupts *****************************
  if (rcReceiver1.hasNP() && !rcReceiver1.hasError()) 
  {
    Servovalue1 = rcReceiver1.getValue();  //Es werden Werte von 0 bis 255 ausgegeben
    KeinRCSignal1 = false;  
  } 
  else if (rcReceiver1.hasError()) {
    KeinRCSignal1 = true;// Fehlerbehandlung failsafe oder sowas...
    Servovalue1 = 0;  // Failsafe: Neutralstellung
  }
  // ******************** Ende Auslesen RC-Signal für das QR***********************************
  if (KeinRCSignal1 == false)    //nur dann ist es ein gültiger Wert
  {
    ServoWert1 = constrain(map(Servovalue1, 0, 255, -1023, +1023), -1023, +1023);
  }
  // ************************* Der Schaltkanal wird abgefragt
  if (rcReceiver2.hasNP() && !rcReceiver2.hasError()) 
  {
    Servovalue2 = rcReceiver2.getValue();  //Es werden Werte von 0 bis 255 ausgegeben
    KeinRCSignal2 = false;  
  } 
  else if (rcReceiver2.hasError()) {
    KeinRCSignal2 = true;// Fehlerbehandlung failsafe oder sowas...
    Servovalue2 = 0;  // Failsafe: Neutralstellung
  }

  // ******************** Ende Auslesen RC-Signal ***********************************
  if (KeinRCSignal2 == false)    //nur dann ist es ein gültiger Wert
  {
    ServoWert2 = constrain(map(Servovalue2, 0, 255, -1023, 1023), -1023, 1023);
    // Wertebereich zwischen -1023 und +1023, Mittenwert ist 0, das wäre dann Setpoint Null
  }

  myservo1.write(map(ServoWert1, -1023, +1023, 160, 20));       //  Durchreichen der erfassten Servosignale vom Empfänger
  myservo2.write(map(ServoWert1, -1023, +1023, 160, 20));       //  Durchreichen der erfassten Servosignale vom Empfänger
}

Hat da irgendjemand (Willie1968 ?) noch eine Idee ? Bzgl. der Signalauslesung habe ich mich ja ziemlich an die Beispielroutine des RC Receivers von RCarduino gehalten. Ist evtl. die Standard Servo-Bibliothek von Arduino faul oder inkompatibel dazu ?

Ansonsten würde ich später mal durchaus gerne den Mischbetrieb testen, also 2 interrupt gesteuerte Kanäle für die zeitkritischen Regelprozesse zur Stabilisierung von Querruder und Seitenruder, sowie einen etwas weniger zeitkritischen Schaltkanal zur Abschaltung dieser Regelung. Wenn ich hier 200 ms Sekunden warten müsste und die Auslesung der anderen Servos blockiert wäre, wäre das noch im Rahmen des machbaren. Die PID Regelung der Servos sollte hingegen über die Interruptsteuerung schneller laufen .

Danke & Gruß,
Tütenflieger

Meine Hardware: China-Arduino Uno , die beiden Miniservos des Testaufbaus werden über ein externes NT gespeist, unabhängig von der USB-Speisung des Unos. Müssen Servosignale evtl. nochmal verstärkt werden, sind die Eingangsströme in die Servos evtl. zu hoch ? Ich ging eigentlich davon aus, daß das vernachlässigbar sei.

Hm, sowas ist mir noch nie untergekommen.
Möglich wäre, dass dir irgendwas nen Timer blockiert.

Grade sie Servobibliothek ist zickiger, als man gemeinhin glaubt. Mit der hatte ich schon nen paarmal Ärger.
Soweit ich mich entsinne (such mal auf Willis Seiten) kann man, wenn man sie benutzt, nur die Interrupt-Methode verwenden.
Ansonsten: versuch mal, die Servos an andere Pins zu legen.

Kannst du die Werte auslesen, über die serielle Konsole z.B?
Kommt da irgendwo dauernd nen Wert mit 65 an?? (kann auch 68 gewesen sein, aber was in den 60ern, und der konstant..)

Es wäre interessant zu sehen, ob ein Fehler von der RCReceive geliefert wird.
Und wenn das der Fall ist, mal mit dem Oszi schauen ob der Empfänger was liefert...

Die Servolib zickt manchmal, deswegen verwende ich den gleichen Timer mit der gleichen Initialisierung wie die Servo Lib, damit das geht. Wenn das aber nicht funktioniert, dann funktioniert es immer nicht. Pausen hab ich noch nie gehabt...

Hallo,
wenn ich im Falle von Fehlermeldungen von RCReceive was auf Serial ausgebe, dann kommen dort einige Fehler an, dann stockt die ganze Sache. Serial und das Programm mögen sich anscheinend nicht. Ich habe dann die LED an Pin 13 als FehlerLED missbraucht, und die blinkt auch richtig wenn man kräftig für einige Zeit an dem Poti rührt. RCReceive detektiert also fehlerhafte Signale.
Die Fehler treten gehäuft auf bei extremeren Ausschlägen des Potis (also ca. 600 µS oder 2200 µS Impulslänge).
Die Servosignaleingänge sind per Oszi getestet OK.

  • Es gibt keine Besserung, wenn ich andere Ausgänge des Arduinos nehme (Pin 11 & 12 statt 9 und 10)
  • Es gibt keine Besserung, wenn ich einen Kanaleingang auf Masse lege. Ich dachte zuerst, daß zwei Eingänge die parallel an einem einzelnen Servosignal hängen hier evtl. gegenseitig über ihre gleichzeitigen Interrupts stolpern, aber ein Eingang alleine macht auch die bekannten Probleme
  • Es gibt keine Besserung, wenn ich die Servos über ein fettes zusätzliches Netzteil speise (diese 5g Servos brauchen zwar nur je ca. 100 mA bei Vollausschlägen, aber die potentielle Problemquelle wollte ich einfach ausschließen),

Ich versuche es jetzt als nächstes :

  • Einen echten RC-Empfänger dranzuhängen, nicht daß ich doch unsaubere Signale speise
  • eine andere Servo-Bibliothek einzusetzen, ich versuche es mit der von Willie1968 aus rcarduino.tk

verzweifelter Tütenflieger

Beim Einsatz eines echten RC-Empfängers statt eines Servotester ergaben sich beim "herumrühren" der Steuerknüppel nun keine Wartezeiten mehr. Das ist die gute Nachricht.
Die schlechte ist, daß es trotzdem weiterhin eine Menge Fehlermeldungen von RCReceiver gibt, auch wenn die Knüppel nur in der Neutralstellung verbleiben.
Ich führe die nun nicht mehr auftretenden Wartezeiten auf den kleineren realen Wertebereich der Servo-Impulslängen zurück. Bei mir konkret 1280 bis 2080 µS aus dem RC-Empfänger, im Gegensatz zu den vorherigen 500 bis 2500 µS die aus dem Servotester herauskamen.

Als nächste Teste ich die komplette Installation mit PID Regler etc. mit dem RC-Empfänger, und versuche mich vorsichtshalber auch nochmal an einer anderen Servobibliothek.

Gruß,

Tütenflieger.

Tütenflieger:
Die schlechte ist, daß es trotzdem weiterhin eine Menge Fehlermeldungen von RCReceiver gibt, auch wenn die Knüppel nur in der Neutralstellung verbleiben.

Wenn das Signal vom RC-Empfänger in Ordnung ist, aber Deine RCReceiver-Library die Impulse nicht korrekt auswerten kann, stimmt da etwas nicht. Entweder mit der RCReceiver-Library selbst oder mit dem Zusammenspiel des Codes in Deinem Sketch.

Ich persönlich würde allenfalls nur die Servo-Library verwenden und das Signal vom RC-Empfänger im Code in einer geeigneten Weise pollen. Und die RCReceiver-Library weglassen.

Ich kenne das genaue Timing-Diagramm der Kanäle nicht, aber bei 20ms Refresh-Rate und 1,5...2,5ms Impulsbreite würde ich mal raten, dass Innerhalb des 20ms Fensters je 3ms pro Kanal laufen, d.h. 4 Kanäle sind nach spätestens 12 ms abgefrühstückt.

Wenn Du jedes einzelne 20ms Zeitfenster pollst, hast Du also 50 mal pro Sekunde je 8ms für andere Aktionen Deines Programms zur Verfügung.

Wenn Du jedes zweite 20ms Zeitfenster pollst, hast Du nach dem Pollen des Signals jedesmal 28ms für andere Aktionen im Sketch. Bei jedem dritten Zeitfenster wären es 48ms für andere Aktionen.

Ich würde es mal ohne die RCReceiver-Library probieren, die loop-Funktion auf den Start des Refresh-Impulses von Kanal-1 synchronisieren, und die Servosignale einfach pollen. Geeignete Timeouts nicht vergessen, damit sich das Polling nicht totläuft, wenn der RC-Empfänger kein Signal liefern sollte.

Nachtrag:
Ich habe mal versucht, einen Sketch zu machen, der die Impulse von einem 4-Kanal RC-Empfänger ausliest.

Testen konnte ich ihn allerdings nicht, da ich hier keinen RC-Empfänger griffbereit habe. Eventuell sind also noch Änderungen notwendig. Damit Änderungen leicht möglich sind, ist der Code von mir kommentiert:

#define TIMEOUTSLICE 21000  // 21 Millisekunden als Zeitscheiben-Timeout
#define TIMEOUTCHANNEL 5000 // 5 Millisekunden als Timeout zwischen den Kanälen
#define TIMEOUTIMPULSE 3000 // 3 Millisekunden Impuls-Timeout

#define CHANNELS 4  // 4 Kanäle
int channelPins[CHANNELS]={2,3,4,5}; // define pin numbers for rc receiver channels
int impulseDuration[CHANNELS]; 

int readRcTiming(int* impulseTime)
/* Rückgabewert
   0 ==> Impulslängen wurden erfolgreich gemessen und stehen im übergebenen int-Array
   Negative Rückgabewerte stehen für Timeout
   -1 ==> Kein Impuls auf erstem Kanal festgestellt
   -2 ==> Keine Folgeimpulse auf weiteren Kanälen festgestellt
   -3 ==> Impuls dauert zu lange
*/
{
  unsigned long duration, timeout;
  unsigned long now=micros();
  while (digitalRead(channelPins[0])==HIGH && micros()-now<TIMEOUTIMPULSE) ; // nur warten
  if (micros()-now>=TIMEOUTIMPULSE) return -3; // exit mit Timeout-Rückgabewert
  now=micros();
  for (int i=0;i<CHANNELS;i++)
  {
    if (i==0) timeout=TIMEOUTSLICE; else timeout=TIMEOUTCHANNEL;
    while (digitalRead(channelPins[i])==LOW && micros()-now<timeout) ; // nur warten
    if (micros()-now>=timeout)
    {
      if (timeout==TIMEOUTSLICE) return -1; // exit mit Timeout-Rückgabewert
      else return -2;  // exit mit Timeout-Rückgabewert
    }
    now=micros();  // Kanal geht HIGH, Beginn des Impulses
    while (digitalRead(channelPins[i])==HIGH && micros()-now<TIMEOUTIMPULSE) ; // nur warten
    duration=micros()-now;
    if (duration>=TIMEOUTIMPULSE) return -3; // exit mit Timeout-Rückgabewert
    impulseTime[i]=duration;
  }
  return 0; // ende ohne Timeout
}



void setup() {
  Serial.begin(9600);
}


void loop() {
  char charbuf[10];
  int result=readRcTiming(impulseDuration);
  if (result<0) Serial.println(result);
  else
  {
    for(int i=0;i<CHANNELS;i++)
    {
      snprintf(charbuf,sizeof(charbuf),"%6d  ",impulseDuration[i]);
      Serial.print(charbuf);
    }
    Serial.println();
  }
}

@jurs: Supervielen Dank für die Mühe mit dem Beispiel Code, ich werde ihn heute Abend "einbauen" und testen.
Prinzipiell dachte ich, daß das Pollen von Signalen ja dem Benutzen von pulseIn entspricht, aber Du baust hier noch eine Synchronisation mit der Schleife ein.
Ich bin mir nicht sicher, ob nicht die Sache mit den Zeitfenstern mit 50 mal 8 ms für den späteren restlichen Code zu knapp wird. Ich will ja eigentlich noch per I2C Daten vom 10OF Sensor abrufen, und via PID Regler verarbeiten. Ich habe hier noch nicht die Geschwindigkeit gemessen.
Da ich aber zusätzlich noch entweder ein LCD-Display nutze (zum Einstellen der Parameter im Testbetrieb), oder auf eine SD-Karte mitlogge, (beides gleichzeitig geht wg. Speicherplatz nicht), dürften für den späteren Vollausbau die 8ms Zeitschlitze wohl zu kurz sein.
Aber ich probiere es aus.

Ich habe jetzt auf Hinweis von Willi168 aber vorher nochmal versucht meinem Beispielscode des einfachen Durchreichens der Signale via "RC receiver" leicht umzubauen, und auf den Pins 12 und 13 jeweils ein Signal im detektiertem Fehlerfall auszugeben. Beim nächsten korrekten Auslesen wird das Signal wieder auf Null gesetzt.
Code:

#include <Servo.h>
#include "makros.h"
#include "debug.h"
#include "RCReceive.h"

//---------- SERVO----------------------
Servo myservo1;  // create servo object to control a servo
Servo myservo2;  // create servo object to control a servo

#define ServoSignalAusgang1 9  // Das Signal für den Ausgangsservo 1
#define ServoSignalAusgang2 10  // Das Signal für den Ausgangsservo 2

int ServoWert1 = 0;  // variable to store the value coming from the sensor
int ServoWert2 = 0;  // variable to store the value coming from the sensor

// ********************** Code für das Auslesen des RC-Signals *****************************
// Code aus http://www.rcarduino.tk/
RCReceive rcReceiver1; // Der Empfänger: QR-Signal
RCReceive rcReceiver2; // Der Empfänger: Schaltkanal
boolean KeinRCSignal1 = true;
boolean KeinRCSignal2 = true;
byte Servovalue1;
byte Servovalue2;
boolean   QR_Stabi_AN = false;
#define RC_QR 2    //arduino pins attached to the receiver Die Interrupts gehen nur für Pin 2 und 3
#define RC_SCHALT 3

void setup() // #################### SETUP ##################################################
{
  myservo1.attach(ServoSignalAusgang1);  // attaches the servo on pin 9 to the servo object 1
  myservo2.attach(ServoSignalAusgang2);  // attaches the servo on pin 10 to the servo object 2
  pinMode(RC_QR, INPUT);  //Querruder-Signal
  pinMode(RC_SCHALT, INPUT); // Das Schaltsignal, daß mal die PID-Regelung ausschalten soll

  // ********************** Code für das Auslesen des RC-Signals *****************************
  // Für die Signalanalyse via Interrupts, geht nur an Pin 2 und 3
  rcReceiver1.attachInt(RC_QR);
  rcReceiver2.attachInt(RC_SCHALT);
  pinMode(12, OUTPUT); // für Fehlersignale von Kanal 1
  pinMode(13, OUTPUT); // für Fehlersignale von Kanal 2
  digitalWrite(12, LOW);
  digitalWrite(13, LOW);
}

void loop()  // #################### LOOP ##################################################
{
  // ********************** Auslesen des RC-Signals für das QR über Interrupts *****************************
  if (rcReceiver1.hasNP() && !rcReceiver1.hasError()) 
  {
    Servovalue1 = rcReceiver1.getValue();  //Es werden Werte von 0 bis 255 ausgegeben
    KeinRCSignal1 = false;  
    digitalWrite(12, LOW);
  } 
  else if (rcReceiver1.hasError()) {
    KeinRCSignal1 = true;// Fehlerbehandlung failsafe oder sowas...
    Servovalue1 = 0;  // Failsafe: Neutralstellung
    digitalWrite(12, HIGH);
  }
  // ******************** Umrechnen des RC-Signal für das QR an Servo 1
  if (KeinRCSignal1 == false)    //nur dann ist es ein gültiger Wert
  {
    ServoWert1 = constrain(map(Servovalue1, 0, 255, -1023, +1023), -1023, +1023);
    // Wertebereich zwischen -1023 und +1023, Mittenwert ist 0, das wäre dann Setpoint Null
  }
  // ************************* Auslesen des RC-Signals für den Schaltkanal über Interrupts  *****************************
  if (rcReceiver2.hasNP() && !rcReceiver2.hasError()) 
  {
    Servovalue2 = rcReceiver2.getValue();  //Es werden Werte von 0 bis 255 ausgegeben
    KeinRCSignal2 = false;  
    digitalWrite(13, LOW);
  } 
  else if (rcReceiver2.hasError()) {
    KeinRCSignal2 = true;// Fehlerbehandlung failsafe oder sowas...
    Servovalue2 = 0;  // Failsafe: Neutralstellung
    digitalWrite(13, HIGH);
  }

  // ******************** Umrechnen des RC-Signal für den Schaltkanal an Servo 2
  if (KeinRCSignal2 == false)    //nur dann ist es ein gültiger Wert
  {
    ServoWert2 = constrain(map(Servovalue2, 0, 255, -1023, 1023), -1023, 1023);
  }
  // ---------------------- Ausgabe der Servosignale ------------------------------------
  // Remapping der Signale auf die Winkel
  myservo1.write(map(ServoWert1, -1023, +1023, 160, 20));       //  Durchreichen der erfassten Servosignale vom Empfänger
  myservo2.write(map(ServoWert2, -1023, +1023, 160, 20));       //  Durchreichen der erfassten Servosignale vom Empfänger
}

Ergebnis: Das Oszi zeigt recht regelmäßig alle ca. 400 ms gleichzeitig(!) auf beiden Kanälen ein 20 oder 40 ms andauerndes Fehlersignal.
Also alle 20 bis 22 RC-Signale werden regelmäßig ein oder 2 Signale falsch gelesen.
Das gilt, wenn beide Kanäle in Ruheposition sind. Screenshot siehe angehängte GIF Datei.
Um Hardwareprobleme auszuschließen, habe ich nochmal:

  • den RC-Empfänger ausgetauscht (Spektrum statt Multiplex-System)
  • einen anderen Arduino Uno (Chinaklon) eingesetzt, an dem sonst nichts anderes mehr angeschlossen war

Keine Änderung, am RC-Signal wird es damit nicht liegen: Weiterhin die regelmäßigen Fehlermeldungen.
Beim Versuch zusammen mit den 10DOF I2C Sensoren und sowie PID Regler wird die ganze Sache wieder recht träge. Mit dem nun neu eingeführten Abschalten der Ausgabe auf LCD auf Tastendruck (ich brauche das ja nur am Boden, nicht in der Luft) reagiert das Gesamtsystem zwar schneller, aber trotzdem noch zu träge für ein sauberes Steuern.

Wenn es sonst keine Ideen mehr gibt, versuche ich als nächste Aktion den Code von Jurs zu beleben, und sonst nochmal auf eine Suche nach einer anderen Servo-Bib zu gehen.

Tütenflieger

Schon merkwürdig-sowas hatte ich nie.

Tütenflieger:
Ich bin mir nicht sicher, ob nicht die Sache mit den Zeitfenstern mit 50 mal 8 ms für den späteren restlichen Code zu knapp wird.

Ich habe mir nochmal den genauen Signalverlauf einer RC-Anlage mit mehreren Servos angesehen:
http://www.cim.mcgill.ca/~vng/Projects/Images/ppm.png
Offenbar folgt immer ein Servosignal auf das nächste, ohne Pause dazwischen, und wenn man von einer maximalen Impulsdauer von 2,5ms ausgeht, sind die Signale von 4 Kanälen nach höchstens 10ms beendet. D.h. in einem 20ms Zeitfenster hast Du immer mindestens 10ms für andere Aufgaben.

Tütenflieger:
Weiterhin die regelmäßigen Fehlermeldungen.

Was ist denn das für ein Oszilloskopbild?
Sollen das die Servoimpulse auf zwei Servokanälen desselben RC-Empfängers sein?

Vergleiche bitte mal mit dem Bild unter dem Link, das ich oben gesendet habe!
Dein Oszilloskopbild sieht nicht so aus!

Der von mir oben gepostete Code ist nur für Signale auf verschiedenen RC-Kanälen, die so einen zeitlichen Verlauf haben wie in dem Link gezeigt:
http://www.cim.mcgill.ca/~vng/Projects/Images/ppm.png
Zwei Servokanäle, die wie auf Deinem Bild gleichzeitig ihren Servo-Impuls feuern wie auf Deinem Oszilloskopbild zu sehen, kann mein Code nicht auswerten, so wie ich ihn gepostet habe.

Wenn die Servoimpulse der verschiedenen RC-Kanäle gleichzeitig feuern, müßte mein Code geändert werden, um die Impulszeiten zu ermitteln.

@jurs: Der Oszi-Screenshot hat die Fehlerausgabe meines Skripts basierend auf der RCReceiver lib visualisiert.
Es wird gezeigt, daß recht regelmäßig alle 20 bis 22 Signale ein Signalfehler detektiert wird.
Das Servosignal ist tatsächlich so wie von Dir gepostet, also die Pulse der einzelnen Kanäle sind alle schön hintereinander, ich habe das gerade eben an einem der Empfänger nochmal nachgemessen.

Gruß,

Tütenflieger.

@Willie1968
Ich habe nun nochmal bei meinem am 2.5. geposteten Skript die Servoaufrufe auskommentiert.
Wenn ich "myservo1.attach" und "myservo2.attach" auskommentiere, dann gibt es keine Fehlersignale beim Aufruf der RC Receiver Lib mehr. (und natürlich auch keine Servoausgabe =( ) Damit scheint das Problem wirklich in einem sich-beißen von lib Servo und der RC Receiver lib zu liegen.
Ich werde mal andere Servolibs suchen.

@jurs
Ich habe Deinen RC Receiver Auslese Code nun in meinen Code zur Lageregelung integriert: Es geht ! :grin:
Vielen Dank nochmal dafür!
Es dauerte ein Weilchen bis ich bemerkte, daß ich mit der Reihenfolge meiner Ausgangssignale aus dem RC Empfänger herumspielen musste. Die Kanäle 1 bis 6 liegen bei dem getesteten RC Empfänger nicht ihrer Kanalreihenfolge entsprechend zeitlich hintereinander, und eine geordnete Abfolge ist bei Dir ja Ausgangsbedingung.
Es zeigt sich, daß die zur Verfügung stehenden Zeitslots für ein Auslesen des Gyros via I2C und dem PID Regler reichen, aber nicht für eine Ansteuerung des LCD Displays. Wenn dieses aktiviert wurde, dann hagelte es Timeouts beim RC-Signalerfassen.
Als Workaround kann ich mit dem Abschalten des I2C LCDs im Fluge leben und mich nun endlich mehr um die Details der Lageregelung kümmern.
Perspektivisch werde ich mich entweder nach einer interruptbasierten Lösung umschauen müssen, da ich zumindest später unbedingt Daten auf eine SD Karte loggen möchte, und dies braucht auch seine Zeit.
Oder ich dekodiere das Servo-Summensignal.
Oder ich mache eine hardwaremäßige Trennung zwischen Datenerfassen und -berechnen, und ihrer Ausgabe auf SD-Karte und LCD mittels eines Doppelprozessorsystems (2 Stk. Pro Mini) mit serielle Verbindung zwischen den zwei 328ern µC.

Grüße,

Tütenflieger

Für sowas nimmt man besser den Mega- der hat nämlich mehr Interrupts.
War einer der Gründe, wieso ich den im Segway habe und nicht den UNO.
Da gehts nämlich...

Display kannst du vergessen, meins im Segway hab ich auch während der Fahrt nur statisch, das wird auch nur im Stand aktualisiert- wird beim Schreiben auf ne SD-Karte ähnlich sein.
Wie wärs mit ner I2C-EEPROM-Erweiterung? Das dürfte ausreichend schnell sein, und so viel wirste ja nicht mitloggen wollen. Billiger wirds auch...musst halt bisschen Speichermanagement betreiben...