Suchcode

Steuere 32 Servos über Wi-Fi mit ESP32 und PCA9685 über Desktop oder Mobiltelefon V5

Steuere 32 Servos über Wi-Fi mit ESP32 und PCA9685 über Desktop oder Mobiltelefon V5

In diesem Tutorial lernen wir, wie man 32 Servomotoren mit dem PCA9685 PWM-Controller-Modul steuert, das über Wi-Fi mit dem ESP32 verbunden ist. Diese Einrichtung ermöglicht es Ihnen, jeden Servomotor einzeln oder alle auf einmal über eine Weboberfläche zu steuern, die von einem Desktop- oder mobilen Gerät aus zugänglich ist. Am Ende dieses Leitfadens werden Sie ein voll funktionsfähiges System haben, das in der Lage ist, mehrere Servos mühelos zu verwalten.

PCA9685 module-0

Das PCA9685-Modul bietet eine einfache Möglichkeit, mehrere Servos mit PWM-Signalen zu steuern, während der ESP32 die Wi-Fi-Kommunikation und die Funktionen des Webservers übernimmt. Sie können den Winkel jedes Servomotors über eine benutzerfreundliche Oberfläche anpassen, die Schaltflächen für jeden Servo anzeigt. Für visuelle Referenz sollten Sie sich das Video (im Video bei :00) ansehen.

Hardware erklärt

Dieses Projekt verwendet hauptsächlich den ESP32-Mikrocontroller und den PCA9685-PWM-Controller. Der ESP32 ist ein leistungsstarker Mikrocontroller mit integrierten WLAN-Funktionen, was ihn ideal für IoT-Projekte macht. Der PCA9685 ist ein 16-Kanal-PWM-Controller, der kaskadiert werden kann, um bis zu 64 Servos zu steuern. Er kommuniziert mit dem ESP32 über das I2C-Protokoll, was es ermöglicht, mehrere Controller anzuschließen und individuell anzusprechen.

Jedes PCA9685-Modul hat eine Standard-I2C-Adresse von 0x40. Wenn mehrere Module verwendet werden, können Sie deren Adressen durch Löten bestimmter Jumper ändern. Zum Beispiel kann das erste Modul auf 0x40, das zweite auf 0x41 usw. eingestellt werden. Diese Kaskadierungsfähigkeit ermöglicht die Steuerung vieler Servos, ohne zusätzliche Pins am ESP32 zu benötigen.

Zwei PCA9685-Boards verbinden

Wie im obigen Bild gezeigt, stellen Sie sicher, dass Sie diesen Pfad für die PCA9685-Platine 2 (links) löten, um die I2C-Adresse so einzustellen, dass sie sich von der Platine 1 (rechts) unterscheidet.

Datenblattdetails

Hersteller Adafruit
Teilenummer PCA9685
Logik/IO-Spannung 2,3 V bis 5,5 V
Versorgungsspannung 2,3 V bis 5,5 V
Ausgangsstrom (pro Kanal) 25 mA
Spitzenstrom (pro Kanal) 100 mA
PWM-Frequenzanleitung 40 Hz bis 1000 Hz
Eingabelogik-Schwellenwerte 0,3 Vcc (niedrig) / 0,7 Vcc (hoch)
Spannungsabfall / RDS(on)/ Sättigung 0,5 V max
Thermische Grenzen 125 °C max
Paket TSSOP-28
Hinweise / Varianten Bis zu 64 Servos mit Kaskadierung

  • Stellen Sie eine ordnungsgemäße Stromversorgung sicher (5V, 2A empfohlen).
  • Verwenden Sie bei Bedarf Pull-up-Widerstände an den SDA- und SCL-Leitungen.
  • Überprüfen Sie die I2C-Adressen sorgfältig, wenn Sie mehrere PCA9685-Module verwenden.
  • Berücksichtigen Sie eine Wärmeableitung für Hochleistungsanwendungen.
  • Testen Sie die Servos einzeln, um den korrekten Betrieb sicherzustellen.

Übliche I2C-Pin-Zuordnungen:SDA= GPIO 21,SCL= GPIO 22.

Verdrahtungsanweisungen

ESP32 wiring for PCA99685 for 32 sevo motors

Um den PCA9685 und ESP32 zu verdrahten, beginnen Sie mit dem Anschließen von Stromversorgung und Erde. Schließen Sie den positiven Anschluss (V+) des PCA9685 an den 5V-Ausgang Ihres Netzteils. Verbinden Sie die Masse (GND) des PCA9685 mit der Masse des ESP32. Stellen Sie sicher, dass beide Geräte eine gemeinsame Masse haben.

