كود البحث

التحكم في 32 سيرفو عبر الواي فاي باستخدام ESP32 و PCA9685 من خلال الكمبيوتر المكتبي أو الهاتف المحمول V5

التحكم في 32 سيرفو عبر الواي فاي باستخدام ESP32 و PCA9685 من خلال الكمبيوتر المكتبي أو الهاتف المحمول V5

في هذا الدليل، سنتعلم كيف نتحكم في 32 محرك سيرفو باستخدام وحدة تحكم PWM PCA9685 المتصلة بـ ESP32 عبر الواي فاي. تتيح لك هذه الإعدادات التحكم في كل سيرفو بشكل فردي أو جميعها دفعة واحدة من خلال واجهة ويب يمكن الوصول إليها من جهاز كمبيوتر مكتبي أو جهاز محمول. بنهاية هذا الدليل، سيكون لديك نظام كامل الوظائف قادر على إدارة عدة محركات سيرفو بسهولة.

PCA9685 module-0

يقدم وحدة PCA9685 طريقة بسيطة للتحكم في عدة سيرفو باستخدام إشارات PWM، بينما يتولى ESP32 التواصل عبر الواي فاي ووظائف خادم الويب. ستتمكن من ضبط زاوية كل محرك سيرفو من خلال واجهة سهلة الاستخدام تعرض أزرارًا لكل سيرفو. للرجوع البصري، تأكد من مشاهدة الفيديو (في الفيديو عند 00:00).

شرح الأجهزة

يستخدم هذا المشروع بشكل أساسي متحكم ESP32 الدقيق ووحدة التحكم PWM PCA9685. يعد ESP32 متحكمًا قويًا مزودًا بإمكانيات واي فاي مدمجة، مما يجعله مثاليًا لمشاريع إنترنت الأشياء. PCA9685 هو وحدة تحكم PWM ذات 16 قناة يمكن توصيلها ببعضها للتحكم في ما يصل إلى 64 سيرفو. يتواصل مع ESP32 عبر بروتوكول I2C، مما يسمح بتوصيل العديد من الوحدات والتحكم فيها بشكل فردي.

كل وحدة PCA9685 لها عنوان I2C افتراضي هو 0x40. عند استخدام وحدات متعددة، يمكنك تغيير عناوينها عن طريق لحام موصلات معينة. على سبيل المثال، يمكن أن تكون الوحدة الأولى على 0x40، والثانية على 0x41، وهكذا. تمكّن هذه القدرة على التسلسل من التحكم في العديد من السيرفو بدون الحاجة إلى دبابيس إضافية على ESP32.

توصيل لوحي PCA9685 اثنين

كما هو موضح في الصورة أعلاه، بالنسبة لقرص PCA9685 رقم 2 (على اليسار)، تأكد من لحام تلك المسار لضبط عنوان I2C بحيث يكون مختلفًا عن القرص 1 (على اليمين).

تفاصيل ورقة البيانات

الشركة المصنعة أدا فروت
رقم الجزء PCA9685
فولتية المنطق/الإدخال والإخراج 2.3 فولت إلى 5.5 فولت
جهد الإمداد 2.3 فولت إلى 5.5 فولت
تيار الخرج (لكل قناة) ٢٥ مللي أمبير
ذروة التيار (لكل قناة) 100 مللي أمبير
إرشادات تردد PWM 40 هرتز إلى 1000 هرتز
عتبات منطق الإدخال 0.3 فولت (منخفض) / 0.7 فولت (مرتفع)
انخفاض الجهد / RDS(on)/ التشبع 0.5 فولت كحد أقصى
الحدود الحرارية 125 °م كحد أقصى
حزمة TSSOP-28
ملاحظات / متغيرات ما يصل إلى 64 سيرفو مع ترابط

  • تأكد من توفير الطاقة المناسبة (5 فولت، 2 أمبير مستحسن).
  • استخدم مقاومات السحب لأعلى على خطوط SDA و SCL إذا لزم الأمر.
  • تحقق من عناوين I2C بعناية عند استخدام وحدات PCA9685 متعددة.
  • اعتبر تبديد الحرارة للتطبيقات عالية القدرة.
  • اختبر السيرفوهات بشكل فردي لضمان عملها بشكل صحيح.

تعيينات الدبابيس الشائعة لـ I2C:SDA= GPIO 21،SCL= GPIO 22.

تعليمات التوصيل

ESP32 wiring for PCA99685 for 32 sevo motors

لتهيئة PCA9685 و ESP32، ابدأ بتوصيل الطاقة والأرض. قم بتوصيل الطرف الموجب (V+قم بتوصيل الدبوس VCC من PCA9685 بمخرج 5V من مصدر الطاقة الخاص بك. قم بتوصيل الأرضي (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()تتم تهيئة اللوحات، ويتم establishes الاتصال بشبكة الواي فاي. تم تعيين الموضع الابتدائي لجميع المحركات باستخدام حلقة.

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يتم إعادة تعيينه بعد كل إجراء لضمان التحكم السليم.

للحصول على الكود الكامل، يرجى الرجوع إلى القسم الموجود أسفل المقال.

عرض / ماذا تتوقع

بمجرد إعداد كل شيء، يجب أن تكون قادرًا على التحكم في كل سيرفو بشكل فردي أو جميعًا مرة واحدة من واجهة ويب. يمكنك ضبط زوايا السيرفوات من خلال النقر على الأزرار المقابلة لكل سيرفو على جهازك. يجب أن يستجيب النظام بسرعة، ولكن تذكر أن قيود الطاقة يمكن أن تؤثر على الأداء (في الفيديو عند 14:30).

تشمل الأخطاء الشائعة التأكد من تعيين عناوين I2C بشكل صحيح وأنه يتم توفير طاقة كافية للخدمات. إذا لم تستجب الخدمات، تحقق مرة أخرى من التوصيلات والأسلاك الخاصة بك.

طوابع الزمن في الفيديو

  • :00 بداية
  • 01:19 مقدمة
  • :32 إعداد عنوان I2C
  • 05:07 شرح الأسلاك
  • 07:44 إعداد Arduino IDE لـ ESP32
  • 09:53 شرح كود الأردوينو
  • 25:49 عرض على سطح المكتب
  • :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;
}

الأشياء التي قد تحتاجها

الموارد والمراجع

ملفات📁

لا توجد ملفات متاحة.