Will man viele Servos mit Arduino steuern, stößt man schnell an die Grenze des Boards. Die USB-Stromversorgung reicht kaum für mehr als einen Servomotor. Um trotzdem viele Servos zu versorgen, gibt es einen Servomotor-Treiber. Diese Erweiterungsplatine kann bis zu 16 Servos steuern und verfügt darüber hinaus über eine Anschlussmöglichkeit für eine externe Stromversorgung. Entwickelt wurde sie von Adafruit und hört auf den schönen Namen PCA9685.
Adafruit PCA9685
Dieser Servomotor-Treiber wird per I2C-Schnittstelle angesprochen und belegt dadurch nur zwei Arduino-Pins. Zum Betreiben gibt es eine eigene Arduino-Programmbibliothek, die die Nutzung extrem einfach macht.
Spannend am Servomotor-Treiber PCA9685 ist, dass er über Adress-Pins verfügt, die die Nutzung von bis zu 62 Servomotor-Treibern ermöglicht. Das führt zu einer Gesamtanzahl von gleichzeitig steuerbaren Servos von 992!! (die nötige Stromversorgung vorausgesetzt)
Installation der Adafruit PWM Programmbibliothek
Klicke in der Arduino-Software auf Sketch>Bibliothek einbinden>Bibliothek verwalten. Suche im Textfeld nach Adafruit PWM und installiere die Adafruit PWM Servo Driver Library in der aktuellen Version.
Code – Viele Servos mit Arduino steuern
In diesem Beispiel wird jeder Servo (von 0 bis 15) einmal hin und her bewegt. Den Original-Code findest du in der Arduino-Software unter Datei>Beispiele>Adafruit PWM Servo Driver Library>test.
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver myServos = Adafruit_PWMServoDriver(); #define SERVOMIN 150 #define SERVOMAX 600 uint8_t servonum = 0; uint8_t numberOfServos = 16; void setup() { myServos.begin(); myServos.setPWMFreq(60); delay(10); } void loop() { for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++){ myServos.setPWM(servonum, 0, pulselen); } delay(500); for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--){ myServos.setPWM(servonum, 0, pulselen); } delay(500); servonum ++; if (servonum > numberOfServos-1) servonum = 0; }
Wie funktioniert dieses Programm?
Da das PCA9685 I2C für den Datenaustausch verwendet, muss die Wire.h-Bibliothek eingebunden werden. Wire war der Vorgänger von Arduino und die Bibliothek beinhaltet noch eine Reihe nützlicher Tools. Dazu die weiter oben erwähnte Bibliothek für das Modul selbst. Das passiert am Anfang des Programmes:
#include <Wire.h> #include <Adafruit_PWMServoDriver.h>
Nun wird ein Adafruit_PWMServoDriver-Objekt angelegt. Über dessen Namen myServos können wir es dann ansprechen. Im Originalcode heißt diese Variable übrigens pwm, was ich als Variablennamen etwas unglücklick finde. Falls du also den Originalcode verwendest, nicht wundern.
Adafruit_PWMServoDriver myServos = Adafruit_PWMServoDriver();
Jetzt werden noch ein paar Konfigurationen getroffen. Der maximale und minimale Ausschlag der Servos wird als Konstante definiert:
#define SERVOMIN 150 #define SERVOMAX 600
Hier könnte fast genauso gut stehen:
int servoMin = 150; int servoMax = 600;
Da man diese Werte aber im laufenden Programm lieber nicht verändert, macht es Sinn, die Konstantendeklaration (oben) zu nutzen.
Die Hilfsvariable servonum wird verwendet, um später im Loop eine Zählervariable zur Verfügung zu haben. Sie zählt pro Durchlauf des Loops von 0 bis numberOfServos-1.
uint8_t servonum = 0; uint8_t numberOfServos = 16;
Springen wir kurz an das Ende des Loops, um uns das genauer anzusehen.
servonum ++; if (servonum > numberOfServos-1) servonum = 0;
Die Variable servonum wird also so lange wiederholt, bis sie größer als numberOfServos-1 ist. Sobald sie größer ist, wird sie auf 0 zurückgesetzt.
Nun steht uns im Loop also eine Variable zur Verfügung, die von 0 bis 15 durchläuft. Das ist praktisch, denn im Beispiel wollen wir ja 16 Servos – und zwar einen nach dem anderen – bewegen.
Das wird durch zwei for-Schleifen realisiert. Die eine zählt von SERVOMIN bis SERVOMAX hoch,
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++){ myServos.setPWM(servonum, 0, pulselen); } delay(500);
die andere (nach einer Verzögerung von 500 ms – delay(500) – ) von SERVOMAX auf SERVOMIN herunter.
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--){ myServos.setPWM(servonum, 0, pulselen); } delay(500);
Die Zähltervariable pulselen speichert dabei den aktuellen Wert, also den Wert zwischen SERVOMIN und SERVOMAX). Und dieser Wert wird jetzt einfach an das PCA9685-Modul gesendet, welches dann den Servo (servonum) auf den Wert pulselen stellt.
myServos.setPWM(servonum, 0, pulselen);
Die Eintragungen im Setup habe ich übersprungen. Also zur Erläuterung. Die erste Zeile startet das myServos-Objekt, die zweite setzt die Servo-Frequenz auf 60 Hz. Das ist auch die Frequenz für Servomotoren (LEDs bevorzugen z. B. 1KHz).
myServos.begin(); myServos.setPWMFreq(60); delay(10);
Servos auf bestimmte Position stellen
Hier noch mal ein Programm, dass 16 Servos zuerst auf zwei je vordefinierte Positionen stellt, wobei die Positionen von Servo zu Servo unterschiedlich sein können. Danach wird jeder Servo auf eine zufällige Position gestellt.
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver myServos = Adafruit_PWMServoDriver(); int servosPos1[]={150,160,170,180,190,200,210,220,230,240,250,260,270,280,290,300}; int servosPos2[]={500,490,480,470,460,450,430,420,410,400,390,380,370,360,350,340}; #define SERVOMIN 150 #define SERVOMAX 600 int numberOfServos = 16; void setup() { myServos.begin(); myServos.setPWMFreq(60); delay(10); } void loop() { for (int i=0; i<numberOfServos; i++){ myServos.setPWM(i, 0, servosPos1[i]); } delay(500); for (int i=0; i<numberOfServos; i++){ myServos.setPWM(i, 0, servosPos2[i]); } delay(500); for (int i=0; i<numberOfServos; i++){ myServos.setPWM(i, 0, random(SERVOMIN,SERVOMAX)); } delay(500); }
Mehrere PCA9685 verwenden
Sollen es noch mehr Servos sein? Kein Problem. Es lassen sich bis zu 62 PCA9685-Module koppeln. (Bitte kauf die 62 Module und die dazugehörigen 922 Servos über meine Affiliate-Links 😂 )
Um mehrere Module zu verwenden, muss man auf den PCA8574-Modulen eindeutige Adressen zuweisen. Das macht man, indem man die dazugehörigen Lötstellen mit Lötzinn überbrückt (A0 – A5). In der Grafik kannst du sehen, wie die Adressen zugewiesen werden.
Schaltplan: Viele PCA9685-Module verwenden
Markus stand genau vor dem Problem, mehrere Module zu betreiben und hat uns den folgenden Beispiel-Code zur Verfügung gestellt. Vielen Dank nochmal dafür. :-)
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40); Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41); int board1gerade[] = {150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300}; //Min Position Servos Board1 int board1abzw[] = {500, 490, 480, 470, 460, 450, 430, 420, 410, 400, 390, 380, 370, 360, 350, 340}; //Max Position Servos Board1 int board2gerade[] = {150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300}; //Min Position Servos Board2 int board2abzw[] = {500, 490, 480, 470, 460, 450, 430, 420, 410, 400, 390, 380, 370, 360, 350, 340}; //Max Position Servos Board2 #define SERVOMIN 150 #define SERVOMAX 600 int numberOfServos = 16; void setup() { board1.begin(); board2.begin(); board1.setPWMFreq(60); board2.setPWMFreq(60); delay(10); } void loop() { for (int i = 0; i < numberOfServos; i++) { //Servos auf im Array vorgegebene Stellung (gerade) setzen board1.setPWM(i, 0, board1gerade[i]); } delay(500); for (int i = 0; i < numberOfServos; i++) { //Servos auf im Array vorgegebene Stellung (abzw) setzen board1.setPWM(i, 0, board1abzw[i]); } delay(500); for (int i = 0; i < numberOfServos; i++) { //Servos auf im Array vorgegebene Stellung (gerade) setzen board2.setPWM(i, 0, board2gerade[i]); } delay(500); for (int i = 0; i < numberOfServos; i++) { //Servos auf im Array vorgegebene Stellung (abzw) setzen board2.setPWM(i, 0, board2abzw[i]); } }
Wenn du mehr Fragen hast, schreibe diese gerne in die Kommentare. Ansonsten viel Spaß mit der Servo-Party!
Bezugsquellen des PCA9685
Original PCA9685 von Adafruit (1 Stück für ca. $14.95)
AZDelivery PCA9685 auf Amazon* (3 Stück für ca. 12,99 €)
Projekte mit Servos
Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!
- Die beliebtesten Arduino-Projekte von StartHardware
- Inklusive Schaltplan, Beschreibung und Code
- Arduino-Schnellstart-Kapitel
- Kompakter Programmierkurs
Hallo Markus
Dein Sketch gefällt mir. Ich möchte die Servos nicht automatisch schalten, sondern per Tasterdruck. Hast du einen Vorschlag für mich?
Gruß Charlie
Hallo
ich habe eine kleine Frage wo ich ein bisschen verzeifel.
wie kann ich einen einzelnen Servo auf eine fixe Position setzen, schaffe es immer nur alle gleichzeitig,
also zb per serieller Monitor kann ich servo1 auf Pos. x setzen dann servo 2 auf Postion y.
Brauche da glaube nur einen schubs wie der start asussehen müsste bzw das Void Setup
Gruß Timo
Hallo in die Runde
Ich bin relativ neu auf dem Gebiet der Arduono-Programmierung. Ein paar kleinere Projekte zum Testen habe ich jedoch schon erfolgreich gemacht. Nun meine Frage; ja ich möchte ein Projekt starten bei dem ebenfalls mehrere Servos zum Einsatz kommen sollen. Diese sollen sich aber gleichzeitig bewegen, also nicht nacheinander sondern synchron. Muss ich dann die Servos in kleinen Schritten nacheinander ansteuern so dass dieser Effekt eine Art Gleichzeitigkeit “simuliert” oder gibt es eine Möglichkeit zB. Servo 1-7 gleichzeitig in eine gewünschte Position zu bewegen?
Danke für etwaige Antworten im vorraus!
Hallo Rocco, das sollte eigentlich relativ gleichzeitig möglich sein. Allerdings muss das Netzteil groß genug sein, da es ziemlich schwere Arbeit leisten muss. Liebe Grüße Stefan
Hallo,
ich habe einen PCA9685 von Amazon gekauft, wohl ein preiswerter Nachbau. Äusserlich erkennbar an einem Elko neben der Power LED. Dieses Teil benötigt als externe Stomquelle den Anschluss an V+ an der Stiftleiste! Ein Anschluss der externen Spannung -wie abgebildet- an der grünen Steckerleiste genügt nicht! Ich habe Plus 5V und Minus an der grünen Steckerleiste angeschlossen und zusätzlich den +5V an V+ an der Steckerleiste verbunden. Nur so klappt das Ganze!
Viel Erfolg, Uli
Klappt leider bei mri nicht! Ich habe ein Labornetzteil mit 5V an die Klemme angeschlossen und die Pins Vcc und GND an den Uno ; geht nicht! Dann habe ich den Plus und den Minus vom Netzteil an die Pins V+ am PCA; geht nicht! Habe die SCL und SDA an SCL und SCA am Uno; geht nicht!Dann SCL und SDA am Uno an Pin ana 4 und 5; geht auch nicht.
Ich weiss nicht mehr weiter.
Achso, habe auch die PCAs gewechselt, weil dort keine gelbe Lampe angeht. Vielleicht beide defekt?
Gruss Bernd
Hi Bernhard, das kann ich dir leider nicht sagen. Die Schaltung hab ich mir noch mal angesehen und die sollte funktionieren. Dass zwei PCA9685 defekt sein sollten, halte ich aber nicht für sehr wahrscheinlich. Kannst du noch mal prüfen, ob der richtige Code auf das Arduino-Board übertragen ist? Liebe Grüße Stefan
Pingback: Servos (allg.) und steuern mit kleinen PICs und AVRs | wer bastelt mit?
Hallo zusammen.
Ich muss gestehen, ich habe von programmieren usw keinerlei Ahnung.
Ich komme aus dem Modelleisenbahn Sektor. Und da beschäftigt mich schon eine zeitlang folgendes:
Ich möchte meine 36 Entkupplungsgleise nicht mehr mit Elektromagneten (sind mir mittlerweile unrealistisch laut) sondern mit Servos betreiben. Der Aufwand ist zwar ein wenig hoch, aber was macht man nicht alles für sein Hobby.
Und zwar soll der jeweilige Servo auf Tastendruck in eine bestimmte Position fahren und beim loslassen wieder zurückfahren, mehr nicht.
Da ich, wie schon erwähnt, keinerlei Ahnung von dieser Materie habe, es aber meiner Erkenntnisse ohne zu großen finanziellen und materiellen Aufwand doch mit dieser Technik möglich sein müsste.
Vielleicht kann jemand sich dieses Themas annehmen und mich aus fem “Dunklen ” raushelfen.
Gruß Peter
Pingback: Animatronic mit Arduino – Arduino Tutorial
Eine Frage:
In einem Glockenstuhl mit 6 Glocken sollen die Glocken einzeln anschwingen (je nach der Tonfolge im verwendeten MP3-File) und auch entsprechend wieder aufhören. Wie kann ich dem einzelnen Servo sagen: – jezt bis du dran – und nach vielleicht 3000 ms nun reichts erst mal… Ohne die anderen damit zu stören bzw. abzuwürgen.
Leider finde ich nichts um mehrere einzelne Glocken nacheinander und zum Teil miteinander anzusteuern.
Und zu allen Überfluss habe ich auch keine Ahnung so einen Sketch zu schreiben…
Gert
Sehr geehrter Herr Herman,
ich möchte Weichen (Servos) mit dem PCA9685 über dem Arduino schalten.
Der Arduino soll das Signal als DCC Signal vom Train Contoller (Freiwald) von den Schienen übernehmen.
https://i0.wp.com/www.modellbahn-anlage.de/wp-content/uploads/2019/11/DCCanMikrocontroller.jpg?ssl=1
Benötige ich dafür zwei Ardinos wegen zwei Sketche oder kann man das ganze auch mit einem Sketch bewerkstelligen?
Hallo Joachim, ich hab mit digitalen Signalen des Train Controller leider keine Erfahrung. Allerdings denke ich schon, dass ein Arduino ausreichen sollte. Liebe Grüße Stefan
Hallo Stefan,
danke für die schnelle Antwort. Ich habe auch schon ein Sketch im Forum opendcc gefunden.
Hier der Sketch werde ihn demnächst ausprobieren.
Gruß aus Hamburg
Joachim
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Arduino DCC Servo and Function Decoder.
// Author: Author: Ruud Boer – January 2015
// This sketch turns an Arduino into a DCC decoder with max 12 servo motor outputs combined with function outputs.
// The DCC signal is optically separated and fed to pin 2 (=Interrupt 0). Schematics: http://www.mynabay.com
// Many thanks to http://www.mynabay.com for publishing their DCC monitor and -decoder code, which is used in this sketch.
//
// Important Change:
// This sketch from Ruud Boer was changed by lordbrummi in April 2016
// Now you can connect a PWM Arduino Servo Shield with 16 possible servos and adress them with DCC adresses
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTANT: change some lines marked as IMPORTANT !!!!!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include
#include
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#include
#include
#define kDCC_INTERRUPT 0
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in these values …
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const byte maxservos = 3; //The number of servos (not the physical number, but the number of servo adresses defined. IMPORTANT!!!!!
const byte servotimer = 0; //Global Servotimer fo all servos, higher value is slower (0 is recommended)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Set the Servomin and the Servomax of your servo between the gear range possibility IMPORTANT!!!!!
const int SERVOMIN = 150; // this is the ‘minimum’ pulse length count (out of 4096)
const int SERVOMAX = 600; // this is the ‘maximum’ pulse length count (out of 4096)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int lastaddr; // last switched adress, internal use only
unsigned long timetoupdatesetpoint = millis() + servotimer;
struct DCCAccessoryAddress {
int address; // DCC address to respond to
byte output; // State of accessory: 1=on, 0=off (for internal use only)
int outputPin; // Arduino output pin
int change; // State of accessory change: 1=change, 0=no change (for internal use only)
};
DCCAccessoryAddress accessory[maxservos];
struct servoItem {
int angle;
int setpoint;
int offangle;
int onangle;
byte inverted;
int servo;
byte functionnumber;
unsigned long stimer;
unsigned long suptimer;
};
servoItem servos[maxservos];
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the address and pin for every accessory / function. Servos are ‘coupled’ to accessory[n] in line 72 and further. IMPORTANT!!!!!
// COPY – PASTE as many times as you have functions. The amount must be same as in line 22 above!
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ConfigureDecoderFunctions()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// You have to declare as much accessorys as servomax is defined above.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
accessory[0].address = 1; // DCC address for this accessory IMPORTANT!!!!!
accessory[0].outputPin = 13; // Arduino pin where accessory is connected to and which will be switched on/off
accessory[1].address = 2; // DCC address for this accessory
accessory[1].outputPin = 13; // Arduino pin where accessory is connected to and which will be switched on/off
accessory[2].address = 3; // DCC address for this accessory
accessory[2].outputPin = 12; // Arduino pin where accessory is connected to and which will be switched on/off
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup output pins for accessories
for(int i=0; i> 1;
boolean enable = (data & 0x01) ? 1 : 0;
for(int i=0; i<maxservos; i++)
{
if(address == accessory[i].address)
{
if (enable)
{
if (accessory[i].output != 1)accessory[i].change = 1;
accessory[i].output = 1;
}
else
{
if (accessory[i].output != 0)accessory[i].change = 1;
accessory[i].output = 0;
}
if (accessory[i].address != lastaddr) accessory[i].change = 1;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
ConfigureDecoderFunctions();
ConfigureDecoderServos();
DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
pinMode(2,INPUT_PULLUP); //Interrupt 0 with internal pull up resistor (can get rid of external 10k)
//pinMode(A5,INPUT_PULLUP); //If made LOW, all servos go to their min angle, to avoid jitter at starup. – Not to use with PWM Servoshield because it uses already pinMode A5
pinMode(13,OUTPUT);
digitalWrite(13,LOW); //switch off Arduino led at startup
Serial.begin(9600);
pwm.begin();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates ( false freq setting may destroy your servo ! ) IMPORTANT!!!!!!!
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
for (int n=0; n= maxservos ) addr = 0; // Next address to test
// Set accessory output pin
if (accessory[addr].change == 1)
{
if (accessory[addr].output)
{
digitalWrite(accessory[addr].outputPin, HIGH);
}
else
{
digitalWrite(accessory[addr].outputPin, LOW);
}
}
// Every ‘servotimer’ ms, modify setpoints and move servos 1 step (if needed)
if (millis() > timetoupdatesetpoint)
{
timetoupdatesetpoint = millis() + servotimer;
for (int n=0; n servos[n].suptimer)
{
if (accessory[servos[n].functionnumber].change == 1)
{
if (accessory[servos[n].functionnumber].output) servos[n].setpoint=servos[n].onangle;
else servos[n].setpoint=servos[n].offangle;
if (servos[n].angle servos[n].setpoint) servos[n].angle–;
if (servos[n].stimer==0)servos[n].angle=servos[n].setpoint;
pwm.setPWM(servos[n].servo, 0, servos[n].angle);
servos[n].suptimer = millis()+ servos[n].stimer;
if (servos[n].angle == servos[n].setpoint)
{
Serial.println(“Weiche wurde gestellt!”);
Serial.println(servos[n].setpoint);
lastaddr = accessory[n].address;
for (int k=0; k<maxservos; k++)
{
if (servos[k].servo == servos[n].servo)
{
servos[k].angle=servos[n].setpoint;
}
}
accessory[servos[n].functionnumber].change = 0;
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Move all servos to min position and set all function outputs to 0, to eliminate startup servo jerk current draw
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//if (digitalRead(A5)==LOW) {for (int n=0; n<maxservos; n++) accessory[n].output = 0;} – Not to use with PWM Servoshield because it uses already pinMode A5
} //END MAIN LOOP
Guten Morgen,
Ich wollte eine Krabbe basteln mit Servos, Von Elektronik habe ich leider keine Ahnung (und will es auch nicht mehr lernen, ich bin zu alt dafür(56)) Ich verwende einen Arduino Mega 2560. also genug Datenleitungen für 18 Motoren. Die Verkabelung ist nicht das Problem, auch scheint die Programmierung nicht allzu schwer. Es liegt wohl an der Stromversorgung. Ich kann alle 18 Motoren bewegen…. aber halt immer nur einen. Sobald ich einen zweiten dazuhänge, geht nichts mehr. Zusätzlich 4 x 1,5V Batterien haben auch keine positive Auswirkung. Was müsste ich denn da verwenden? Vielleicht kann mir hier jemand helfen? Im Gegenzug helfe ich gerne bei EINFACHEN Programmier Fragen
Hi Thomas,
hast du die Batterien an den Versorgungsanschluss des Servomotor-Treibers PCA9685 angeschlossen? 18 Servos ziehen echt viel Strom, wenn man sie gleichzeitig stellen will.
Liebe Grüße
Stefan
Hallo,
ich habe eine Frage bzgl. des Laufzeitverhaltens der Software.
Zum Hintergrund: Mein Projekt ist ein Flugsimulator – ich würde gerne ein Cockpit mit Zeigerinstrumenten realisieren. Die Zeiger würden sich am einfachsten mit Servos ansteuern lassen.
Das Vorgehen wäre dann in etwa so:
Vom PC-Flugsimulator alle 100 ms die relevanten Werte abfragen, an einen anderen Rechner senden und in Servo-Positionen übersetzten, um auf dem Arduino-Board möglichst wenig zu rechnen (ich rechne in der finalen Ausbaustufe mit knapp 100 Werten für 20-40 LEDs und 40-60 Servos…). Die LED-Helligkeiten und Servo-Positionen müssten dann via Ethernet auf das Arduino zur Weiterverteilung auf die PCA9685-Boards. Theoretisch kann man ja eben 992 Servos regeln, aber wie performant ist das? Wenn ich dem ersten Servo seine neue Position mitgeteilt habe, wie lange braucht das Arduino Board die anderen Werte an die Servos zu kommandieren? Ist es realsitisch an die 100 PWM-Werte innerhalb von 100 ms weiterzuleiten, denn nach 100 ms kämen schon wieder die aktualisierten Werte aus der Simulation.
Ich habe auf Youtube Videos gesehen in denen 32 Servos bewegt werden und hatte den Eindruck, dass es einen deutlich sichtbaren Zeitversatz gibt zwischen der ersten Bewegung von Servo 1 und Servo 32. Da werden zwar map-Funktionen verwendet, daher die Idee die Positionen noch auf PC-Seite zu berechnen, aber die Daten an Arduino zu senden und dann auf die Servos zu verteilen, wird wohl einen Moment dauern…
Wäre das ESP32 eine bessere Wahl?
Herzliche Grüße
Dominik
Hi Dominik,
wow! Das wäre natürlich ein krasses Projekt. Leider kann ich dir dazu nichts sagen. Das einzelne Steuern der Servos dauert halt immer etwas. Allerdings muss man vielleicht nicht immer neue Daten an alle 32 Servos senden. Also Flughöhe und Geschwindigkeit sind ja vielleicht zeitkritischer als der Inhalt der Tanks. Du wirst es wahrscheinlich aufbauen müssen, um es zu probieren. Die Geschwindigkeit des Controllers ist aber sicherlich nicht das Problem. Da sollte das Arduino schnell genug für sein.
Liebe Grüße
Stefan
Kann ich die Drehgeschwindigkeit der Servos einstellen mit der Software im ARDUINO??
Welche Software ist dafür geeignet ?
Die Standardbiblitheken können dies leider nicht, ich nutze die „Mobatools“, dort kann man die Geschwindigkeit schön einstellen.
Ist ja super beschrieben…ich bin ein gaaaz blutiger Anfänger…wie sieht es aus wenn ich jeden Servo einzeln Steuern will ??? z.B. aus einem Empfänger 12 Servos einer Fernsteuerung durch einen Slipring (wenig Pole) wieder auf die passenden Servos verteilen will ? hat das jemand schon gemacht ?
Hm, ich hab das noch nicht gemacht. Könnte mir aber vorstellen, dass das ab und zu jemand braucht.
ich brauche das…. stell dir vor: Fernsteuerung im Baggerfahrwerk und die Steuersignale müssen durch den Drehkranz nach oben zumRest…
Guten Abend,
das wäre schön, wenn es ohne großen Aufwand funktionieren würde, aber Du hast ja nur einen Schleifring. Darüber könnte man theoretisch die nötige Adresse pro Board ansprechen, aber wie willst Du mit der Funke dannn sagen, welches Servo was machen soll pro Board? Schön wäre so eine Lösung auf jeden Fall.
Gruß
Markus
Nabend…
also meine Idee wäre die Ausgänge der Steuerung in den Arduino, dann mit den 4 Kabeln durch den Schleifring und aus dem PCA dann auf die Servos. Der Schleifring hat 18 Pole, brauch aber für andere Sachen auch noch Leitungen (Stromversorgungen , Beleuchtungen etc.), dann wäre das mit dem PCA super, 18-4 wären noch 12 Leitungen übrig für die anderen Sachen…oder andere PCA´s für noch mehr Dummheiten…
Ich würde gerne mehrere dieser Boads verbinden. Die Adresseinstellung wird ja über die Lötbrücken realisiert, aber wie werden die weiteren Module dann angesprochen?
Hi Markus,
spannend! Was baust du für ein Projekt? Weißt du das schon?
Also: Scheinbar kann man das in der Deklaration des Objektes gleich mit übernehmen:
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x41);
Hier ist das noch mal genauer beschrieben: https://learn.adafruit.com/16-channel-pwm-servo-driver/chaining-drivers
Sag bescheid, ob es klappt.
Liebe Grüße
Stefan
Hi Stefan,
habs gestern auch schon gefunden. Funktioniert einwandfrei diese Lösung. Will eine Weichensteuerung für Sohnemann bauen mit Touchdisplay zum schalten der Weichen.
Gruß
Markus
Hi Markus, ach super. Das klingt doch lustig. Na dann wünsche ich euch viel Spaß dabei :-) Liebe Grüße Stefan
Hi Stefan,
vielleicht magst Du Deinen SUPER Artikel ja ergänzen! Es können bis zu 62?? Boards a 16 Servos angesprochen werden.
Ich habe nun testweise nur zwei genommen und A0 gebrückt.
Anbei der Testsketch:
#include
#include
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);
int board1gerade[]={150,160,170,180,190,200,210,220,230,240,250,260,270,280,290,300}; //Min Position Servos Board1
int board1abzw[]={500,490,480,470,460,450,430,420,410,400,390,380,370,360,350,340}; //Max Position Servos Board1
int board2gerade[]={150,160,170,180,190,200,210,220,230,240,250,260,270,280,290,300}; //Min Position Servos Board2
int board2abzw[]={500,490,480,470,460,450,430,420,410,400,390,380,370,360,350,340}; //Max Position Servos Board2
#define SERVOMIN 150
#define SERVOMAX 600
int numberOfServos = 16;
void setup() {
board1.begin();
board2.begin();
board1.setPWMFreq(60);
board2.setPWMFreq(60);
delay(10);
}
void loop() {
for (int i=0; i<numberOfServos; i++){ //Servos auf im Array vorgegebene Stellung (gerade) setzen
board1.setPWM(i, 0, board1gerade[i]);
}
delay(500);
for (int i=0; i<numberOfServos; i++){ //Servos auf im Array vorgegebene Stellung (abzw) setzen
board1.setPWM(i, 0, board1abzw[i]);
}
delay(500);
for (int i=0; i<numberOfServos; i++){ //Servos auf im Array vorgegebene Stellung (gerade) setzen
board2.setPWM(i, 0, board2gerade[i]);
}
delay(500);
for (int i=0; i<numberOfServos; i++){ //Servos auf im Array vorgegebene Stellung (abzw) setzen
board2.setPWM(i, 0, board2abzw[i]);
}
}
Nochmals besten Dank und Gruß
Markus
Hi Markus,
wow! Echt cool. Vielen Dank dafür :-)
Ich hoffe ich komme am Wochenende dazu, den Code mit einzubinden. Das wird bestimmt vielen Leuten helfen!
Liebe Grüße
Stefan
So, erledigt. Noch mal lieben Dank Markus. War echt super, dass du mir den Code geschickt hast :-)
Funktioniert das ganze auch mit einem ANGEEK PCA9685? Und wenn ja worauf muss ich achten? Also gibt es dann eine andere Programmbibliothek? Und wenn ja wo bekomme ich die her?
Hi Patrick, also das sollte (eigentlich) genau so funktionieren. Bei so Open-Hardware-Sachen gibt es immer eine große Anzahl von Herstellern für exakt das gleiche Modul. Probiert hab ich es mit genau diesem Teil aber noch nicht.