Code de recherche

Contrôlez 32 servomoteurs via Wi-Fi en utilisant ESP32 et PCA9685 depuis un ordinateur de bureau ou un téléphone mobile V5

Contrôlez 32 servomoteurs via Wi-Fi en utilisant ESP32 et PCA9685 depuis un ordinateur de bureau ou un téléphone mobile V5

Dans ce tutoriel, nous allons apprendre comment contrôler 32 servomoteurs en utilisant le module de contrôle PWM PCA9685 connecté à l'ESP32 via Wi-Fi. Cette configuration vous permet de contrôler chaque servomoteur individuellement ou tous en même temps via une interface web accessible depuis un ordinateur de bureau ou un appareil mobile. À la fin de ce guide, vous disposerez d'un système pleinement fonctionnel capable de gérer plusieurs servos avec facilité.

PCA9685 module-0

Le module PCA9685 offre un moyen simple de contrôler plusieurs servomoteurs à l'aide de signaux PWM, tandis que l'ESP32 gère la communication Wi-Fi et les fonctionnalités du serveur web. Vous pourrez ajuster l'angle de chaque servomoteur grâce à une interface conviviale qui affiche des boutons pour chaque servomoteur. Pour une référence visuelle, n'oubliez pas de consulter la vidéo (dans la vidéo à :00).

Matériel Expliqué

Ce projet utilise principalement le microcontrôleur ESP32 et le contrôleur PWM PCA9685. L'ESP32 est un microcontrôleur puissant avec des capacités Wi-Fi intégrées, ce qui le rend idéal pour les projets IoT. Le PCA9685 est un contrôleur PWM à 16 canaux qui peut être mis en cascade pour contrôler jusqu'à 64 servos. Il communique avec l'ESP32 via le protocole I2C, permettant de connecter plusieurs contrôleurs et de les adresser individuellement.

Chaque module PCA9685 a une adresse I2C par défaut de 0x40. Lors de l'utilisation de plusieurs modules, vous pouvez changer leurs adresses en soudant des cavaliers spécifiques. Par exemple, le premier module peut être à 0x40, le second à 0x41, et ainsi de suite. Cette capacité de chaînage permet de contrôler de nombreux servomoteurs sans avoir besoin de broches supplémentaires sur l'ESP32.

Connection de deux cartes PCA9685

Comme montré dans l'image ci-dessus, pour la carte PCA9685 2 (à gauche), assurez-vous de souder ce chemin pour définir l'adresse I2C afin qu'elle soit différente de celle de la carte 1 (à droite).

Détails de la fiche technique

Fabricant Adafruit
Numéro de pièce PCA9685
Tension logique/IO 2,3 V à 5,5 V
Tension d'alimentation 2.3 V à 5.5 V
Courant de sortie (par canal) 25 mA
Courant de crête (par canal) 100 mA
Guide de fréquence PWM 40 Hz à 1000 Hz
Seuils logiques d'entrée 0,3 Vcc (bas) / 0,7 Vcc (haut)
Chute de tension / RDS(on)/ saturation 0,5 V max
Limites thermiques 125 °C max
Paquet TSSOP-28
Notes / variantes Jusqu'à 64 servomoteurs en cascade

  • Assurez-vous d'une alimentation correcte (5V, 2A recommandée).
  • Utilisez des résistances de tirage sur les lignes SDA et SCL si nécessaire.
  • Vérifiez les adresses I2C avec soin lors de l'utilisation de plusieurs modules PCA9685.
  • Considérez le dissipateur thermique pour les applications haute puissance.
  • Testez les servos individuellement pour vous assurer de leur bon fonctionnement.

Mappings de broches I2C courants :SDA= GPIO 21,SCL= GPIO 22.

Instructions de câblage

ESP32 wiring for PCA99685 for 32 sevo motors

Pour câbler le PCA9685 et l'ESP32, commencez par connecter l'alimentation et la masse. Connectez la borne positive (V+) du PCA9685 à la sortie 5V de votre alimentation. Connectez le ground (GND) du PCA9685 au ground de l'ESP32. Assurez-vous que les deux appareils partagent une mise à la terre commune.

Ensuite, pour la communication I2C, connectez la broche SDA du PCA9685 au GPIO 21 de l'ESP32 et la broche SCL au GPIO 22. Si vous utilisez plusieurs modules PCA9685, assurez-vous qu'ils sont correctement adressés en soudant le cavalier A0 pour changer l'adresse du deuxième module à 0x41, et ainsi de suite. Après cela, vous pouvez connecter les servomoteurs aux broches de sortie PWM du PCA9685 selon vos besoins.

Exemples de code et guide étape par étape

Le code commence par inclure les bibliothèques nécessaires et initialiser deux cartes PCA9685. Les identifiants tels quemaximumServoetservoAngledéfinir le nombre de servos et l'angle actuel, respectivement.

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

Cet extrait montre l'initialisation des objets PCA9685 avec leurs adresses respectives. La variablemaximumServodéfinit le nombre total de servomoteurs qui peuvent être contrôlés.

