3.2 ⚙️ Servo steuern mit PWM
[L293D] [MezData: Servos][Arduino Servo Library][MezData: Modellbau-Servotester mit Pulsweiten-Anzeige]
Modellbauservo


Ein Modellbauservo wird durch die Breite eines Impulses gesteuert. Der Stellwinkel des Servos ist proportional zur Impulsbreite. Alle 20 ms sollte ein Steuerimpuls kommen. Die übliche Impulsbreite bewegt sich zwischen 1 ms und 2 ms. Servos können auch ausserhalb dieses Bereiches noch gesteuert werden, drehen weiter, allerdings besteht die Gefahr von Getriebeschäden wenn der Servo auf seinen mechanischen Anschlag gestellt wird.
Servotester
Fehler sind im Video, wer findet sie?
Auf dem Multifunction-Board sind bereits Ausgänge für 4 Servos vorgesehen. Allerdings sind diese Ausgänge auch für die Ansteuerung von Schrittmotoren und normalen Motoren gedacht. Die Signale von PC0..PC7 werden durch einen Leistungsverstärker L293D verstärkt und dann an den Ausgängen im Bild bereit gestellt. Die Stromversorgung des Verstärkers kann auch extern zugeführt werden um entweder höhere Spannungen oder Ströme an den Ausgängen zu ermöglichen. Der Leistungseingang des L296D kann mittels Jumper entweder mit Extern V+ und Intern 5V verbunden werden. Zum Testen eines Servos reichen die Internen 5V.


