Servosteuerung über "Servo lib" macht keinen Muckser

Hallo,

mit Servos hatte ich mangels Bedarf noch nie experimentiert - bis gestern. Ein paar Billigservos vom Typ "Tower Pro SG90" hatte ich mir schon vor längerer Zeit besorgt - diese sind eigentlich recht weit verbreitet und im Modellbau nicht nur für Spielereien eingesetzt.

Rot an Vcc, Braun an GND und gelb als Steuerleitung (PWM Pin 11) - das sollte eigentlich passen. Der Servo ist an eine externe 5V-Spannungsversorgung angeschlossen, für gemeinsame Masse mit dem Arduino ist gesorgt.

Für einen ersten Test habe ich aus den beiden Examples der Servolib "sweep" gewählt:

// Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.

#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int pos = 0;    // variable to store the servo position 
 
void setup() { 
  myservo.attach(11);  // attaches the servo on pin 11 to the servo object 
} 
 
void loop() { 
  for(pos = 0; pos < 180; pos += 1)  { // goes from 0 degrees to 180 degrees in steps of 1 degree 
    myservo.write(pos);                    // tell servo to go to position in variable 'pos' 
    delay(15);                                   // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1) {    // goes from 180 degrees to 0 degrees 
    myservo.write(pos);                   // tell servo to go to position in variable 'pos' 
    delay(15);                                  // waits 15ms for the servo to reach the position 
  } 
}

Der Servo reagiert auf diesen Code seltsamerweise überhaupt nicht. Ich habe auch den Servo ausgetauscht und andere PWM-Ports probiert - dasselbe Ergebnis.

Lasse ich die Servo-Bibliothek weg und spreche den Servo einfach mit z.B. "analogWrite(11, 100)" an, dreht er nach rechts und hängt an der Endposition, die Stromaufnahme steigt auf ca. 500 mA. Ändere ich "100" in z.B. "50" oder "150", ändert sich eigentlich nichts, er dreht immer in die gleiche Richtung bis zum Endanschlag.
Ich stecke ihn dann auch schnell ab, um Schäden (hoffentlich) zu vermeiden und drehe ihn per Hand wieder in die Mittenposition. Dasselbe Verhalten gibt es auch mit den beiden anderen, neuen Servos.

Wie gesagt, sehr seltsam finde ich, daß bei Verwendung der Servo-Lib gar nichts passiert. Ich habe auch schon einen anderen Arduino angeschlossen - gleiches Verhalten, ebenso erfolglos.

Habe ich da eine Serie kaputter Servos erwischt ??

Gruß, mmi.

Ich frage mich jedes mal, wer die Geschichte in die Welt gesetzt hat, dass Servos mit einer PWM angesteuert werden...

Ok, das dachte ich bis jetzt auch - frag mich nicht warum. :wink:
Hast Du einen guten Link, um mein (Fehl-)Wissen zu korrigieren ?

Hab's gefunden - mit PWM via analogWrite kann es so einfach nicht klappen.

Zitat:
Die Servos aus dem Modellbau steuert man ja idR. über die Länge eines
High-Pulses, meist zw. 1 und 2ms alle 20ms, .5ms ist dabei die
Mittelstellung.

Jetzt habe ich es auch begriffen. :wink:

Bleibt mein Problem, warum es mit der Servo-Lib nicht funktioniert.

Na geht doch. :wink: Ich denke, das Datenblatt zu deinen Servos dürfte der erste Ansatzpunkt sein. Eventuell ergeben sich aus den Angaben dort Abweichungen vom Standard-Timing.

1,5mS ist die Mittelstellung.
Die Lösung Deines Problems weiß ich auch nicht.
Du scheinst alles richtig zu machen.
Grüße Uwe

Wenn man sich auf die Schnelle informiert, ist's manchmal schon schwierig, die Spreu vom Weizen zu trennen - ich hätte gleich Euch fragen sollen, aber nachdem es im engl. Forum einen ausgiebigen thread dazu gab, wo einer beharrlich "analogWrite" verwendet - da meint man schnell, es ist normales PWM. :frowning:

Man sieht auch einige Schaltpläne, wo der Servo direkt über 5V am Arduino versorgt wird - vermutlich auch nicht unbedingt empfehlenswert.

Ein ausführliches Datenblatt habe ich auch auf der Seite des Herstellers zu diesem Typ nicht finden können, aber mit 1ms < 1.5ms > 2 ms sollte man kaum falsch liegen.

