شِفر (کود) جستجو

کنترل ۳۲ سروو از راه Wi-Fi با استفاده از ESP32 و PCA9685 از طریق دسکتاپ یا گوشی موبایل V5

کنترل ۳۲ سروو از راه Wi-Fi با استفاده از ESP32 و PCA9685 از طریق دسکتاپ یا گوشی موبایل V5

در این آموزش، یاد خواهیم گرفت که چگونه ۳۲ موتور سرو را با استفاده از ماجیول کنترلر PWM PCA9685 متصل به ESP32 از طریق Wi-Fi کنترل کنیم. این تنظیم امکان کنترل هر سرو به صورت جداگانه یا همه آن‌ها به‌صورت همزمان از طریق یک رابط وب که از طریق دستگاه‌های دسکتاپ یا موبایل در دسترس است را فراهم می‌کند. در پایان این راهنما، شما یک سیستم کاملاً کاربردی خواهید داشت که قادر به مدیریت چندین سرو به راحتی باشد.

PCA9685 module-0

ماجیول PCA9685 راهی ساده برای کنترل چندین سروو با استفاده از سیگنال‌های PWM فراهم می‌کند، در حالی که ESP32 وظیفه ارتباط Wi-Fi و عملکرد سرور وب را بر عهده دارد. شما می‌توانید زاویه هر موتور سروو را از طریق یک رابط کاربری دوست‌داشتنی که دکمه‌هایی برای هر سروو نمایش می‌دهد، تنظیم کنید. برای مرجع بصری، حتماً ویدیو را مشاهده کنید (در ویدیو در 00:00).

توضیح سخت‌افزار

این پروژه عمدتاً از میکروکنترلر ESP32 و کنترل‌کننده PWM PCA9685 استفاده می‌کند. ESP32 میکروکنترلر قدرتمندی است که دارای قابلیت‌های Wi-Fi داخلی است و آن را برای پروژه‌های IoT ایده‌آل می‌سازد. PCA9685 یک کنترل‌کننده PWM 16 کاناله است که می‌تواند به صورت زنجیره‌ای برای کنترل حداکثر 64 سروو استفاده شود. این دستگاه از طریق پروتکل I2C با ESP32 ارتباط برقرار می‌کند که امکان اتصال و آدرس‌دهی جداگانه چندین کنترلر را فراهم می‌کند.

هر ماجیول PCA9685 دارای یک آدرس پیش‌فرض I2C معادل 0x40 است. هنگام استفاده از چندین ماجیول، می‌توانید آدرس‌های آنها را با لحیم‌کاری جامپرهای خاص تغییر دهید. به عنوان مثال، ماجیول اول می‌تواند در 0x40، ماجیول دوم در 0x41 و به همین ترتیب باشد. این قابلیت زنجیره‌ای اجازه می‌دهد تا بسیاری از سروها را بدون نیاز به پایه‌های اضافی بر روی ESP32 کنترل کنید.

اتصال دو صفحه PCA9685

همانطور که در تصویر بالا نشان داده شده است، برای بورد PCA9685 شماره ۲ (در سمت چپ)، مطمئن شوید که آن مسیر را لحیم کنید تا آدرس I2C تنظیم شود و با بورد ۱ (در سمت راست) متفاوت باشد.

جزئیات برگه مشخصات

تولیدکننده آدافرونت
شماره قطعه PCA9685
ولتاژ منطقی/ورودی و خروجی ۲.۳ ولت تا ۵.۵ ولت
ولتاژ تامین ۲.۳ ولت تا ۵.۵ ولت
جریان خروجی (به ازای هر کانال) ۲۵ میلی آمپر
جریان اوج (برای هر کانال) 100 میلی‌آمپر
راهنمایی فرکانس PWM ۴۰ هرتز تا ۱۰۰۰ هرتز
آستانه‌های منطقی ورودی 0.3 ولت Vcc (پایین) / 0.7 ولت Vcc (بالا)
افت ولتاژ / RDS(on)/ اشباع ۰.۵ ولت حداکثر
محدودیت‌های دما حداکثر ۱۲۵ درجه سانتی‌گراد
پکیج TSSOP-28
یادداشت‌ها / واریانت‌ها تا ۶۴ سروو با سسکادینگ

  • تأمین منبع تغذیه مناسب (5 ولت، 2 آمپر توصیه می‌شود).
  • در صورت نیاز از مقاومت‌های کشش به بالا در خطوط SDA و SCL استفاده کنید.
  • هنگام استفاده از چند ماجیول PCA9685، آدرس‌های I2C را به دقت بررسی کنید.
  • به خنک‌سازی حرارتی برای کاربردهای پرقدرت توجه کنید.
  • سروها را به صورت جداگانه آزمایش کنید تا از عملکرد صحیح آنها اطمینان حاصل شود.

