Servo zappelt (mit Servo-Lib)

... nur unter bestimmten Umständen !

Nach dem ich meine gute alte Robbe FX-18 nun auslesen kann (RC-Steuerung - PPM-Signal auslesen - #3 by TERWI - Deutsch - Arduino Forum),
wollte ich "eben mal schnell" auch mit in dem Sketch einige Servos mitlaufen lassen.
Entsprechende Code habe ich mir aus nem anderen Testsketch hier geholt, mit dem ich schon erfolgreich (zappelfrei) dies und das getetet habe.

Sobald ich auch nur einen Servo initialisiere, geht das Gezappel los: Der Servo schüttelt sich mit geschätzt 20 Hz.
Laufen tut er aber trotzdem, wenn ich ihn von der Fernsteuerung bediene.

Als Timer hab ich in o.g. Sketch mal auf 4 gewechselt, damit sich das nicht mit dem zuerst initialisiertem Timer5 der Servo-Lib stört.
Der Interrupt-Eingang ist dann ICP4 auf Pin 49 (am Mega).
Das funzt ja so weit auch ....

Nun jabe ich im Sketch alles Stück für Stück auskommentiert, so das die Loop leer läuft und aktiv nur noch 1 Servo initialisiert wird.
Sonst passiert nichts weiter ..... aber der Servo zappelt nach wie vor in Mittelstellung.

In der Servo-Lib hab ich bis auf Timer5 alles andere auskommentiert - keine Änderung.

Dieses Phänomen verschwindet erst, wenn ich meine Fersteuerung ausschalte !
Sprich es kommen kein Signal mehr auf Pin 49 (der eh nicht mehr gelesen wird).

Was geht hier vor sich ? Hilfe bitte.

Wie genau ist denn das Servo mit dem Arduino verbunden?
Ich habe die Vermutung du verwechselst da was, PPM und PWM, beides mit RC zu tun, aber funktionieren hier unterschiedlich.

Nein, ich verwechsle da sicher nichts.

Das PPM-Signal (also das kombinierte Signal der Fersteuerung mit 8-Kanälen) lese ich mit o.g. Sketch aus.
Ich verwende Timer4 mit 0,5µs Auflösung und triggere mit der steigenden Fklanke den Timer am Pin ICP4 der Mega.
Das funktioniert ja auch 1A.

Zum Steuern der Servo's (mit einem PWM-Signla) benutze ich die handelsübliche Servo-Lib.
Das hatte ich vorab in einem anderen Sketch ausgiebig betreff Timings für max. Werte bei verschiedenen Servos ausbrobiert.
Die Servos werden direkt aus dem Mega gesteuert, haben aber eine separate Versorgung aus einem Akku.
Das zappelt nix oder ist irgendwie unruhig.
Auch das funktioniert 1A.

Bringe ich nun beide Sketche zusammen entsteht eben der genannte Effekt.

Ich habe das eben auch noch mal nur mit dem Servo-Sketch alleine ausprobiert.
Motoren lassen sich sauber fahren, aber:
Sobalb ich die Fernsteuerung einschalte und es werden PPM-Signale an Pin 49 gesendet, geht das Gezappel los !

Was stört da wen und warum ?

Nachtrag:
Gleiches Verhalten, wenn ich auf ICP5 / Pin 48 umstecke.
Ich definiere (im Servo-Sketch) keinen dieser Pins als Eingänge !

Zeig doch mal den Sketch, viele Augen sehen mehr als 2 :smiley:

Das ist sicherlich vollkommen richtig, aber es hat ganz offensichtlich nichts mit dem Sketch zu tun.
Ich kann auch die Demo der Servo-Lib namens "sweep" (http://arduino.cc/en/Tutorial/Sweep) nehmen.

So bald das PPM Signal an Pin 48 oder 49 des Mega anliegt, wird gezappelt !

Da muss irgendwas, was eigentlich direkt zum Timer4 / 5 gehört, den Dino sonstwie mächtig aus dem Tritt bringen.
Nur was ?

Wie gesagt:
Die Servo-Lib scheint ja alles verfügbare an Timer zu nutzen was geht.
Ich habe explizit alles bis auf Timer5 (auch mal nur Timer3) ausmarkiert und in Setup jeweils mit

#if defined (_useTimerX)
Serial.println(F("- Timer used: X"));
#endif

geprüft, welcher genutzt wird.

Es zappelt.

Keiner eine Idee ?

Ja, natürlich hängt die "am Draht" dran. Siehe: RC-Steuerung - PPM-Signal auslesen - #3 by TERWI - Deutsch - Arduino Forum
Ich nehme das Signal aus der Schüler-/Lehrer-Buchse ab.
Es sind ca. 2m geschirmte Leitung dran.
Einstrahlen tut da nix - jedenfalls zappelts nicht mehr, wenn ich den Kollektor des Transistors am Ende der Leitung vor dem Eingang 48 oder 49 abnehme.

Das muss irgendwas internes im / mit dem Arduino sein ....

Ich hab dieses Prob mal im internationalen Forum eingestellt und nach nur ca. einer halben Stunde hat mir Grumpy_Mike ein Lichtlein aufgehen lassen.

Ganz offensichtlich treten sich hier 2 Interrupts gegenseitig auf die Füße - also ein Timing-Problem !

Jetzt, wo ich mit der Nase darauf gestossen wurde, kann ich es sogar sehen:
Jedesmal, wenn die ISR für das PPM-Signal "fertiggesampled" hat und Werte ausgibt, wird ja auch der Motor angesteuert, bzw. mache ich div Serial.print's.
Der Takt der LED auf dem Bord ist genau die "Zappelfrequenz". Alle ~67ms neue Werte =>> also etwa 15Hz.
.... wobei das ganze aber offensichtlich nichts mit der Ausgabe via Seriell zu tun hat, denn es jittert weiter auch wenn ich das alles auskommentiere.

Um nun sicher zu gehen, dass das nicht nur allein mit Interrupt-Compare eines Timers in diesem speziellen Fall zusammenhängt, habe ich mal die alte Auswerte-Routine genommen wo ich mit ** attachInterrupt(0, EvalPPM, RISING); ** die Signal auswerte und die Zeiten mittels micros() ermittle.
-> Das gleiche in grün, es reicht auch hier wieder nur das anschießen des PPM-Signal auch wenn attachinterrupt auskommentiert ist.

Watt'n schietkroam würde der Norddeutsche nun sagen. :~

Interessanterweise fühlt sich aber offensichtlich nur die Servo-Lib dadurch gestört.
Den internen Timer scheint das nicht zu beeindrucken, gibt er mir die mircros() ganz offensichtlich korrekt aus.

Was tun sprach Zeus.
Hat jemand "auf die schnelle" eine Idee / Vorschläge, wie man Servos auch anders steuern kann, bevor ich hier div. Räder neu erfinde ? :roll_eyes:

Drum nehm ich grundsätzlich nur den hier: http://www.watterott.com/de/Micro-Maestro-6-Channel-USB-Servo-Controller-Assembled
Da braucht mein Arduino nur die Kommandos geben (seriell) und muss sich ansonsten um nichts kümmern. Hat einstellbare Geschwindigkeit und Ramping und kann sogar vom PC gesteuert werden. In der großen Ausführung lassen sich 24 Servos gleichzeitig steuern, wobei bis zu 127 Controller miteinander verkettet werden können (= 3048 Servos :astonished: ).

Hmmmm ..... das wäre sicherlicherlich eine sehr elegante Lösung.
Macht dann aber in meinem Fall für einen 12-Kanal-Controller mit Versand schon wieder schlappe 31 Taler.
Treibt mich nich zwingend in den Ruin, aber ....

Das muss doch auch "so" gehen ?
Fände ich sehr betrüblich, wenn ein Arduino nur mit einem IR zur Zeit umgehen kann.
Was mein "HELUINO"-Projekt betrifft:
Da nimmt zwar der Senderseitige Dino die Signale auf und hat eigentlich so weiter mit nichts zeitkritischem zu kämpfen.
Alle weiter wird in der Loop ermitelt und ist nicht zeitkritisch.
Allerdings kommen zu nicht definierbaren Zeiten Daten über den Telemetrie-Transceiver (NRF24L01) und das geht auch via Interrupt.
Das könnte man auch noch ändern.

Aber:
Auf der Enpfängerseite im Heli passiert ähnliches.
Ich sende ja kontinuierlich Daten für die Servos und das geht auch via Interrupt. Auch das lässt sich nötigenfalls ändern.
Allerdings hätte ich auch gerne die Ist-Rotordrehzahl gewusst und wie soll ich die genau ohne ISR ermitteln ?
Zeiten sind hier ähnlich mit 800-1800 U/Min = alle ca. 77 bis 38ms ein "Tick".
Dazu käme noch bei Bedarf die Auswertung eines Ultraschallsignals für den Bodenabstand ...

Ich kann doch nicht 2 Dino's in den Flieger bauen, nur weil der eine ein Zeitproblem hat .....

Reicht es vielleicht wenn du während der kritischen ISR die Interrupts deaktivierst so dass die Routine nicht unterbrochen werden kann? Wenn in der Zeit ein anderes Interrupt-Flag gesetzt wird wird das glaube ich nach der Re-Aktivierung abgearbeitet.

Gute Frage ! Welchen wann ?
Dazu müsste ich erst mal kapieren, wie die Servo-Lib eigentlich arbeitet.
Ich werde das mal auf einen Timer ausdünnen und zerpflücken. Vielleicht kommt ja noch ein Lichtlein ....

Ich habe mir mal die Servo Lib angesehen. Welcher Timer da verwendet ist unterschiedlich. Aber alle Timer-ISRs rufen letztendlich die Methode handle_interrupts(...) auf. Die steht am Anfang als erstes nach den defines.

Mach da mal cli() am Anfang und sei() am Ende. Die Arduino-Funktionen noInterrupts() und interrupts() sollten da auch gehen, aber die werden das nur kapseln.

Schade, schade, schade ... kein Hauptgewinn. Sprich: Keine Änderung.

Noch mal zur Erinnerung:
Dieses "Servo-Zappeln" tritt ja auch auf, wenn ich nur allein die Servo-Lib einbinde, einen Servo instanziere - also mit attach einen Pin zuweise.
Da muss ich nicht mal eine write() oder writemicroseconds() ablassen, das zappelt auch so !

Für mich absolut unverständlich, da hier der In-Pin für das PPM-Signal (sonst mit attachInterrupt(0, EvalPPM, RISING); oder auf einen ICP) in keiner Weise zugewiesen wurde.
D.h., es sollte den Dino nicht scheren, was sich da an Pin 12 oder 49 tut - tut es aber offensichtlich doch.

Und wer nun denkt: Ah, es hängt vielleicht mit einem Interruptbezogenem Eingang zusammen ..... der irrt ebenfalls: Das macht der an jedem Pin ! Auch über 22.

Ich krieg das echt nicht auf den Schirm.
Ist das ein Hardwarefehler ?

Eigene Antwort: Wahrscheinlich nicht.

Nach dem Vorschlag von MaFu, vielleicht einen eigenständigen Servo-Controller zu nehmen, hab ich da vorhin mal ein wenig herumgesucht, was es so alles sonst noch gibt.
Dabei bin ich u.a. in der Bucht auf haufenweise MultiWii Flight-Controller gestoßen.
Dazu gab es dann auch mal einen Link zu einem "Manual":

Auf Seite 3 kann man dort lesen, das man entweder seinen RC-Empfänger kanalweise oder sogar direkt via PPM anschließen kann. AHA !
Dazu passen dann noch 8 Motorsteuerungen und bis zu 5 Servos dran.
Alles mit einem ATmega 32U4 .... der sich wie ein Leo ansprechen lässt.
MultiWii drauf und abheben.
Sososo !

Also muss das doch irgendwie funktionieren ! Nur wie ?
Ich werde mir mal den MutiWii-Code im Detail reinziehen. (Uff)

Für ungeduldige Leser sei vorweg gesagt: ES ZAPPELT IMMER NOCH !.
Es ist zum Haare raufen ......

Ich habe mir dieser Tage mal ein paar INO's vom MultWii reingespannt.
Die Leseroutine des PPM-Signals machen die genau wie ich (ich hab nicht abgeguckt !). Einfach ein attachinterrupt() und die micros() ausgewertet. Also nix besonderes.

Zum Betreiben der ESC/Servos gibt es einen Mix aus "direkt schreiben" oder ala Servo-Lib mit umgedängelten Pins.
Da das mit der Servo-Lib ja hier nicht läuft, weil eine zusätzliche ISR möglicherweise durch die PPM-ISR gestört wird, habe ich mir gedacht, nimmst du halt alle freien Timer des MEGA und machst dir 9 Servokanäle max. mit Fast-PPM auf Hardware-Basis.
In etwa so:
(diesmal richtig !)

void setup()
{
  .....
  // Setup pins & timer for servos
  pinMode(3,OUTPUT);   // timer 3 channel A
  pinMode(2,OUTPUT);   // timer 3 channel B
  pinMode(5,OUTPUT);   // timer 3 channel C
  pinMode(6,OUTPUT);   // timer 4 channel A
  pinMode(7,OUTPUT);   // timer 4 channel B
  pinMode(8,OUTPUT);   // timer 4 channel C
  pinMode(46,OUTPUT);  // timer 5 channel A
  pinMode(45,OUTPUT);  // timer 5 channel B
  pinMode(44,OUTPUT);  // timer 5 channel C

  // ATMEL Doku MEGA: http://www.atmel.com/images/doc2549.pdf 
  // 17.9 Modes of Operation, Seite 148 ff
  // ! ! ! http://www.mikrocontroller.net/topic/177721 ! ! !
  
  // Modus 14: Fast PWM - Steuerung des Ausgangsport: Set at BOTTOM, Clear at match (Tabelle 17.2)
  //           -> WGMn1, WGMn2, WGMn3
  // PreScaler: clk/8 -> CSn1 -> "Tick" = 0.5µs (alle ICR-/OCR-Werte x 2 !!!)
  // Zu setzen in TCCRxA: COMnA1, COMnB1, COMnC1 für alle 3 Compare-Out-Pins
  //                      WGMn1
  // Zu setzen in TCCRxB: WGMn2, WGMn3, CSn1
  // Zu setzen ICRn: 40000 für Wiederholfrequenz 50Hz 20ms (6666/150Hz, 3333/300Hz)
  // Zu setzen OCRnA/B/C: PPM-Signal x 2 (angepasst mit map für min./max. Servoweg)

  rep_rate = 40000; // div 2 = 20000 µs = 20 ms = 50 Hz
  val_mid = 3000; // div 2 = 1500 µs = 1,5 ms = Servo-Mittelstellung

  // init 16bit timer 3 - connect pin 5, 2, 3
  TCCR3A = (1<<COM3A1) | (1<<COM3B1) | (1<<COM3C1) | (1<<WGM31);      
  TCCR3B = (1<<WGM33)  | (1<<WGM32)  | (1<<CS31); 
  ICR3   = rep_rate;
  OCR3A  = OCR3B = OCR3C = val_mid;
  // init 16bit timer 4 - connect pin 6, 7, 8
  TCCR4A = (1<<COM4A1) | (1<<COM4B1) | (1<<COM4C1) | (1<<WGM41);      
  TCCR4B = (1<<WGM43)  | (1<<WGM42)  | (1<<CS41); 
  ICR4   = rep_rate;
  OCR4A  = OCR4B = OCR4C = val_mid;
  // init 16bit timer 5 - connect pin 46, 45, 44
  TCCR5A = (1<<COM5A1) | (1<<COM5B1) | (1<<COM5C1) | (1<<WGM51);      
  TCCR5B = (1<<WGM53)  | (1<<WGM52)  | (1<<CS51); 
  ICR5   = rep_rate;
  OCR5A  = OCR5B = OCR5C = val_mid;
}

Die Pulsbreite wird dann in der Loop mit jeweils anderen Werten für OCRnA/B/C gesetzt.
Das funktioniert wie ne "1", wenn man z.B. mit nem Poti Werte vorgibt und die passend mit map() aufbereitet.

Aber ...........
Wie oben schon gesagt: Kommt das PPM-Signal hinzu, ist wieder Ende im Gelände !
... der/die Servos zappel wieder.
HEUL. :~

Hat das doch was mit der Hardware zu tun ?