Im vorigen Kursbeitrag haben wir uns angesehen, wie man einen Seriellen Monitor verwendet, um die Farben einer RGB-LED zu steuern. Heute lernen wir, wie man Servos (oder Servomotoren) mit Hilfe eines Potentiometers steuern kann. Mit diesem Wissen können wir lernen, einen bestimmten Sensor so auszurichten, dass wir Informationen aus einem bestimmten Bereich erhalten. Zu diesem Zweck sehen wir uns ein paar neue Konzepte an. Diese sind das analoge Auslesen und die Funktion map, die wir beide im weiteren Verlauf erklären.
Materialliste
- ZUM BT-328, Arduino-Platine oder kompatibel.
- Servo.
- Potentiometer.
Elektrische Verbindungen
Die Module für dieses Projekt anzuschließen ist sehr einfach. Wir müssen nur den Servo mit einem Pin verbinden, der den PWM-Ausgang enthält und das Potentiometer mit einem analogen Eingang. Auf der folgenden Abbildung siehst du ein Verbindungsschema:
Der Code
Wir beginnen mit dem einfachsten Beispiel und steigern dann später den Schwierigkeitsgrad.
Wir bewegen den Servo an die vom Potentiometer angegebene Position
Wir schreiben zunächst den vollständigen Code, um ihn anschließend Stück für Stück zu analysieren.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include int pinPot = A1; //Analoger Pin mit dem das Potentiometer verbunden ist Servo miServo; //Variable für die Steuerung des Servos void setup() { miServo.attach(10); } void loop() { int potRead = analogRead(pinPot); // liest den Wert des analogen Sensors aus int servoValue = map(potRead, 0, 1023, 0, 180); //überträgt den Wert des Bereichs 0 und 1023 auf 0 und 180 miServo.write(servoValue); //schickt den Servo an die entsprechende Position delay(500); //500 ms warten } |
Beginnen wir damit, die Servo-Bibliothek einzufügen und die Variablen der Pins zu benennen:
1 2 3 4 5 6 |
//Wir fügen die Servo-Bibliothek ein #include //Wir erstellen ein Servo-Objekt Servo miServo; int pinPot = A1; //Analoger Pin mit dem das Potentiometer verbunden ist |
Die Servo-Bibliothek für diese Art von Motoren ist spezifisch. Der Großteil der Servos erlaubt Bewegungen zwischen 0 und 180 °. Wenn du mehr über die Servo-Bibliothek erfahren möchtest kannst du zur Referenzseite von Arduino gehen.
setup()-Funktion
1 2 3 4 |
void setup() { miServo.attach(10); } |
In dieser Funktion geben wir an, dass der Servo mit dem digitalen Pin 10 verbunden ist.
loop()-Funktion
In dieser Funktion wird die Handlung ausgeführt. Dafür folgen wir diesen Schritten:
- Wir lesen den Wert des Potentiometers. Da es sich um einen analogen Eingang handelt, gibt er einen Wert zwischen 0 und 1023 aus. Wir verwenden die Funktion analogRead().
- Wir wandeln den Wert zwischen 0 und 1023 in einen Wert zwischen 0 und 180 um, indem wir die Funktion map() verwenden. Die Funktion map wandelt eine Variable von einem Ausgangsbereich in einen Zielbereich um. Das heißt, dass eine Variable im Bereich A-B im Bereich C-D liegen wird. Dabei bleibt die Position bezüglich des Ausgangs- und Zielbereichs gleich. Mehr über die Funktion map findet sich auf der Referenzseite.
- Wir ordnen dem Servo an, sich entsprechend der empfangenen Position zwischen 0 und 180 zu bewegen.
- Wir unterbrechen die Ausführung des Programms für 500 ms. Der Grund dafür ist, dass wir nicht wollen, dass der Servo andauernd seine Position ändert. Unser Programm wird dadurch stabiler, auch wenn es etwas an Flexibilität einbüßt.
Und so sieht der Code aus:
1 2 3 4 5 6 7 8 |
void loop() { int potRead = analogRead(pinPot); // liest den Wert des analogen Sensors aus int servoValue = map(potRead, 0, 1023, 0, 180); //überträgt den Wert des Bereichs zwischen 0 und 1023 auf 0 und 180. miServo.write(servoValue); //schickt den Servo an die entsprechende Position delay(500); //500 ms warten } |
Den Servo ohne ruckartige Bewegungen an die vom Potentiometer angegebene Position bewegen
Im folgenden Beispiel führen wir die gleiche Aufgabe durch, weisen den Servo aber an, sich alle 10 Millisekunden in kleinen Schritten von einem Grad vorwärts zu bewegen. So vermeiden wir plötzliche Sprünge, die durch ruckartige Bewegungen des Potentiometers hervorgerufen werden. Nach der anfänglichen Deklaration:
1 2 3 4 5 6 |
//Wir fügen die Servo-Bibliothek ein #include //Wir erstellen ein Servo-Objekt Servo miServo; int pinPot = A1; //Analoger Pin mit dem das Potentiometer verbunden ist |
Anschließend deklarieren wir die Variablen, die wir für die ordnungsgemäße Ausführung des Programmes benötigen:
1 |
int aktValue, nextValue; // Variable in der wir die Werte des Potentiometers speichern |
Nun verwenden wir die Funktion setup, um das Programm zu starten:
1 2 3 4 5 6 7 8 |
void setup() { //Wir starten die Serial-Bibliothek, um mit der Platine zu kommunizieren Serial.begin(9600); pinMode(pinPot, INPUT); miServo.attach(10); //Gibt an mit welchem Pin der Servo verbunden ist Serial.println("Fertig!"); } |
Wir starten die Serial-Bibliothek in der Funktion setup, geben den Pin des Potentiometers als Eingang an und teilen dem Programm mit, mit welchem Pin der Servo verbunden ist. Außerdem senden wir eine Nachricht, die dem Nutzer angibt, dass das Programm startbereit ist. Im weiteren Verlauf können wir die loop-Funktion komplett ansehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
void loop() { nextValue = analogRead(pinPot); // Wir lesen den Wert des Potentiometers (zwischen 0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Wir wechseln zu einem Wert, den der Servo lesen kann (0-180) //wir drucken den Wert der Position des Servos in Grad Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); /* Wir können zwischen zwei Fällen unterscheiden: Im ersten Fall ist die Folgeposition größer als die aktuelle Position, daher erhöhen wir den Wert Im zweiten Fall ist die Folgeposition kleiner als die aktuelle Position, daher verringern wir den Wert */ if (nextValue > aktValue) { for (int i = aktValue; i <= nextValue; i++) { miServo.write(i); //Wir verwenden die spezifische Funktion der Servo-Bibliothek, um den Wert zu schreiben delay(10); // und warten bis der Wert ankommt. } } else if (nextValue < aktValue) { for (int i = aktValue; i >= nextValue; i--) { miServo.write(i); delay(10); } } aktValue = miServo.read(); delay(1000); } |
Innerhalb der loop-Funktion entnehmen wir zunächst die Messwerte des Potentiometers und verwenden die map-Funktion, um den Wert des Potentiometer in einen Winkel zu “übersetzen”. Anschließend drucken wir im seriellen Monitor den Winkel:
1 2 3 4 5 6 7 |
nextValue = analogRead(pinPot); // Wir lesen den Wert des Potentiometers (zwischen 0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Wir wechseln zu einem Wert, den der Servo lesen kann (0-180) //wir drucken den Wert der Position des Servos in Grad Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); |
Im Gegensatz zum digitalen Auslesen erlaubt das analoge Auslesen die Unterscheidung von Werten zwischen 0 und 5 V. Die ZUM- und die Arduino-Platinen enthalten normalerweise einen Analog-Digital-Umsetzer mit 10 Bit, weshalb der mögliche Wertebereich zwischen 0-1023 liegt. Mehr über analogRead findet ihr auf der Referenzseite. Danach modifizieren wir die Position des Servos. Hierbei unterscheiden wir zwei mögliche Fälle:
- Der Wert, zu dem sich der Servo bewegt, ist höher als der jetzige Wert und wir müssen daher die Positon erhöhen:
1 2 3 4 5 6 |
if (nextValue > aktValue) { for (int i = aktValue; i <= nextValue; i++) { miServo.write(i); //wir verwenden die spezifische Funktion der Servo-Bibliothek, um den Wert zu schreiben delay(10); // wir warten bis der Servo diesen Wert erreicht. } } |
- Der Wert, zu dem sich der Servo bewegt, ist niedriger als der jetzige Wert und wir müssen die Position verringern:
1 2 3 4 5 6 |
else if (nextValue < aktValue) { for (int i = aktValue; i > nextValue; i--) { miServo.write(i); delay(10); } } |
Als Letztes speichern wir den Wert der Position, an der sich der Servo befindet und pausieren die Ausführung des Programmes eine Sekunde lang:
1 2 |
aktValue = miServo.read(); delay(1000); |