Zu den grundlegenden Funktionen eines jeden Roboters gehört die Fortbewegung bzw. Bewegungen überhaupt. Beschränken wir uns auf die elektrische Antriebstechnik, so sind es vor allem die folgenden 4 Technologien, die dafür zum Einsatz kommen:
Die bürstenlosen DC-Motoren sind korrekterweise überhaupt keine Gleichstrommotoren, sondern Drehstromantriebe. Die Gleichspannung wird dabei in 3 phasenverschobene Wechselspannungen zerlegt. Intern haben wir es also mit einem gewöhnlichen Drehstrommotor zu tun, der nach außen wie ein Gleichstromtyp wirkt. Er benötigt ganz spezielle Motorcontroller. In diesem Tutorial werden wir uns auf die reinen DC-Motoren mit Kohlenbürsten und die Servoantriebe konzentrieren, weil diese im Böcker RoverROM-B3000 zum Einsatz kommen. In späteren Tutorial gehen wir dann auch auf die beiden anderen Technologien ein.
Gleichstrom-Motoren
Die reinen DC-Motoren sind als Antrieb besonders gut geeignet, weil ihre Drehzahl einfach über die Spannung eingestellt werden kann. Bei Drehstrommotoren kann dies nur über eine Änderung der Frequenz des Drehfeldes erreicht werden, was sehr aufwendig ist. Da die Drehzahlen meist im Bereich von mehreren 1000 Umdrehunge pro Minute liegen, werden DC-Antriebsmotoren in der Robotik in der Regel als Getriebemotor ausgeführt. Typische Übersetzungsverhältnisse sind 1:50 bis 1:100 mit denen sich Nutzdrehzahlen von ca. 100 bis 200 Umdrehungen erzielen lassen. Durch die recht starke Übersetzung erhöht sich natürlich auch das Drehmoment entscheidend.
Doch so einfach die Steuerung per Spannungseinstellung auch sein mag, wie lässt sich das mit einem Mikrocontroller erledigen? An den digitalen Ausgängen liegt ja entweder nur ein High-Pegel (in der Regel 5 oder 3,3 V) oder ein Low-Pegel mit 0 Volt. Einen integrierten D/A-Wandler mit analogen Ausgängen hat der Atmega328 ja nicht (und auch dann wäre noch eine Verstärkung und Stromwendung notwendig).
Doch es gibt einen recht simplen Trick, ein Verfahren, das wir Pulsweitenmodulation (PWM) nennen. Dabei geht man davon aus, dass viele elektrische Verbraucher so träge sind, das ein schnelles Ein- und Ausschalten nicht erkennbar ist. Das Ganze lässt sich am an einem Heizdraht erläutern.
Im Bild sehen Sie den Spannungsausgang des Controllers (blau) und die Temperatur, die sich am Heizelement einstellt. Während der Einschaltphase steigt die Temperatur an. Der Anstieg ist hier linear dargestellt, was in der Praxis nicht der Fall ist, aber zur Veranschaulichung ist diese Vereinfachung akzeptabel. In der Ausschaltphase sinkt die Temperatur wieder ab, allerdings nicht so stark wie im Anstieg, weil dort aktiv Energie hinzugefügt wird. In der 2. Anschaltphase steigt die Temperatur abermals, allerdings nicht mehr so stark, weil immer mehr Energie benötigt wird, um einen Anstieg zu erzielen. Nach einer Weile kommt es zum einem leichten Pendeln und wenn Sie wie im unteren Teil des Bild die Frequenz erhöhen, dann bleibt die Temperatur konstant.
Im Falle unseres Mikrocontrollers wäre der Maximalwert der Spannung z. B. 5 V. Exakt die gleiche Temperatur wie oben könnte man auch erreichen, wenn man eine kleinere Gleichspannung anlegen würde, die allerdings nicht ein- und ausgeschaltet würde. Da das gepulste Rechtecksignal die gleiche Wirkung (Effekt) hat, wie die geringere Gleichspannung sprechen wir von Effektivwert. Sind Ein- und Ausschaltphasen gleich lang ist der Effektivwert 50 % des Maximalwertes also 2,5 V.
Wir können nun durch die Variation des Tastverhältnisses jede beliebige Spannung zwischen 0 und dem Maximalwert einstellen, z. B. 3,75 V:
oder 0,5 V:
Jede beliebige Spannung ist allerdings nicht ganz korrekt, denn das hängt natürlich von der zeitlichen Auflösung ab.
Softwaremäßig lässt sich ein PWM-Signal ja sehr einfach realisieren, Sie müssen lediglich den entsprechenden Anschluss für eine bestimmte Zeit ein- und wieder ausschalten. Doch das Ganze hat einen nicht unerheblichen Nachteil. Stellen Sie sich vor, Sie haben das folgende Programm:
Wenn Sie damit zufrieden sind, lediglich an PIN1 ein Rechtecksignal auszugeben, wäre das Programm zufriedenstellend, aber in den meisten Fällen wollen Sie noch eine Reihe anderer Dinge erledigen. Stellen Sie sich vor, Sie würden das Programm erweitern, um einen 2. Pin anzusteuern. Die beiden Rechtecksignal nutzen Sie nun für die Anteuerung von zwei Motoren. Sie wollen aber auch noch diverse Sensoren abfragen. Wo tun Sie das? Wenn Sie es am Ende der loop-Schleife einfügen, verlängert sich die 2. Wartezeit je nachdem wie lang Ihr Programm ist. Damit ändert sich aber auch das Tastverhältnis und somit die Spannung am Motor. Kommt es gar zu längeren Abfragen oder Berechnungen, könnte der Motor stehen bleiben oder auf maximale Geschwindigkeit auflaufen, je nachdem wo sich der längere Programmteil befindet.
Tipp: Wenn es Sie interessiert, wie die Arduino-Funktion den PWM-Ausgang programmiert, können Sie sich das in der Quelldatei "wiring_analog.c" anschauen. Sie finden alle Arduino-Funktionen im Verzeichnis:
arduino_verzeichnis\hardware\arduino\cores\arduino
Motorsteuerung des RoverROM-B3000
Schauen wir uns jetzt aber konkret an, wie die Antriebe im RoverROM-B3000 gesteuert werden. Dazu werden wir ein kleines Programm schreiben, das unseren RoverROM-B3000 einfach vor und zurück fahren lässt. Wir haben 2 Motoren: rechts (M1) und links (M2). Für jeden Motor benötigen wir zwei Steueranschlüsse:
Richtung und Gechwindigkeit. Im Programmcode sieht das folgendermaßen aus:
Der Anschluss "dirM1" liegt in unserem Fall an Pin 4 und steuert die Richtung des rechten Motors, mit "speedM1" (Pin 5) stellen wir die Geschwindigkeit ein. Da wir die PWM-Funktion nutzen, können wir natürlich auch nur Anschlüsse für den Motorenantrieb einsetzen, die diese Funktion unterstützen. Analog gehen wir beim linken Motor vor. Dann definieren wir uns noch zwei Symbole "FORW" und "BACK", damit wir uns nicht immer daran erinnern müssen, ob nun 1 vorwärts oder rückwärts bedeutet.
Hinweis: Die Anschlüsse steuern natürlich nicht direkt die Motoren, sie steuern lediglich den integrierten Motorcontroller an, der die Signale verstärkt und auf den Motor leitet.
Wie schon im 1. Teil erläutert, brauchen wir am Anfang unseres Programm die setup()-Funktion, in der wir z. B. die Anschlüsse konfigurieren. Da alle Motorenanschlüsse Ausgänge sind, sieht die setup()-Funktion bei uns folgendermaßen aus:
Wenn wir die Geschwindigkeit ändern wollen, müssen wir für beide Motoren neue Werte eingeben und evtl. auch noch die Richtung ändern. Bei häufigen Änderungen wird das Ganze schnell unübersichtlich, deshalb schreiben wir uns eine eigene Ansteuerungsfunktion, die wir "MotorControl" nennen und die wie folgt aufgebaut ist:
Wir übergeben die 4 Parameter und setzen dann die entsprechenden Werte über die digitalWrite()- und analogWrite()-Funktionen. Durch diese Funktion reduzieren wir die Eingaben auf jeweils eine Zeile. Wir könnten die Funktion auch in eine eigene Bibliothek auslagern und dann über eine #include-Anweisung einbinden.
Am Anfang unserer Programm müssen wir die Funktion noch bekannt machen, das tun wir durch den Funktionsprototypen:
Und in der loop()-Schleife rufen wir dann die MotorControl-Funktion auf:
Der RoverROM B3000 fährt zunächst für 2 Sekunden mit mittlerer Geschwindigkeit (Werte von 0 bis 255) nach vorn, stoppt für 2 Sekunden und fährt dann sehr langsam rückwärts u.s.w. Beim Geschwindigkeitswert ist noch zu beachten, dass ein Gleichstrommotor natürlich nicht bei Werten direkt über 0 anfährt und linear bis 255 schneller wird. In der Regel setzt er sich erst bei Werten von ca. 30 bis 40 in Bewegung. Das hängt sehr stark vom Ladezustand der Batterien bzw. Akkus ab.
Auch Servo-Motoren benötigen PWM-Funktionen
Im Grunde handelt es sich bei DC-Motoren und Servo-Motoren nicht um unterschiedliche Technologien, sie unterscheiden sich nur durch die Beschaltung und Ansteuerung. Die reinen Antriebseinheiten bei einem Servo sind ebenfalls DC-Motoren. Meist werden Servos aber nicht für kontinuierliche Drehbewegungen eingesetzt, sondern lediglich zum Einstellen eines bestimmten Drehwinkels. Dabei gibt es Servos mit einem bestimmten Schwenkbereich (z. B. 90, 120, 180 aber auch 360 °) aber auch kontinuierlich drehende Typen. Letzere sind praktisch identisch mit den schon behandelten DC-Antrieben, benötigen aber ein anderes Steuersignal.
Im Gegensatz zum "normalen" PWM-Signal entscheidet hier die reale Impulsdauer. Liegt der Wert genau bei 1,5 ms so befindet sich der Servo im Ruhezustand bzw. der Mittelposition. Die Endwerte stellen die Pulslängen von 2 ms und 1 ms dar. Die Dauer Pulslänge + Leerzeit beträgt ca. 20 ms. Bei einem Servo mit 180 ° Schwenkbereich befindet sich der Antrieb bei einer Pulslänge von 1,5 ms genau bei 90 °, bei 2 ms sind es z. B. 0 ° und bei 1 ms 180 °. Bei kontinuierlich drehenden Servos wird die Geschwindigkeit durch die Pulslänge gesteuert. Ein Wert von 1,5 ms bedeutet Stillstand, bei einer 1 ms dreht der Motor mit maximaler Geschwindigkeit links bzw. rechts herum, bei 2 ms mit maximaler Geschwindigkeit in die Gegenrichtung.
Servomotoren haben in der Regel einen 3-poligen Anschluss (+V, GND, Steuersignal). Im Gegensatz zur DC-Steuerung dient das Signal selbst nicht zur Energieversorgung des Motors.
Um die Ansteuerung über ein PWM-Signal vorzunehmen können wir folgende Überlegungen anstellen:
Der komplette Zählbereich des PWM-Timers sind 20 ms, wählen wir einen 8-Bit-Timer würden diese 20 ms in 256 Schritten aufgelöst. Unser effektiver Steuerungsbereich liegt aber zwischen 1 und 2 ms, also nur 1 ms. Wenn uns für 20 ms 256 Schritte zur Verfügung stehen, können wir 1 ms lediglich in 12,8 Schritte unterteilen. Sie sollten also den 10-Bit- oder den 16-Bit-PWM-Timer im Atmega328 nutzen. Aber um diese Systemtiefen müssen wir uns in diesem Tutorial nicht kümmern, denn es geht ja um die Programmierung mit Arduino und dort gibt es eine eigene Bibliothek "Servo", die wir im Folgenden nutzen. Wir werden einfach einen Wert über die serielle Schnittstelle einlesen und dem Servo unseres RoverROM-B3000 übergeben:
Dazu binden wir die Bibliothek ein und instanziieren ein Objekt vom Typ "Servo". Desweiteren benötigen wir noch eine Variable "pos", in der wir die Position speichern. In der setup()-Funktion wird über die Objektmethode "attach" das Servosignal an den Pin 9 gelegt und außerdem die serielle Schnittstelle initialisiert.
In der loop()-Funktion fragen wird mit Serial.read die serielle Schnittstelle ab, wenn ein "n" eingegeben wurde, weiß das Programm, das nun ein neuer Positionswert folgt und liest diesen über "Serial.ParseInt()" ein. Danach übergibt er ihn an die Methode "write" der Servo-Instanz.
Laden Sie das Programm in Ihren RoverROM-B3000 und rufen Sie den "Serial Monitor" im Menü "Tools" auf.
Geben Sie jetzt unterschiedliche Werte zwischen 0 und 180 mit führendem "n" ein und der Servomotor des Abstandsscanners stellt sich genau in die gewünschte Richtung.
Im nächsten Tutorial werden wir und das Thema Encoder genauer anschauen.
Für weitere Informationen und Bestellungen des
RoverROM-B3000
Sie wollen Arduino-Profi werden? Dann ist unser Video Mikrocontroller-Lehrgang MC1 genau das Richtige für Sie!
Falls Sie Fragen zum Thema haben, wenden Sie sich einfach an uns.
Wir helfen Ihnen gern weiter!
Ihr Team von Böcker Systemelektronik
Hinweis: Unser Tutorialangebot wird in unregelmäßigen Abständen erweitert. Wenn Sie sofort über eine Neuerscheinung informiert werden möchten, tragen Sie sich bitte hier in unsere Benachrichtigungsliste "Tutorials" ein. Sie können diesen unverbindlichen Service jederzeit in Ihrem Kundenkonto oder per E-Mail wieder abbestellen.
Copyright © Böcker Systemelektronik