Dans lesetup()fonction, les cartes sont initialisées et la connexion Wi-Fi est établie. La position initiale de tous les servomoteurs est définie à l'aide d'une boucle.

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]));
    }
  }
}

Ce code configure les cartes PCA9685 et définit la fréquence PWM. Il initialise tous les servos à leurs positions de départ, qui sont définies dans leallServoPositiontableau.

Enfin, la boucle principale gère les demandes des clients entrantes pour contrôler les servos en fonction des entrées de l'utilisateur.

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;
}

Cette boucle traite en continu les demandes des clients et met à jour les positions des servos en fonction du bouton pressé. La variablebuttonPushedest réinitialisé après chaque action pour garantir un contrôle adéquat.

Pour le code complet, veuillez vous référer à la section ci-dessous l'article.

Démonstration / À quoi s'attendre

Une fois que tout est configuré, vous devriez pouvoir contrôler chaque servo individuellement ou tous en même temps depuis une interface web. Vous pouvez ajuster les angles des servos en cliquant sur les boutons correspondants à chaque servo sur votre appareil. Le système devrait répondre rapidement, mais gardez à l'esprit que les limitations de puissance peuvent affecter les performances (dans la vidéo à 14:30).

Les pièges courants incluent s'assurer que les adresses I2C sont correctement attribuées et qu'une alimentation suffisante est fournie aux servos. Si les servos ne répondent pas, vérifiez à nouveau votre câblage et vos connexions.

Horodatages vidéo

  • 00:00 Début
  • 01:19 Introduction
  • 02:32 Réglage de l'adresse I2C
  • 05:07 Câblage expliqué
  • 07:44 Préparation de l'IDE Arduino pour l'ESP32
  • 09:53 Code Arduino expliqué
  • 25:49 Démonstration sur bureau
  • 31:52 Démonstration sur téléphone mobile

Images

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
Langue: C++
/*
* Original PCA9685 Module library source: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * This is the Arduino code PCA6985 32 channel servo controller
 * to control 32 Servo Motors over WiFi using ESP32 MCU
 *  get this code and wiring from for this video:  http://robojax.com/RJT365

 * Watch video for this code:  https://youtu.be/bvqfv-FrrLM
 * 
 * Related Videos
V4 video of PCA9685 32 Servo with ESP32: https://youtu.be/JFdXB8Za5Os
V3 video of PCA9685 how to control 32 Servo motors https://youtu.be/6P21wG7N6t4
V2 Video of PCA9685 3 different ways to control Servo motors: https://youtu.be/bal2STaoQ1M
V1 Video introduction to PCA9685 to control 16 Servo  https://youtu.be/y8X9X10Tn1k
 *  
 * Written by Ahmad Shamshiri for Robojax Video channel www.Robojax.com
 * Date: Feb 17, 2020, in Ajax, Ontario, Canada



or make donation using PayPal http://robojax.com/L/?id=64

 *  * This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
 * This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
////////////////////// PCA9685 settings started
#include <Wire.h>

#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);
int maximumServo = 32;//how many servos are connected

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
// Watch video V1 to understand the two lines below: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)

int servoAngle =0;
int servoStep = 10;

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

// minimum angle of each servo     
int allServoMin[]={
      0,    0,    0,    0,    0,    0,    0,    0,// 1 to 8
      0,    0,    0,    0,    0,    0,    0,    0,//9 to 16
      0,    0,    0,    0,    0,    0,    0,    0,//17 to 24
      0,    0,    0,    0,    0,    0,    0,    0};//25 to 32                   

//maximum value of each servo
int allServoMax[]={
      180,    180,    180,    180,    180,    180,    180,    180,// 1 to 8 
      180,    180,    180,    180,    180,    180,    180,    180,//9 to 16
      180,    180,    180,    180,    180,    180,    180,    180,//17 to 24 
      180,    180,    180,    180,    180,    180,    180,    180};//25 to 32 

// initial position of servos      
int allServoPosition[] ={
      0,    0,    0,    0,    0,    0,    0,    0,// 1 to 8
      0,    0,    0,    0,    0,    0,    0,    0,//9 to 16
      0,    0,    0,    0,    0,    0,    0,    0,//17 to 24
      0,    0,    0,    0,    0,    0,    0,    0};//25 to 32               

int servoNumber = 100;//servo to move
int buttonPushed =0;
int allServo =0;

void handleServo();//this is prototype of function defined at the end of this code
int angleToPulse(int ang); //this is prototype of function defined at the end of this code
////////////////////////PCA9685 ended

#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);  // 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]) );       
    }
  }//for end
    
    Serial.begin(115200);
    Serial.println("32 channel Servo test!");
	

  //Servo control using ESP32 from Robojax.com

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  
    
  // Wait for connection
  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 channel Servo control
  delay(100);        

  }//if pushed
  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()
 * update the buttonPushed varialbe
 * returns nothing
 * Written by Ahmad Shamshiri on Dec 29, 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() end


/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on seial monitor
 * written by Ahmad Shamshiri for Robojax, Robojax.com
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max 
   //Serial.print("Angle: ");Serial.print(ang);
   //Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}

Ce dont vous pourriez avoir besoin

Ressources et références

Fichiers📁

Aucun fichier disponible.