Verbinden Sie als Nächstes für die I2C-Kommunikation den SDA-Pin des PCA9685 mit GPIO 21 des ESP32 und den SCL-Pin mit GPIO 22. Wenn Sie mehrere PCA9685-Module verwenden, stellen Sie sicher, dass sie entsprechend adressiert sind, indem Sie den A0-Jumper löten, um die Adresse des zweiten Moduls auf 0x41 zu ändern, und so weiter. Danach können Sie die Servomotoren nach Bedarf an die PWM-Ausgangs-Pins des PCA9685 anschließen.

Code-Beispiele & Durchlauf

Der Code beginnt mit dem Einfügen notwendiger Bibliotheken und der Initialisierung von zwei PCA9685-Boards. Die Bezeichner wiemaximumServoundservoAngledefiniere die Anzahl der Servos und den aktuellen Winkel.

Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);
int maximumServo = 32; // how many servos are connected

Dieser Auszug zeigt die Initialisierung der PCA9685-Objekte mit ihren jeweiligen Adressen. Die VariablemaximumServolegt die Gesamtzahl der Servos fest, die gesteuert werden können.

In dersetup()Die Funktion, die Platinen werden initialisiert und die Wi-Fi-Verbindung wird hergestellt. Die Anfangsposition aller Servos wird mit einer Schleife eingestellt.

void setup() {
  board1.begin();
  board2.begin();  
  board1.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
  board2.setPWMFreq(60);
  //initial position of all servos
  for(int i=0; i < maximumServo; i++) {
    if(i < 16) {
      board1.setPWM(i, 0, angleToPulse(allServoPosition[i]));
    } else {
      board2.setPWM(i-15, 0, angleToPulse(allServoPosition[i]));
    }
  }
}

Dieser Code konfiguriert die PCA9685-Boards und setzt die PWM-Frequenz. Er initialisiert alle Servos auf ihre Ausgangspositionen, die in derallServoPositionArray.

Schließlich verarbeitet die Hauptschleife eingehende Client-Anfragen, um die Servos basierend auf Benutzereingaben zu steuern.

void loop() {
  server.handleClient();
  if (buttonPushed && (servoNumber >= 0 && servoNumber < maximumServo)) {
    if (servoNumber < 16) {
      board1.setPWM(servoNumber, 0, angleToPulse(allServoPosition[servoNumber]));
    } else {
      board2.setPWM(servoNumber-15, 0, angleToPulse(allServoPosition[servoNumber]));
    }
  }
  buttonPushed = 0;
}

Diese Schleife verarbeitet kontinuierlich Client-Anfragen und aktualisiert die Servopositionen basierend auf dem gedrückten Knopf. Die VariablebuttonPushedwird nach jeder Aktion zurückgesetzt, um eine ordnungsgemäße Steuerung zu gewährleisten.

Für den vollständigen Code verweisen Sie bitte auf den Abschnitt unter dem Artikel.

Demonstration / Was zu erwarten ist

Sobald alles eingerichtet ist, sollten Sie in der Lage sein, jeden Servomotor einzeln oder alle auf einmal über eine Weboberfläche zu steuern. Sie können die Winkel der Servomotoren anpassen, indem Sie auf die Schaltflächen klicken, die jedem Servomotor auf Ihrem Gerät entsprechen. Das System sollte schnell reagieren, aber bedenken Sie, dass Leistungsgrenzen die Leistung beeinträchtigen können (im Video um 14:30).

Häufige Fallstricke sind die korrekte Zuordnung der I2C-Adressen und die ausreichende Stromversorgung der Servos. Wenn die Servos nicht reagieren, überprüfen Sie Ihre Verkabelung und Anschlüsse erneut.

Video-Zeitstempel

  • 00:00 Start
  • 01:19 Einführung
  • 02:32 I2C-Adresse einstellen
  • 05:07 Verdrahtung erklärt
  • 07:44 Vorbereitung der Arduino IDE für ESP32
  • 09:53 Arduino-Code erklärt
  • 25:49 Demonstration auf dem Desktop
  • 31:52 Demonstration auf dem Mobiltelefon

Bilder