نقشه‌برداری پایه‌های رایج I2C:SDA= GPIO 21،SCL= GPIO 22.

دستورالعمل‌های سیم‌کشی

ESP32 wiring for PCA99685 for 32 sevo motors

برای اتصال PCA9685 و ESP32، ابتدا باید منبع تغذیه و زمین را وصل کنید. پایه مثبت (V+) از PCA9685 به خروجی ۵ ولت منبع تغذیه خود وصل کنید. زمین (GND) PCA9685 را به زمین ESP32 وصل کنید. مطمئن شوید که هر دو دستگاه یک زمین مشترک دارند.

سپس، برای ارتباط I2C، پایه SDA PCA9685 را به GPIO 21 روی ESP32 و پایه SCL را به GPIO 22 متصل کنید. اگر از چندین ماجیول PCA9685 استفاده می‌کنید، اطمینان حاصل کنید که آن‌ها به درستی آدرس‌دهی شده‌اند با لحیم کردن جامپر A0 تا آدرس ماجیول دوم به 0x41 تغییر کند و به همین ترتیب. پس از آن، می‌توانید موتورها را به پایه‌های خروجی PWM PCA9685 متصل کنید.

نمونه‌های شِفر (کود) و راهنمایی

شِفر (کود) با وارد کردن کتابخانه‌های لازم و راه‌اندازی دو بورد PCA9685 آغاز می‌شود. شناسه‌هایی مانندmaximumServoوservoAngleتعداد سرووها و زاویه فعلی را به ترتیب تعریف کنید.

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

این بخش نحوه‌ی راه‌اندازی اشیاء PCA9685 را با آدرس‌های مربوطه‌شان نشان می‌دهد. متغیرmaximumServoتعداد کل سرووهایی که می‌توان کنترل کرد را تعیین می‌کند.

در setup()تابع، بوردها راه‌اندازی می‌شوند و اتصال Wi-Fi ایجاد می‌شود. موقعیت اولیه همه سرووها با استفاده از یک حلقه تنظیم می‌شود.

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

این شِفر (کود)، بردهای PCA9685 را پیکربندی کرده و فرکانس PWM را تنظیم می‌کند. همچنین، تمام سرووها را به موقعیت‌های ابتدایی خود که تعریف شده‌اند، راه‌اندازی می‌کند.allServoPositionآرایه.

در نهایت، حلقه اصلی درخواست‌های ورودی مشتری را برای کنترل سروها بر اساس ورودی کاربر مدیریت می‌کند.

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

این حلقه به طور مداوم درخواست‌های مشتری را پردازش کرده و موقعیت‌های سرو را بر اساس دکمه‌ای که فشار داده شده به‌روز می‌کند. متغیرbuttonPushedپس از هر عمل برای اطمینان از کنترل مناسب، دوباره تنظیم می‌شود.

برای شِفر (کود) کامل، لطفاً به بخش زیر مقاله مراجعه کنید.

نمایش / چه چیزی باید انتظار داشت

زمانی که همه چیز آماده شد، باید بتوانید هر سروو را به طور جداگانه یا همه را به طور همزمان از یک واسط وب کنترل کنید. می‌توانید زوایای سرووها را با کلیک بر روی دکمه‌های مربوط به هر سروو در دستگاه خود تنظیم کنید. سیستم باید به سرعت پاسخ دهد، اما به خاطر داشته باشید که محدودیت‌های قدرت می‌توانند بر عملکرد تأثیر بگذارند (در ویدئو در ساعت ۱۴:۳۰).

مشکلات رایج شامل اطمینان از اختصاص صحیح آدرس‌های I2C و اینکه قدرت کافی به سروها تأمین شده است، می‌باشد. اگر سروها پاسخ نمی‌دهند، سیم‌کشی و اتصالات خود را دوباره بررسی کنید.

برچسب‌های زمانی ویدیو

  • ۰۰:۰۰ شروع
  • ۰۱:۱۹ مقدمه
  • تنظیم آدرس I2C 02:32
  • 05:07 توضیح سیم‌کشی
  • 07:44 آماده‌سازی Arduino IDE برای ESP32
  • 09:53 توضیح شِفر (کود) آردوینو
  • 25:49 نمایش بر روی دسکتاپ
  • نمایش در تلفن همراه 31:52

تصاویر

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
زبان: 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;
}

مواردی که ممکن است به آن‌ها نیاز داشته باشید

منابع و مراجع

فایل‌ها📁

هیچ فایلی موجود نیست.