Questo tutorial è parte di: Controllo di 16 o 32 servomotori con PCA9685
Questa raccolta di tutorial con video ti aiuta a controllare 32 o più servomotori utilizzando Arduino UNO, Nano, Mini o ESP32. Tutti i codici sono forniti.
Controlla 32 servomotori tramite Wi-Fi utilizzando ESP32 e PCA9685 tramite desktop o telefono cellulare V5
In questo tutorial, impareremo come controllare 32 servo motori utilizzando il modulo controller PWM PCA9685 collegato all'ESP32 tramite Wi-Fi. Questa configurazione consente di controllare ogni servo singolarmente o tutti insieme tramite un'interfaccia web accessibile da un dispositivo desktop o mobile. Alla fine di questa guida, avrete un sistema completamente funzionante in grado di gestire più servomotori con facilità.

Il modulo PCA9685 offre un modo semplice per controllare più servomotori utilizzando segnali PWM, mentre l'ESP32 gestisce la comunicazione Wi-Fi e la funzionalità del server web. Sarai in grado di regolare l'angolo di ciascun servomotore attraverso un'interfaccia intuitiva che mostra i pulsanti per ogni servomotore. Per un riferimento visivo, assicurati di dare un'occhiata al video (nel video a 00:00).
Hardware spiegato
Questo progetto utilizza principalmente il microcontrollore ESP32 e il controller PWM PCA9685. L'ESP32 è un microcontrollore potente con capacità Wi-Fi integrate, rendendolo ideale per progetti IoT. Il PCA9685 è un controller PWM a 16 canali che può essere in cascata per controllare fino a 64 servomotori. Comunica con l'ESP32 tramite il protocollo I2C, consentendo di collegare e indirizzare individualmente più controller.
Ogni modulo PCA9685 ha un indirizzo I2C predefinito di 0x40. Quando si utilizzano più moduli, è possibile cambiare i loro indirizzi saldando jumper specifici. Ad esempio, il primo modulo può essere a 0x40, il secondo a 0x41, e così via. Questa capacità di cascata consente il controllo di molti servomotori senza la necessità di ulteriori pin sull'ESP32.
Come mostrato nell'immagine sopra, per la scheda PCA9685 2 (a sinistra), assicurati di saldare quel percorso per impostare l'indirizzo I2C in modo che sia diverso da quello della scheda 1 (a destra).
Dettagli del Foglio Informativo
| Produttore | Adafruit |
|---|---|
| Numero di parte | PCA9685 |
| Tensione logica/IO | 2,3 V a 5,5 V |
| Tensione di alimentazione | 2,3 V a 5,5 V |
| Corrente di uscita (per canale) | 25 mA |
| Corrente di picco (per canale) | 100 mA |
| Guida sulla frequenza PWM | 40 Hz a 1000 Hz |
| Soglie logiche di ingresso | 0,3 Vcc (basso) / 0,7 Vcc (alto) |
| Caduta di tensione / RDS(on)/ saturazione | 0,5 V max |
| Limiti termici | 125 °C max |
| Pacco | TSSOP-28 |
| Note / varianti | Fino a 64 servomotori in cascata |
- Assicurati di fornire un'alimentazione adeguata (5V, 2A raccomandata).
- Utilizzare resistori di pull-up sulle linee SDA e SCL se necessario.
- Controlla attentamente gli indirizzi I2C quando utilizzi più moduli PCA9685.
- Considera il dissipazione di calore per applicazioni ad alta potenza.
- Testa i servomotori singolarmente per garantire un funzionamento corretto.
Mappature comuni dei pin I2C:SDA= GPIO 21,SCL= GPIO 22.
Istruzioni di cablaggio