Danke Euch für die Tipps !

Mit der servo library wird der Fehler dann wohl softwareseitig zu suchen sein, da habe ich oft die neueste Version des avr-gcc, möglicherweise läuft da was schief.

Gruß, mmi.

Also bei mir funktionierte die Servo-Library ausnahmslos immer und sie macht ja auch nicht viel, was Fehlverhalten hervorrufen könnte. Probier doch mal, den Servo manuell anzusteuern, eben ohne Bibliothek und die (angenommenen) Timings per delay testen.

Habe ich mir für heute abend vorgenommen - da sollte für den groben Test ein "digitalWrite" mit entsprechendem "delay" genügen.

mmi:
Habe ich mir für heute abend vorgenommen - da sollte für den groben Test ein "digitalWrite" mit entsprechendem "delay" genügen.

Ja genügt. vieleicht besser Du mimmst http://arduino.cc/en/Reference/DelayMicroseconds

Grüße Uwe

Gängig ist für die Servostellung am linken Anschlag 1ms, also die kürzeste Zeitspanne, die mit delay möglich ist. Sollte für einen Test eigentlich reichen. Aber weil wir ja schon über möglichen Abweichungen von der Standardansteuerung sprachen, kann man Uwes Vorschlag durchaus einbinden.
Probiere die 1 ms (HIGH) vorerst mit 19ms Pause (LOW), gem. Wikipedia sind die 20 ms (entspricht 50Hz) zwar nicht kritisch, aber immerhin eine Grundlage. :wink:

Beispiel:

void setup() {
  pinMode(12, OUTPUT);
}

void loop() {
  digitalWrite(12,HIGH);
  delayMicroseconds(1000);
  digitalWrite(12,LOW);
  delayMicroseconds(19000);
}

Servo fährt mit dieser Routine nach rechts bis zum Anschlag, dasselbe auch, wenn ich 2000/18000 verwende - also immer nach rechts.

Das sei jetzt aber erstmal egal, denn es wird skurriler, irgendwas ist mit meinem Duemilanove faul, denn die delays werden nicht korrekt ausgeführt.

Habe deshalb alles abgesteckt und will nur die LED an Pin 13 mit delay(4000), also im 4 Sek.-Rhythmus blinken lassen. Sie blinkt aber recht exakt im 1 sek. Rhythmus - die delays sind 4x schneller als codiert! Sonst geht aber alles wie gewohnt, auch die Baudraten über die Serielle.

Habe der Einfachheit halber den Prozessor ausgetauscht: gleiches Ergebnis. Was kann da die Ursache sein ? Läuft der etwa nur noch mit 4 Mhz ?

Habe deshalb alles abgesteckt und will nur die LED an Pin 13 mit delay(4000), also im 4 Sek.-Rhythmus blinken lassen. Sie blinkt aber recht exakt im 1 sek. Rhythmus

Hmm, aber wenn Du ein "delay(16000) einstellst, sind es dann tatsächlich 4 Sekunden? Ansonsten würde ich fast darauf tippen, das der "normale" Blink-Sketch auf dem Board läuft.

Nene, der originale sketch ist das nicht, der ist schon lange über Bord gegangen - es liefen ja alle meine Servoversuche vorher.

Bei 16000 werden es in der Tat 4 Sek.

Der Servo hat jetzt erstmal Zwangspause.

Mit dem Duemilanove und der Blinkzeitdauer habe ich folgendes festgestellt:

  • "Burn Bootloader": Fuses und Bootloader über ISP mit AVR MKII neu geflasht
  • siehe da: jetzt stimmt das delay, auch nach mehreren resets mit reset button
  • Programmer abgeklemmt, selbes Programm über USB neu geladen
  • wieder derselbe Fehler (delay 4x so schnell)

Diese Prozedur mit anderem Prozessor wiederholt, gleiches Ergebnis.

Dazu wäre noch zu sagen, daß ich auf diesem Arduino vor dem Servo ein RTC shield von ELV im Einsatz hatte. Dieses kam mit einer falsch eingebauten Transildiode, die eigentlich evtl. auftretende Spannungsspitzen nach Masse ableiten sollte. So trat aber generell ein kurzschlußähnlicher Zustand auf, den ich erst nach mehreren Minuten bemerkte. Clock-IC war sehr heiß (ging aber nicht kaputt). Ich vermute mal, daß diese erhöhte Stromaufnahme (Shield läuft mit 3.3 V) doch irgendwas auf dem Arduinoboard in Mitleidenschaft gezogen hat. Das ist aber eine andere Baustelle, ich muß mir jetzt erst einen Clone zusammenlöten und melde mich dann demnächst zum Servothema nochmal.

