Servo-Motor-Ansteuerung mit dem Arduino und einem Multi Function Shield

Das Multi Function Shield, das ich ja bereits vorgestellt habe, bietet mit der Möglichkeit zur einfachen Anzeige von Daten auf seinem 4-fach-7-Segment-Display und den freien Anschlusspins eine gute Grundlage, Sensoren ausprobieren.

Heute soll mit dem MFS und einem Servomotor SG90 der Umgang mit einem Servomotor gezeigt werden.

Servomotor SG90


Ein gewöhnlicher Elektromotor dreht sich, sobald Strom anliegt und hört mit dem Drehen auf, wenn der Strom wieder aufhört, eventuell dreht er aufgrund Trägheit noch ein Stückchen nach. Eine exakte Positionierung, z. B. eine exakte 90°-Drehung ist mit diesen nicht zu bewerkstelligen. Für so etwas braucht man einen Schrittmotor oder eben einen Servo-Motor.

Ein Servo-Motor hat gegenüber dem Schrittmotor allerdings den Nachteil, dass er meist nur einen begrenzten Aktionsradius von 0 bis 180 Grad hat, während sich ein Schrittmotor frei und mehrmals um 360° drehen kann. Dafür ist ein Servo leichter, schneller und stromsparender, wenn auch nicht ganz so präzise.

Zudem geschieht die Ansteuerung eines Servos ganz anders, nämlich indem die gewünschte Gradzahl per Puls-Verfahren an den Servo übertragen wird. Dabei wird eine Zeitspanne von 20 ms in zwei Teile aufgeteilt. Einen High-Teil für die geünschte Gradzahl: zwischen 1 (0°) und 2 ms (180°) und einen Low-Teil, der die 20 ms auffüllt.


Im Servo ist an der Achse ein Potentiometer verbaut, das mit der Position den Widerstand ändert. Eine Steuerungselektronik im Servo misst diesen Widerstand fortwährend, weiß, an welcher Position sich der Servoarm befindet und korrigiert diese dann in Richtung der neu übermittelten Position. Dies tut er solange, wie das 20ms-Steuersignal anliegt und die Position noch nicht erreicht ist. Wird das 20ms-Steuersignal dann noch weiter gesendet, erfolgen weitere Korrekturen, die sich durch ein Zittern des Servoarms zeigen, denn die Widerstandsmessung und Positionierung ist nicht hunderprozentig exakt wie bei Schrittmotor.

Servomototen werden gerne im Modellbau eingesetzt, um sie z. B. bei Funkfernsteuerung zu befehligen und dann Dinge wie Bremsenzug, Gaszug, oder Lenkung zu betreiben. Winkel größer 180° sind für diese Anwendungen auch gar nicht nötig.

Die Technisches Daten des SG90 sind:
Die Anschlüsse des SG90 sind: Das 3-polige Kabel kann mit dem braunen Kabel nach links in die oberste Reihe des 3x4-Pin-Headers des Multi Function Shields bei "~5" gesteckt werden.



Laut Datenblatt soll die Duty Cycle in der PWM-Zeitspanne von 20ms zwischen 1 ms (ganz links) und 2 ms (ganz rechts) betragen, aber das führte nur zu einer Bewegung von 90° statt 180°. Eher passen 0.5 ms bis 2.2 ms.

Durch Experimentieren bin ich für meinen SG90, der übrigens ein wenig mehr als in der 180°-Spanne positionieren kann, auf folgende Formel gekommen, die bei 0°, 90° und 180° rechtwinklig zueinander positioniert: pulse = (degrees/.105) + 460.

Software

Die Standard-Library für die Verwendung mit Servos ist normalerweise die Servo.h, doch dummerweise funktionierte mit dieser die 4-fach-7-Segment-Anzeige und die Taster des MFS nicht mehr richtig.

Darum habe ich die PWM selbst per Software emuliert, was den Vorteil hat, dass dies einwandfrei mit dem MFS zusammen läuft und genauer positioniert als mit der Servo-Library. Außerdem kann man die Parameter verändern und so an andere SG90 anpassen, sollten die sich evtl. nicht alle komplett gleich verhalten.

Trotzdem darf man sich nichts vormachen: so genau wie ein Schrittmotor ist ein Servo nicht; es gibt aber noch ein weites Anwendungsgebiet, in dem Servos sinnvoll sind.

Programm

Das Testprogramm wartet auf die Betätigung einer der drei Taster. Der linke Taste fährt den Servoarm ganz nach links, der mittlere Taster positioniert den Arm bei 90°, also mittig und der rechte Taste fährt den Arm ganz nach rechts.

Wobei ich dabei davon ausgehe, dass der Servoarm nach vorne (von einem weg) gerichtet ist. Sollen sich die Gradzahlen auf einen zu einem hin zeigenden Servoarm gemeint sein, so muss die entsprechende Zeile auskommentiert werden.



Source-Code

//////////////////////////////////////////////////////// // (C) 2018 by Oliver Kuhlemann // // Bei Verwendung freue ich mich über Namensnennung, // // Quellenangabe und Verlinkung // // Quelle: http://cool-web.de/arduino/ // //////////////////////////////////////////////////////// #include <TimerOne.h> // für Timings und Interrupts #include <MultiFuncShield.h> // API für das Multi Function Shield #define PinServo 5 int degreesBefore=-1; void servoMove (uint8_t degrees) { if (degrees < 0) degrees = 0; if (degrees > 180) degrees = 180; degrees = 180 - degrees; // Zeile herausnehmen, um Richtung umzukehren float pulse = (degrees/.105) + 460. ; // passt gut für meinen SG90 int steps = 100; if (degreesBefore >= 0) { steps = abs(degreesBefore-degrees)/2+15; } degreesBefore=degrees; for (int i = 0; i < steps; i++) { digitalWrite(PinServo,1); delayMicroseconds(pulse); digitalWrite(PinServo,0); delayMicroseconds(20000-pulse); } } void setup() { Timer1.initialize(); // TimerOne initialisieren MFS.initialize(&Timer1); // Multi Function Shield initialisieren MFS.write("serv"); pinMode(PinServo,OUTPUT); } void loop() { byte btn = MFS.getButton(); if (btn == BUTTON_1_PRESSED) { MFS.beep(1); MFS.write(0); servoMove(0); } else if (btn == BUTTON_2_PRESSED) { MFS.beep(1); MFS.write(90); servoMove(90); } else if (btn == BUTTON_3_PRESSED) { MFS.beep(1); MFS.write(180); servoMove(180); } delay(100); }