PCA9685 module-0
PCA9685 module-0
PCA9685 module-1
PCA9685 module-1
PCA9685 module-2
PCA9685 module-2
PCA9685 module-3
PCA9685 module-3
PCA9685 module
PCA9685 module
ESP32-2
ESP32-2
Connecting two PCA9685 board
Connecting two PCA9685 board
ESP32 wiring for PCA99685 for 32 sevo motors
ESP32 wiring for PCA99685 for 32 sevo motors
881-new- PCA9685 Video V5, Arduino ESP32 Code : Controlling all 32 servo motor over WiFi
Sprache: C++
/*
 * Ursprüngliche PCA9685 Modulbibliotheksquelle: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * Dies ist der Arduino-Code PCA6985 32-Kanal Servosteuerung
 * zur Steuerung von 32 Servomotoren über WiFi mit dem ESP32 MCU.
 * Holen Sie sich diesen Code und die Verdrahtung für dieses Video: http://robojax.com/RJT365
 * 
 * Video zu diesem Code ansehen: https://youtu.be/bvqfv-FrrLM
 * 
 * Verwandte Videos
 * V4 Video von PCA9685 32 Servos mit ESP32: https://youtu.be/JFdXB8Za5Os
 * V3 Video von PCA9685 wie man 32 Servomotoren steuert https://youtu.be/6P21wG7N6t4
 * V2 Video von PCA9685 3 verschiedenen Möglichkeiten zur Steuerung von Servomotoren: https://youtu.be/bal2STaoQ1M
 * V1 Video Einführung in PCA9685 zur Steuerung von 16 Servos https://youtu.be/y8X9X10Tn1k
 * 
 * Geschrieben von Ahmad Shamshiri für den Robojax Video-Kanal www.Robojax.com
 * Datum: 17. Februar 2020, in Ajax, Ontario, Kanada
 * 
 * oder machen Sie eine Spende über PayPal http://robojax.com/L/?id=64
 * 
 * Dieser Code ist "WIE BESEHEN" ohne Gewährleistung oder Haftung. Kostenfrei zu verwenden, solange Sie diese Notiz unverändert lassen.*
 * Dieser Code wurde von Robojax.com heruntergeladen.
 * Dieses Programm ist freie Software: Sie können es weitergeben und/oder ändern
 * unter den Bedingungen der GNU General Public License, die von
 * der Free Software Foundation veröffentlicht wurde, entweder Version 3 der Lizenz oder
 * (nach Ihrer Wahl) jede spätere Version.
 * 
 * Dieses Programm wird in der Hoffnung verbreitet, dass es nützlich sein wird,
 * aber OHNE IRGENDEINE GARANTIE; nicht einmal die implizierte Garantie der
 * MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die
 * GNU General Public License für weitere Details.
 * 
 * Sie sollten eine Kopie der GNU General Public License
 * zusammen mit diesem Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
 * /
 * ////////////////////// PCA9685-Einstellungen gestartet
 */
#include <Wire.h>

#include <Adafruit_PWMServoDriver.h>

 // so genannt, verwendet es die Standardadresse 0x40
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);
int maximumServo = 32; // Wie viele Servos sind angeschlossen?

 // Je nach Ihrem Servomotor-Hersteller können die minimalen und maximalen Pulsweiten variieren, Sie
 // möchte, dass diese so klein/groß wie möglich sind, ohne die harte Grenze zu erreichen
 // für maximale Reichweite. Du musst sie nach Bedarf anpassen, um zu den Servos zu passen, die du
 // haben!
 // Sehen Sie sich Video V1 an, um die beiden Zeilen unten zu verstehen: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN  125 // dies ist die 'Mindest'-Pulslängenanzahl (von 4096)
#define SERVOMAX  575 // dies ist die 'maximale' Pulsdaueranzahl (von 4096)

int servoAngle =0;
int servoStep = 10;

int stepDelay = 50; // 50 Millisekunden
int servoAngleMin =0;
int servoAngleMax = 180;

 // Mindestwinkel jedes Servos
int allServoMin[]={
      0,    0,    0,    0,    0,    0,    0,    0, // 1 bis 8
      0,    0,    0,    0,    0,    0,    0,    0, // 9 bis 16
      0,    0,    0,    0,    0,    0,    0,    0, // 17 bis 24
      0,    0,    0,    0,    0,    0,    0,    0}; // 25 bis 32

 // maximaler Wert jedes Servos
int allServoMax[]={
      180,    180,    180,    180,    180,    180,    180,    180, // 1 bis 8
      180,    180,    180,    180,    180,    180,    180,    180, // 9 bis 16
      180,    180,    180,    180,    180,    180,    180,    180, // 17 bis 24
      180,    180,    180,    180,    180,    180,    180,    180}; // 25 bis 32

 // Ursprungsposition der Servos
int allServoPosition[] ={
      0,    0,    0,    0,    0,    0,    0,    0, // 1 bis 8
      0,    0,    0,    0,    0,    0,    0,    0, // 9 bis 16
      0,    0,    0,    0,    0,    0,    0,    0, // 17 bis 24
      0,    0,    0,    0,    0,    0,    0,    0}; // 25 bis 32

int servoNumber = 100; // Servo bewegen
int buttonPushed =0;
int allServo =0;

void handleServo(); // dies ist der Prototyp einer Funktion, die am Ende dieses Codes definiert ist
int angleToPulse(int ang); // dies ist der Prototyp einer Funktion, die am Ende dieses Codes definiert ist
 // PCA9685 beendet

#include "PCA9684_32Servo_ESP32.h"

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>

