Ce tutoriel fait partie de: Commande de 16 ou 32 servomoteurs avec PCA9685
Cette collection de tutoriels vidéo vous aide à contrôler 32 servomoteurs ou plus à l'aide d'Arduino UNO, Nano, Mini ou ESP32. Tous les codes sont fournis.
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é.

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.
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

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 connectedCet 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
Ce tutoriel fait partie de: Commande de 16 ou 32 servomoteurs avec PCA9685
- Code Arduino et vidéo pour le contrôleur de servomoteurs PCA9685 16 canaux 12 bits V1
- Contrôlez 16 servomoteurs à l'aide d'un module PCA9685 et du croquis Arduino V2 #1 : Un par un
- Contrôler 16 moteurs servo à l'aide d'un module PCA9685 et d'un croquis Arduino V2 : Contrôle individuel des servos
- Controlling 16 Servo Motors Using a PCA9685 Module and Arduino V2 Sketch #3: All Servos Together
- Contrôler un moteur servo 32 en utilisant un module PCA9685 et un croquis Arduino V3 #1 : Tous les servos ensemble
- Contrôler un moteur servo 32 à l'aide d'un module PCA9685 et d'un ESP32 V4
/*
* 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
-
AmazonAcheter le PCA9685 sur Amazonamzn.to
-
AmazonMoteur servo sur Amazonamzn.to
-
eBayAchetez le PCA9685 sur eBayebay.us
-
AliExpressAcheter PCA9685 sur AliExpresss.click.aliexpress.com
-
AliExpressAchetez le moteur servo SG90 180 ou 360 sur AliExpress.s.click.aliexpress.com
-
BanggoodAcheter PCA9685 sur Bangoodbanggood.com
Ressources et références
-
ExterneBibliothèque PAC9685 (de GitHub)github.com
Fichiers📁
Aucun fichier disponible.