Jumper bei 5V einsetzten.
Info: Herr Sturm hat die PWM-Signale mit Timer-PWM gemacht und daher Drahtbrücken vorgesehen. Hier werden per Software die Signale mit der Arduino-Servo-Library erzeugt, daher ist dieser Aufwand nicht gegeben.
Ausgang | Gebrückt | PWM-Kanal |
---|---|---|
PC0 | PB9 | TIM4_CH4 |
PC3 | PB3 | TIM2_CH2 |
PC4 | PB4 | TIM3_CH1 |
PC7 | – | TIM3_CH2 |
Arduino-Sketch mit einem Servo
Die Arduino-Servo-Library verwendet Software zur Erzeugung der PWM Signale, daher kann praktisch jeder Ausgang verwendet werden. Damit die Servos Versorgungsspannung erhalten müssen die Ausgänge PC1,PC2,PC5 und PC6 bei Verwendung eine 1 ausgeben.
#include <Servo.h>
Servo myservo;
void setup() {
pinMode(PC1,OUTPUT); // PC1 braucht +5V
digitalWrite(PC1,HIGH);
myservo.attach(PC0); // Servosignal an PC0 anschliessen
}
void loop() {
for (int i =30;i<150;i++){ // zwischen 30 und 150 Grad laufen
myservo.write(i); // in Grad ausgeben
delay(50);
}
}
Servotester mit LCD-Anzeige
Hinweis: Brücke zwischen PB8-PA11 und PB9-PA12 für LCD-Anzeige notwendig.
#include <Servo.h>
#include <LiquidCrystal_PCF8574.h>
#define MSMIN 800 // kleinste Pulsweite
#define MSMAX 2500 // groesste Pulsweite
Servo myservo;
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27
void setup() {
pinMode(PC1,OUTPUT); // PC1 braucht +5V
digitalWrite(PC1,HIGH);
myservo.attach(PC0); // Servosignal an PC0 anschliessen
lcd.begin(16, 2); // LCD initialisieren
lcd.clear();
lcd.setBacklight(255);
}
void loop() {
int adWert = analogRead(PA0); // AD-Wandler einlesen 0..1023
int us = map(adWert,0,1023,MSMIN,MSMAX); // Arduino map-Funktion rechnet AD-Wert in ms-Wert um
lcd.clear();
lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
lcd.print(F("PWeite: "));
lcd.print(us);
lcd.print(F("us"));
myservo.writeMicroseconds(us);
delay(50);
}
Wie funktioniert die Map-Funktion, erstellen Sie eine eigene Funktion (selber versuchen, nicht spicken).
Lösung
extern long map(long x, long in_min, long in_max, long out_min, long out_max){
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Servo mit Timer-PWM steuern
Der Servo ist an PB10 (D6) angeschlossen und wird mit TIM2_CH3 PWM gesteuert. Die Servowerte gelten für einen Funduino SG90 Servo.
Eine µs genaue Auflösung reicht. Ermittle Werte für Prescaler, Overflow und Capture-Register siehe 1.7 💯 PWM (PulsWeitenModulation).
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
#define P_POTI A0 // Poti an PA0
#define P_SERVO PB10 // D6 TIM2_CH3
#define KANAL 3 // CH2
#define SERVO_L 2400 // Linker Wert in us
#define SERVO_R 600 // Rechter Wert in us
static HardwareTimer mytimer = HardwareTimer(TIM2); // Timerinstanz sowie Timerauswahl
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein
void setup() {
lcd.begin(16, 2); // LCD initialisieren
lcd.setBacklight(255); // Hintergrundbeleuchtung einschalten
mytimer.setPrescaleFactor(32); // Timer zählt in µs
mytimer.setOverflow(20000); // Wiederholung alle 20ms
mytimer.setMode(KANAL,TIMER_OUTPUT_COMPARE_PWM1,P_SERVO); // Ausgang einstellen
mytimer.setCaptureCompare(KANAL,1500); // Impulsbreite 1500 µs einstellen
mytimer.resume(); // Timer starten
}
void loop() {
int poti = 0;
for(int i=0;i<10;i++){ // 10 Messungen machen
poti += analogRead(P_POTI);
delay(2);
}
poti /= 10;
int servo = map(poti,0,1023,SERVO_L,SERVO_R); // Arduino-Umrechnungsfunktion
mytimer.setCaptureCompare(KANAL,servo); // Impulsbreite einstellen
lcd.setCursor(0,1);
lcd.printf("A %4d S %4d\xe4s",poti,servo); // Poti- und Servowert
}
🤯 Servo mit analogWrite() ansteuern
War ein Versuch..
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
#define P_POTI A0 // Poti an PA0
#define P_SERVO PB10 // D6 TIM2_CH3
#define SERVO_L 2200 // Linker Wert in us
#define SERVO_R 800 // Rechter Wert in us
#define RESOLUTION 16 // Bit-Auflösung
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein
float faktor = ((1<<RESOLUTION)-1)/20.0; // Wert für 1ms
void setup() {
lcd.begin(16, 2); // LCD initialisieren
lcd.clear(); // Displaypuffer löschen
lcd.setBacklight(255); // Hintergrundbeleuchtung einschalten
lcd.setCursor(0,0); // Cursor auf erstes Zeichen, erste Zeile setzen
lcd.printf("Res %2d F %5.2f",RESOLUTION,faktor); // Auflösung und Faktor
analogWriteFrequency(50); // PWM-Frequenz für Servo
analogWriteResolution(RESOLUTION); // möglichst genau
}
void loop() {
int poti = 0;
for(int i=0;i<10;i++){ // 10 Messungen machen
poti += analogRead(P_POTI);
delay(2);
}
poti /= 10;
int servo = map(poti,0,1023,SERVO_L*faktor/1000,SERVO_R*faktor/1000); // Arduino-Umrechnungsfunktion
analogWrite(P_SERVO,servo);
lcd.setCursor(0,1);
lcd.printf("A %4d S %4d",poti,servo); // Poti- und Servowert
}
Aufgabe Servo zeigt Sekunden an
Ein Servo ist mit einem Zeiger verbunden und zeigt damit die Sekunden an.
Das Servo wird dazu an PC7 angeschlossen und wird mit TIM3_CH2 zwischen 1000 µs und 2000 µs Pulsweite alle 20 ms angesteuert.
Ein Timer TIM2 zählt über eine ISR im Sekundentakt von 0 bis 59 und gibt dabei die Pulsweite 1000 µs bis 2000 µs vor. Dieser Code ist gegeben, ergänzen Sie ihn..
Aufgabe Servo steuert Helligkeit
Die Helligkeit in einem Raum soll begrenzt werden, dazu steuert ein Servo eine Jalousie. An einem AD-Wandler-Eingang wird mittels Poti die Wunschhelligkeit eingestellt und mit einem Photowiderstand an einem anderen AD-Eingang die Helligkeit gemessen. Ergänzen Sie den Code..