const char *ssid = "Robojax";
const char *password = "YouTube2020";

WebServer server(80);

const int led = 13;



 // ///////////////////////////////////
void handleRoot() {

String HTML_page = pageHeader_p1;

 if(allServo)
 {
 HTML_page.concat("<div class=\"btn\"><a class=\"angleButton colorAll\"  href=\"/servo?do=stop\">Stop Servo</a></div>");

 }else{
 HTML_page.concat("<div class=\"btn\"><a class=\"angleButton colorAll\"  href=\"/servo?do=all\">All Servo</a></div>");
 }

 for (int i=0; i < maximumServo; i++)
 {

  HTML_page.concat("<div class=\"btn\"><a class=\"angleButton colorBtn\"  href=\"/servo?move=");
  HTML_page.concat(i);
  HTML_page.concat("\">SRV ");
  HTML_page.concat(i+1);
  HTML_page.concat(" </a></div>");
 }

 HTML_page.concat("</body>\n</html>");
 server.send(200, "text/html", HTML_page);
}

void handleNotFound() {
  digitalWrite(led, 1);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";

  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }

  server.send(404, "text/plain", message);
  digitalWrite(led, 0);
}


void setup() {
  board1.begin();
  board2.begin();
  board1.setPWMFreq(60); // Analoge Servos arbeiten mit ~60 Hz Aktualisierungen.
  board2.setPWMFreq(60);
 // anfängliche Position aller Servos
  for(int i=0; i < maximumServo; i++) {
    if(i < 16)
    {
      board1.setPWM(i, 0, angleToPulse(allServoPosition[i]) );
    }else{
      board2.setPWM(i-15, 0, angleToPulse(allServoPosition[i]) );
    }
  } // für Ende

    Serial.begin(115200);
    Serial.println("32 channel Servo test!");


 // Servo-Steuerung mit ESP32 von Robojax.com

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");


 // Warten auf Verbindung
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());


  if (MDNS.begin("robojaxESP32")) {
    Serial.print("MDNS responder started at http: // ");
    Serial.println("robojaxESP32");
  }

  server.on("/", handleRoot);
  server.on("/servo", HTTP_GET, handleServo);

  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
	server.handleClient();
  if(allServo ){

    for( int angle =servoAngleMin; angle <= servoAngleMax; angle +=servoStep){
      for(int i=0; i<16; i++)
        {

            board2.setPWM(i, 0, angleToPulse(angle) );
            board1.setPWM(i, 0, angleToPulse(angle) );
        }
        delay(stepDelay);
    }

 // robojax PCA9865 32-Kanal Servosteuerung
  delay(100);

  } // wenn gedrückt
  if(false){
  Serial.print("Servo #");
  Serial.print (servoNumber);
  Serial.print(" Angle ");
  Serial.println(allServoPosition[servoNumber]);
  }


  if( buttonPushed && (servoNumber >=0 && servoNumber < maximumServo) ){
    if(servoNumber < 16)
    {
      board1.setPWM(servoNumber, 0, angleToPulse(allServoPosition[servoNumber]) );
    }else{
      board2.setPWM(servoNumber-15, 0, angleToPulse(allServoPosition[servoNumber]) );
    }
  }

   buttonPushed =0;
}



/*
 * handleServo()
 * aktualisiere die Variable buttonPushed
 * gibt nichts zurück
 * Geschrieben von Ahmad Shamshiri am 29. Dezember 2019
 * www.Robojax.com
 * http://youTube.com/robojaxTV
 */
void handleServo() {
  if(server.arg("do") == "all" )
  {
    allServo =1;

  }else{
    allServo =0;
  }
   int servoNumberRequested= server.arg("move").toInt();

  if(servoNumberRequested >=0 && servoNumberRequested < maximumServo)
  {

    buttonPushed = 1;
    if(allServoPosition[servoNumberRequested] == allServoMin[servoNumberRequested] ) {
     allServoPosition[servoNumberRequested] = allServoMax[servoNumberRequested];
    }else{
     allServoPosition[servoNumberRequested] = allServoMin[servoNumberRequested];
    }
    servoNumber =servoNumberRequested;
  }

  handleRoot();
} // handleServo() Ende


/*
 * angleToPulse(int ang)  
 * nimmt den Winkel in Grad und gibt die Pulsbreite zurück  
 * druckt auch den Wert auf dem seriellen Monitor aus  
 * geschrieben von Ahmad Shamshiri für Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX); // Karte den Winkel von 0 bis 180 auf Servo min und Servo max.
 // Serial.print("Winkel: ");Serial.print(ang);
 // Serial.print(" Puls: ");Serial.println(pulse);
   return pulse;
}

Dinge, die Sie vielleicht brauchen

Ressourcen & Referenzen

Dateien📁

Keine Dateien verfügbar.