Die Chancen stehen gut, daß dann auch die Servolib es tut :slight_smile:

Arduino Duemilanove ist soweit ok, Spannungsversorgung und Taktfrequenz sind stabil.

Das von mir vorher Beschriebene mit "4x so schnell" vergesst bitte - das waren durch ungünstige Pinwahl Clocksignale vom gleichzeitig über ISP angesteckten Programmer, sorry. :frowning:

Weiter auf der Fehlersuche mit dem Oszi, es läuft folgendes simple Programm:

void setup() {
  pinMode(7, OUTPUT);

  START:
   digitalWrite(7,HIGH);
   delayMicroseconds(1000);
   digitalWrite(7,LOW);
   delay(1);  // für Servotest soll es 19 sein, bitte aber erst weiterlesen
  goto START;
}

void loop {
}

/*
Bitte nicht schreiben, daß die Routine ohne "goto" genauso gut in die "loop" gepasst hätte.
Ich wollte nur absolut sicher sein, daß der Compiler auch wirklich
nur ein "jump" im Maschinencode generiert.
*/

Das Ergebnis:

9 Perioden laufen absolut korrekt, dann kommt kurioserweise eine ca. 80ms lange Pause, für einen Mikrocontroller recht lang. Dieses Muster wiederholt sich dann endlos.

Würde ich, passend für den Servo, die 2. Pause mit 19ms setzen, so gibt es nur eine korrekte Periode, anschliessend wieder die lange "Pause".

Eine Erklärung wäre, daß der Prozessor wohl etwas besseres zu tun hat - normalerweise wären es entsprechende Interruptroutinen - aber mit so langer Dauer und welche überhaupt? Oder sleep Modi bzw. watchdog - aber wer hätte die dann aktiviert? Sehr seltsam.

Sehr merkwürdig.

Der letzte Puls fällt deutlich langsamer ab, als hätte sich dein Pin in einen hochohmigen Zustand geschaltet. Bekommt dein Arduino vielleicht alle 100ms ein Reset durch einen Programmer oder unsaubere Spannungsversorgung?

Nein, läuft "standalone" - nichts externes mehr dran. Als Spannungsversorgung habe ich auch schon verschiedene probiert, oben hängt er an einem Labornetzteil mit max. 3A Leistung. Spannung sieht auf dem Oszi auch absolut sauber aus.
Deine Idee mit dem wiederkehrenden "reset" würde auf den ersten Blick aber gut zu dem Verhalten passen, mal sehen, wie ich das am besten feststellen kann.

Anmerken will ich noch, daß ich jetzt mit dem Oszi auch das Signal nach Aufruf über die Servolib angesehen habe, aber da kommt unverändert gar nichts - es bleibt immer LOW. Ich gehe davon aus, daß ein "attachInterrupt" und "Servo.write" im Setup für den Test genügt, der refresh also durch die lib automatisch erledigt wird.

Hast Du den watchdog aktiviert?
Was siehst Du am Pin wenn du es nur HIGH setzst?

void setup() {
  pinMode(7, OUTPUT);
  digitalWrite(7,HIGH);
 }
void loop {
}

grüße Uwe

Hallo Uwe,

nach etlichen Stunden habe ich gerade wieder eingeschaltet. Jetzt kommen die 9 Perioden nur noch einmal nach dem Einschalten, dann bleibt dauerhaft alles LOW. Nach Reset dasselbe.

Watchdog o.ä. habe ich nicht gesetzt, es ist alles sehr jungfräulich:
Neuen ATmega328 eingesetzt -> "Burn Bootloader" für DUEMILANOVE mit AVR ISP MKII -> "Upload using Programmer"
Vor jedem Test Programmer abgesteckt, nur Oszi hängt an Pin 7 und GND.
Alles so einfach wie möglich gehalten.

Setze ich nach Deinem Vorschlag Pin7 dauerhaft auf HIGH, dann ist alles bestens, das mag "er" :slight_smile:
... und dauerhaft LOW mag er auch.

EDIT:
Am Resetpin geht das Signal nur auf LOW, wenn die Resettaste gedrückt wird. Würde man einen internen Reset z.B. durch Watchdog hier auch sehen ?