Per collegare il PCA9685 e l'ESP32, inizia collegando l'alimentazione e la terra. Collega il terminale positivo (V+Collegare il pin VCC del PCA9685 all'uscita di 5V della tua alimentazione. Collegare il ground (GND) del PCA9685 al ground dell'ESP32. Assicurati che entrambi i dispositivi condividano un ground comune.
Successivamente, per la comunicazione I2C, collegare il pin SDA del PCA9685 al GPIO 21 dell'ESP32 e il pin SCL al GPIO 22. Se si utilizzano più moduli PCA9685, assicurarsi che siano indirizzati correttamente saldando il jumper A0 per cambiare l'indirizzo del secondo modulo a 0x41, e così via. Dopo di ciò, è possibile collegare i servomotori ai pin di uscita PWM del PCA9685 come necessario.
Esempi di codice e guida passo-passo
Il codice inizia includendo le librerie necessarie e inizializzando due schede PCA9685. Gli identificatori comemaximumServoeservoAngledefinire il numero di servomotori e l'angolo attuale, rispettivamente.
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);
int maximumServo = 32; // how many servos are connectedQuesto estratto mostra l'inizializzazione degli oggetti PCA9685 con i loro rispettivi indirizzi. La variabilemaximumServoimposta il numero totale di servomotori che possono essere controllati.
In thesetup()funzione, le schede sono inizializzate e la connessione Wi-Fi è stabilita. La posizione iniziale di tutti i servo è impostata utilizzando un ciclo.
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]));
}
}
}Questo codice configura le schede PCA9685 e imposta la frequenza PWM. Inizializza tutti i servo nelle loro posizioni di partenza, che sono definite nelallServoPositionarray.
Infine, il ciclo principale gestisce le richieste dei client in arrivo per controllare i servomotori in base all'input dell'utente.
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;
}Questo ciclo elabora continuamente le richieste dei clienti e aggiorna le posizioni dei servo in base al tasto premuto. La variabilebuttonPushedviene azzerato dopo ogni azione per garantire un controllo adeguato.
Per il codice completo, si prega di fare riferimento alla sezione sottostante dell'articolo.
Dimostrazione / Cosa Aspettarsi
Una volta che tutto è impostato, dovresti essere in grado di controllare ogni servo singolarmente o tutti insieme da un'interfaccia web. Puoi regolare gli angoli dei servomotori cliccando sui pulsanti corrispondenti a ciascun servo sul tuo dispositivo. Il sistema dovrebbe rispondere rapidamente, ma tieni presente che le limitazioni di potenza possono influenzare le prestazioni (nel video alle 14:30).
Le trappole comuni includono assicurarsi che gli indirizzi I2C siano assegnati correttamente e che venga fornita energia sufficiente ai servo. Se i servo non rispondono, controlla di nuovo il cablaggio e le connessioni.
Timestamp video
- 00:00 Inizio
- 01:19 Introduzione
- 02:32 Impostazione dell'indirizzo I2C
- 05:07 Spiegazione del cablaggio
- 07:44 Preparazione dell'IDE Arduino per ESP32
- 09:53 Codice Arduino spiegato
- 25:49 Dimostrazione su desktop
- 31:52 Dimostrazione su telefono cellulare
Questo tutorial è parte di: Controllo di 16 o 32 servomotori con PCA9685
- Codice Arduino e video per il controller per servomotori PCA9685 a 16 canali e 12 bit V1
- Controlla 16 Motori Servo utilizzando un modulo PCA9685 e sketch Arduino V2 #1: Uno per uno
- Controllo di 16 servomotori utilizzando un modulo PCA9685 e uno sketch Arduino V2: Controllo individuale dei servomotori
- Controlling 16 Servo Motors Using a PCA9685 Module and Arduino V2 Sketch #3: All Servos Together
- Controllare un motore servo da 32 utilizzando un modulo PCA9685 e uno sketch Arduino V3 #1: Tutti i servomotori insieme
- Controllare un servomotore da 32 utilizzando un modulo PCA9685 e un ESP32 V4
/*
* Modulo PCA9685 sorgente della libreria originale: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
*
* Questo è il codice Arduino per il controller di servo PCA9685 a 32 canali per controllare 32 motori servo tramite WiFi usando MCU ESP32. Ottieni questo codice e il cablaggio per questo video: http://robojax.com/RJT365
*
* Guarda il video per questo codice: https://youtu.be/bvqfv-FrrLM
*
* Video correlati V4 video di PCA9685 32 Servo con ESP32: https://youtu.be/JFdXB8Za5Os V3 video di PCA9685 come controllare 32 motori servo https://youtu.be/6P21wG7N6t4 V2 Video di PCA9685 3 modi diversi di controllare i motori servo: https://youtu.be/bal2STaoQ1M V1 Video introduzione a PCA9685 per controllare 16 Servo https://youtu.be/y8X9X10Tn1k
*
* Scritto da Ahmad Shamshiri per il canale video Robojax www.Robojax.com Data: 17 febbraio 2020, ad Ajax, Ontario, Canada
*
* oppure fai una donazione utilizzando PayPal http://robojax.com/L/?id=64
*
* Questo codice è "COSÌ COM'È" senza garanzia o responsabilità. Libero di essere utilizzato finché mantieni intatta questa nota.* Questo codice è stato scaricato da Robojax.com Questo programma è software libero: puoi redistribuirlo e/o modificare
* secondo i termini della GNU General Public License come pubblicata dalla Free Software Foundation, sia nella versione 3 della Licenza, o (a tua scelta) qualsiasi versione successiva.
*
* Questo programma è distribuito con la speranza che sia utile, ma SENZA ALCUNA GARANZIA; senza nemmeno la garanzia implicita di MERCEOLOGIA o ADEGUATEZZA PER UN PARTICOLARE SCOPO. Vedi la GNU General Public License per ulteriori dettagli.
*
* Dovresti aver ricevuto una copia della GNU General Public License insieme a questo programma. Se non l'hai ricevuta, vedi <https://www.gnu.org/licenses/>.
* /
* ////////////////////// Impostazioni PCA9685 iniziate
*/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// chiamato in questo modo, utilizza l'indirizzo predefinito 0x40
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver board2 = Adafruit_PWMServoDriver(0x41);
int maximumServo = 32; // quanti servomotori sono collegati
// A seconda della marca del tuo servo, la larghezza dell'impulso minimo e massimo può variare, tu
// voglio che questi siano il più piccoli/grandi possibile senza raggiungere il limite massimo
// per la portata massima. Dovrai ajustarli secondo necessità per adattarli ai servomotori che
// !avere
// Guarda il video V1 per comprendere le due righe sottostanti: http://youtu.be/y8X9X10Tn1k
#define SERVOMIN 125 // questo è il conteggio della lunghezza di impulso 'minima' (su 4096)
#define SERVOMAX 575 // questo è il conteggio della lunghezza massima dell'impulso (su 4096)
int servoAngle =0;
int servoStep = 10;
int stepDelay = 50; // 50 millisecondi
int servoAngleMin =0;
int servoAngleMax = 180;
// angolo minimo di ciascun servomotore
int allServoMin[]={
0, 0, 0, 0, 0, 0, 0, 0, // 1 a 8
0, 0, 0, 0, 0, 0, 0, 0, // 9 a 16
0, 0, 0, 0, 0, 0, 0, 0, // 17 a 24
0, 0, 0, 0, 0, 0, 0, 0}; // 25 a 32
// valore massimo di ciascun servo
int allServoMax[]={
180, 180, 180, 180, 180, 180, 180, 180, // 1 a 8
180, 180, 180, 180, 180, 180, 180, 180, // 9 a 16
180, 180, 180, 180, 180, 180, 180, 180, // 17 a 24
180, 180, 180, 180, 180, 180, 180, 180}; // 25 a 32
// posizione iniziale dei servomotori
int allServoPosition[] ={
0, 0, 0, 0, 0, 0, 0, 0, // 1 a 8
0, 0, 0, 0, 0, 0, 0, 0, // 9 a 16
0, 0, 0, 0, 0, 0, 0, 0, // 17 a 24
0, 0, 0, 0, 0, 0, 0, 0}; // 25 a 32
int servoNumber = 100; // servo per muovere
int buttonPushed =0;
int allServo =0;
void handleServo(); // questo è il prototipo di una funzione definita alla fine di questo codice
int angleToPulse(int ang); // questo è il prototipo di una funzione definita alla fine di questo codice
// //////////////////////PCA9685 terminato
#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); // I servomotori analogici funzionano con aggiornamenti a ~60 Hz.
board2.setPWMFreq(60);
// posizione iniziale di tutti i servomotori
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]) );
}
} // per fine
Serial.begin(115200);
Serial.println("32 channel Servo test!");
// Controllo servo utilizzando ESP32 di Robojax.com
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Aspetta la connessione
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 controllo servo a 32 canali
delay(100);
} // se spinto
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()
* aggiorna la variabile buttonPushed
* non restituisce nulla
* Scritto da Ahmad Shamshiri il 29 dicembre 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() fine
/*
* angleToPulse(int ang)
* ottiene l'angolo in gradi e restituisce la larghezza dell'impulso
* stampa anche il valore sul monitor seriale
* scritto da Ahmad Shamshiri per Robojax, Robojax.com
*/
int angleToPulse(int ang){
int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX); // mappa l'angolo da 0 a 180 ai valori minimi e massimi del Servo
// Angolo: ; ang
// Serial.print(" impulso: ");Serial.println(pulse);
return pulse;
}
Cose di cui potresti avere bisogno
-
AmazonAcquista PCA9685 da Amazonamzn.to
-
AmazonServo motore su Amazonamzn.to
-
eBayAcquista PCA9685 su eBayebay.us
-
AliExpressAcquista il servomotore SG90 da 180 o 360 da AliExpresss.click.aliexpress.com
-
AliExpressAcquista PCA9685 da AliExpresss.click.aliexpress.com
-
BanggoodAcquista PCA9685 da Bangoodbanggood.com
Risorse e riferimenti
-
EsternoPAC9685 Libreria (da GitHub)github.com
File📁
Nessun file disponibile.