使用PCA9685控制多个舵机

todolist
在这里插入图片描述要单独去找舵机的两个极值的大小,然后去该前文的映射的初始值
在这里插入图片描述
在这里插入图片描述

把角度值打印出来
在这里插入图片描述

0.准备

0.1.硬件设备
0.2.软件安装

1.安装好Arduino IDE
可以前往Arduino官网下载安装,支持windows、macos、linux系统;
在这里插入图片描述2.在Arduino IDE内配置相关的库(也可以到Adafruit PWM Servo Driver Library代码库中下载源码,但是要自己配置路径,所以不推荐 )
在Arduino IDE中依次打开:工具(Tools)-库管理(Library manager)然后搜索Adafruit PWM Servo Driver Library然后选择最新的版本安装就行;
请添加图片描述然后打开Adafruit PWM Servo Driver Library自带的一个案例
在Arduino IDE中依次打开:文件(File)-案例(Example)- Adafruit PWM Servo Driver Library - servo
这个案例也是我们要展示的第一个案例,利用PCA9685,控制八个舵机,并让他们依次完成正转和反转的运动;
请添加图片描述

0.3.硬件连接

请按照如下图实物图所示连接板子
请添加图片描述
请添加图片描述

0.单独使用arduino控制舵机转动

舵机0~180°来回转动。

#include <Servo.h>            //加载文件库
int pos = 0;
Servo myservo;
 
void setup()
{
  myservo.attach(9, 500, 2500);          //修正脉冲宽度
}
 
void loop()
{
  for (pos = 0; pos <= 180; pos += 1) {       //pos+=1等价于pos=pos+1
    myservo.write(pos);
    delay(15);					
  }
  for (pos = 180; pos >= 0; pos -= 1) {
    myservo.write(pos);
    delay(15); 					
  }
}

在这里插入图片描述

舵机单独在一个度数,例如90度

#include <Servo.h> //引入lib
 
Servo myservo;  // 创建一个伺服电机对象
 
char inByte = 0; //串口接收的数据
int angle = 90;  //角度值
String temp = "";//临时字符变量,又或者说是缓存用的吧
 
void setup() 
{
  myservo.attach(9);    //定义舵机的引脚为9,舵机只能是10,或者9引脚
  Serial.begin(9600);  //设置波特率
}
 
 
void loop() 
{
  while (Serial.available() > 0) //判断串口是否有数据
  {
    inByte = Serial.read();//读取数据,串口一次只能读1个字符
    temp += inByte;//把读到的字符存进临时变量里面缓存,
                   //再继续判断串口还有没有数据,知道把所有数据都读取出来
   }
 
   if(temp != "")   //判断临时变量是否为空
   {
    angle = temp.toInt();    //把变量字符串类型转成整型
    Serial.println(angle);  //输出数据到串口上,以便观察
   }
  temp = "";//请看临时变量
  myservo.write(angle);  //控制舵机转动相应的角度。
  delay(100);//延时100毫秒
}

在这里插入图片描述

1.使用一块PCA9685,控制一个舵机转动

1.1实物演示过程:

请添加图片描述

1.2代码:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN  125 
#define SERVOMAX  575 
uint8_t servonum = 0;
void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");
  pwm.begin();
  pwm.setPWMFreq(60); 
}
void loop() {
  for( int angle =0; angle<181; angle +=20){
    delay(500);
    pwm.setPWM(0, 0, angleToPulse(angle) );
  }
  delay(1000);
}
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}

 
1.3带注释代码:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// called this way, it uses the default address 0x40 通过这种方式调用,它使用默认地址0x40通过这种方式调用,它使用默认地址0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// 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!
// 你也可以调用它与不同的地址,你想Adafruit_PWMServoDriver pwm= Adafruit_PWMServoDriver(0x41);
// 根据您的伺服制造,脉冲宽度最小和最大可能会有所不同,您希望这些尽可能小/大,而不击中最大范围的硬停止。
// 你将不得不调整他们作为必要的配合你的伺服!
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096) 这是“最小”脉冲长度计数(4096)
#define SERVOMAX  575 // this is the 'maximum' pulse length count (out of 4096)这是“大”脉冲长度计数(4096)
// our servo # counter 我们的伺服计数器
uint8_t servonum = 0;
void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");
  pwm.begin();
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates 模拟伺服运行在~ 60hz更新
  //yield();
}

void loop() {
  for( int angle =0; angle<181; angle +=20){
    delay(500);
    pwm.setPWM(0, 0, angleToPulse(angle) );
  }
  delay(1000);
}
/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on seial monitor
 */
int angleToPulse(int ang){
   int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max  映射角度0到180伺服min和伺服max
   Serial.print("Angle: ");Serial.print(ang);
   Serial.print(" pulse: ");Serial.println(pulse);
   return pulse;
}

 
1.4另外一种实现代码
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// 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!
#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)
// our servo # counter
uint8_t servonum = 0;
void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  //yield();
}

void loop() {

    pwm.setPWM(0, 0, 125 );
  delay(500);
    pwm.setPWM(0, 0, 255 );
  delay(500);
    pwm.setPWM(0, 0, 450 );
  delay(500);
    pwm.setPWM(0, 0, 575 );
  delay(500); 

}

2.使用一块PCA9685,控制十六个舵机,实现十六个舵机的依次转动

2.1实物演示过程:

请添加图片描述

2.2代码:
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN  150 
#define SERVOMAX  600 
#define USMIN  600 
#define USMAX  2400 
#define SERVO_FREQ 50 
uint8_t servonum = 0;
void setup() {
  Serial.begin(9600);
  Serial.println("8 channel Servo test!");
  pwm.begin();
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ); 
  delay(10);
}
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  pulselength = 1000000;   
  pulselength /= SERVO_FREQ;   
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000000;  
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}
void loop() {
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }
  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }
  delay(500);
  for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);
  for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
    pwm.writeMicroseconds(servonum, microsec);
  }
  delay(500);
  servonum++;
  if (servonum > 7) servonum = 0; 
}
2.3带注释的代码:

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 8 servos, one after the other on the
  first 8 pins of the PCA9685
  这是我们的Adafruit 16通道PWM和伺服驱动器伺服测试的一个例子-这将驱动8个伺服,一个接一个在PCA9685的前8引脚上
  Pick one up today in the adafruit shop! 今天去adafruit店买一个吧
  ------> http://www.adafruit.com/products/815
  These drivers use I2C to communicate, 2 pins are required to  
  interface.
  #这些驱动程序使用I2C进行通信,需要2个引脚进行接口。
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!
  #Adafruit投入了时间和资源来提供这个开放源代码,请通过购买Adafruit的产品来支持Adafruit和开源硬件
  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
  #由Limor Fried/Ladyada为Adafruit Industries编写。BSD许可,以上所有文本必须包含在任何重分发中
 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

  // called this way, it uses the default address 0x40 #通过这种方式调用,它使用默认地址0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
  // you can also call it with a different address you want #你也可以用你想要的另一个地址打电话
  //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
  // you can also call it with a different address and I2C interface #你也可以用不同的地址和I2C接口调用它
  //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire);
  // 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!
  // #而不击中硬停止最大范围。您必须根据需要调整它们以匹配您拥有的伺服!

#define SERVOMIN  150 // This is the 'minimum' pulse length count (out of 4096) #这是“最小”脉冲长度计数(4096)
#define SERVOMAX  600 // This is the 'maximum' pulse length count (out of 4096) #这是“最大”脉冲长度计数(4096)
#define USMIN  600    // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
                      // #这是基于150最小脉冲的四舍五入的“最小”微秒长度
#define USMAX  2400   // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
                      // #这是基于最大脉冲600的四舍五入的“最大”微秒长度
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates #模拟伺服运行在~50赫兹更新

// our servo # counter #我们的伺服计数器
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("8 channel Servo test!");

  pwm.begin();
  /*
   * In theory the internal oscillator (clock) is 25MHz but it really isn't
   * that precise. You can 'calibrate' this by tweaking this number until
   * you get the PWM update frequency you're expecting!
   *  #理论上,内部振荡器(时钟)是25MHz,但它真的没有那么精确。你可以通过调整这个数字“校准”,直到你得到你期待的PWM更新频率!
   * The int.osc. for the PCA9685 chip is a range between about 23-27MHz and
   * is used for calculating things like writeMicroseconds()
   * #int.osc。用于PCA9685芯片的是一个大约23-27MHz的范围,用于计算像写微秒()
   * Analog servos run at ~50 Hz updates, It is importaint to use an
   * oscilloscope in setting the int.osc frequency for the I2C PCA9685 chip.
   *  #模拟伺服运行在~ 50hz更新,这是重要的使用示波器设置int。用于I2C PCA9685芯片的osc频率。
   * 1) Attach the oscilloscope to one of the PWM signal pins and ground on
   *    the I2C PCA9685 chip you are setting the value for.
   *    #将示波器连接到PWM信号引脚中的一个,并接地在I2C PCA9685芯片上,您正在设置的值。
   * 2) Adjust setOscillatorFrequency() until the PWM update frequency is the
   *    expected value (50Hz for most ESCs)
   *    #调整setOscillatorFrequency()直到PWM更新频率为期望值(大多数esc为50Hz)
   * Setting the value here is specific to each individual I2C PCA9685 chip and
   * affects the calculations for the PWM update frequency. 
   *  #此处设置的值针对每个I2C PCA9685芯片,会影响PWM更新频率的计算。
   * Failure to correctly set the int.osc value will cause unexpected PWM results
   *  #未能正确设置int.osc值会导致意想不到的PWM结果
   */
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates #模拟伺服运行在~50赫兹更新

  delay(10);
}

// You can use this function if you'd like to set the pulse length in seconds 
// #如果你想设置以秒为单位的脉冲长度,你可以使用这个函数
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
// #例如setServoPulse(0,0.001)是~1毫秒的脉冲宽度。它并不精确

void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  
  pulselength = 1000000;       // 1,000,000 us per second #每秒1,000,000个单位
  pulselength /= SERVO_FREQ;   // Analog servos run at ~60 Hz updates #模拟伺服运行在~ 60hz更新
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;         // 12 bits of resolution #12位分辨率
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000000;            // convert input seconds to us #将输入秒转换为我们
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}

void loop() {
  // Drive each servo one at a time using setPWM() #使用setPWM()一次驱动每个伺服
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);

  // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding!
  // #每次使用writemmicroseconds()驱动每个伺服,由于计算舍入不精确每次使用writemmicroseconds()驱动每个伺服,
  // #由于计算舍入不精确每次使用writemmicroseconds()驱动每个伺服,由于计算舍入不精确
  // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. 
  // #writeMicroseconds()函数用于模拟Arduino Servo库的writeMicroseconds()行为。
  writeMicroseconds()
  for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);
  for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);

  servonum++;
  if (servonum > 7) servonum = 0; // Testing the first 8 servo channels
}

3.使用一块PCA9685,控制十六个舵机,实现十六个舵机的依次转动请添加图片描述#### 3.1代码

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40 通过这种方式调用,它使用默认地址0x40通过这种方式调用,它使用默认地址0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// 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!
#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)

// our servo # counter
uint8_t servonum = 0;

void setup() {
Serial.begin(9600);
Serial.println(“16 channel Servo test!”);

pwm.begin();

pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates

//yield();
}

void loop() {

for(int i=0; i<16; i++) //这里就是依次控制从0号到15号舵机
{
for( int angle =0; angle<181; angle +=10){ //舵机角度从零开始每50ms增加10度
delay(50);
pwm.setPWM(i, 0, angleToPulse(angle) );//舵机角度置零
}
}

delay(1000);// wait for 1 second

}

/*
/* angleToPulse(int ang)

  • @brief gets angle in degree and returns the pulse width
  • @param “ang” is integer represending angle from 0 to 180
  • @return returns integer pulse width
  • Usage to use 65 degree: angleToPulse(65);
    */

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

4.使用一块PCA9685,控制十六个舵机,实现十六个舵机的同时转动

/*
 * Original sourse: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * This is the Arduino code PAC6985 16 channel servo controller
 * watch the video for details (V1) and demo http://youtu.be/y8X9X10Tn1k
 *  This code is #3 for V2 Video Watch the video :
 *  I have got 3 codes as follow:https://youtu.be/bal2STaoQ1M
 *  
   #1-Arduino Code to run one by one all servos from 0 to 180°   
   #2-Arduino Code to control specific servos with specific angle
   #3-Arduino Code to run 2 or all servos at together
   
 * Written/updated by Ahmad Shamshiri for Robojax Video channel www.Robojax.com
 * Date: Dec 16, 2017, in Ajax, Ontario, Canada
 * Permission granted to share this code given that this
 * note is kept with the code.
 
  * Watch video for this code: 
 * 
 * Related Videos
V5 video of PCA9685 32 Servo with ESP32 with WiFi https://youtu.be/bvqfv-FrrLM
V4 video of PCA9685 32 Servo with ESP32 (no WiFi): 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

 * Disclaimer: this code is "AS IS" and for educational purpose only.
 * this code has been downloaded from http://robojax.com/learn/arduino/
 
 * Get this code and other Arduino codes from Robojax.com
Learn Arduino step by step in structured course with all material, wiring diagram and library
all in once place. Purchase My course on Udemy.com http://robojax.com/L/?id=62

****************************
Get early access to my videos via Patreon and have  your name mentioned at end of very 
videos I publish on YouTube here: http://robojax.com/L/?id=63 (watch until end of this video to list of my Patrons)
****************************

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/>.
 */
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

// 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)

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {

    //watch video for details: https://youtu.be/bal2STaoQ1M
    for( int angle =0; angle<181; angle +=10){
      delay(50);
      for(int i=0; i<16; i++)
        {      
          pwm.setPWM(i, 0, angleToPulse(angle) );
        }
    }
 

  
// robojax PCA9865 16 channel Servo control
  delay(1000);
 
}

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

5.使用一块PCA9685,控制三十二个舵机,实现三十二个舵机的同时转动

 /*
 * Original sourse: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
 * 
 * This is the Arduino code PCA6985 16 channel servo controller
 * to control 32 Servo Motors
 * This is V3 Video on PCA9685: https://youtu.be/6P21wG7N6t4
 * 
 * watch the video for details (V1) and demo http://youtu.be/y8X9X10Tn1k
 * Watch Video V2 :https://youtu.be/bal2STaoQ1M
 *  
   
 * Written/updated by Ahmad Shamshiri for Robojax Video channel www.Robojax.com
 * Date: Dec 15, 2019, in Ajax, Ontario, Canada

 * Watch video for this code: 
 * 
 * Related Videos
V5 video of PCA9685 32 Servo with ESP32 with WiFi https://youtu.be/bvqfv-FrrLM
V4 video of PCA9685 32 Servo with ESP32 (no WiFi): 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
 * Disclaimer: this code is "AS IS" and for educational purpose only.
 * this code has been downloaded from http://robojax.com/learn/arduino/
 
 * Get this code and other Arduino codes from Robojax.com
Learn Arduino step by step in structured course with all material, wiring diagram and library
all in once place. Purchase My course on Udemy.com http://robojax.com/L/?id=62

****************************
Get early access to my videos via Patreon and have  your name mentioned at end of very 
videos I publish on YouTube here: http://robojax.com/L/?id=63 (watch until end of this video to list of my Patrons)
****************************

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/>.
 */
#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);

// 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 servoNumber = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  board1.begin();
  board2.begin();  
  board1.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
  board2.setPWMFreq(60);
  //yield();
}

// the code inside loop() has been updated by Robojax
void loop() {


    for( int angle =0; angle<181; angle +=10){
      for(int i=0; i<16; i++)
        {      
            board2.setPWM(i, 0, angleToPulse(angle) );
            board1.setPWM(i, 0, angleToPulse(angle) );
        }
    }
  
// robojax PCA9865 16 channel Servo control
  delay(100);
 
}

/*
 * angleToPulse(int ang)
 * gets angle in degree and returns the pulse width
 * also prints the value on seial monitor
 * written by Ahmad Nejrabi 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;
}
 

参考:http://robojax.com/learn/arduino/

<think>我们正在使用ESP32和PCA9685模块来控制多路舵机。根据引用[2]和引用[4],PCA9685是一个常用的舵机驱动板,可以通过I2C接口控制多达16路舵机。ESP32可以通过I2C与PCA9685通信。步骤:1.硬件连接:-将PCA9685的VCC连接到ESP32的3.3V或5V(注意:舵机通常需要5V供电,但逻辑电平可以是3.3V,所以如果舵机不多,可以用ESP32的5V输出,否则建议外接电源)。-GND连接到ESP32的GND。-SDA连接到ESP32的SDA引脚(例如GPIO21)。-SCL连接到ESP32的SCL引脚(例如GPIO22)。2.软件部分:-我们需要使用一个库来简化PCA9685控制。在MicroPython中,我们可以使用`micropython-pca9685`库。示例代码(MicroPython):首先,确保你已经将PCA9685的MicroPython驱动库上传到ESP32。如果没有,可以下载并上传。代码示例:```pythonfrommachineimportPin,I2Cimporttimefrompca9685importPCA9685#初始化I2C,使用默认引脚(SDA=21,SCL=22)或者指定引脚i2c=I2C(scl=Pin(22),sda=Pin(21),freq=100000)#创建PCA9685对象,地址通常是0x40(可以通过I2C扫描得到)pca=PCA9685(i2c,address=0x40)#设置PWM频率(舵机通常使用50Hz)pca.freq(50)#设置舵机的角度(0-180度)对应脉冲宽度0.5ms-2.5ms(占空比2.5%-12.5%)#注意:PCA9685的分辨率是12位(4096),所以我们需要将角度转换为0-4095的数值#对于50Hz,每个周期20ms,则0.5ms对应4096*(0.5/20)=102.4,取整102;2.5ms对应4096*(2.5/20)=512。#因此,角度0度对应102,180度对应512。我们可以用线性映射:value=102+(angle/180)*(512-102)defset_angle(channel,angle):#将角度转换为脉冲宽度对应的值pulse=int(102+(angle/180)*410)#410=512-102pca.duty(channel,pulse)#测试:控制0号舵机从0度到180度whileTrue:forangleinrange(0,181,5):set_angle(0,angle)time.sleep(0.05)forangleinrange(180,-1,-5):set_angle(0,angle)time.sleep(0.05)```注意:上述代码中的`pca9685.py`库需要先上传到ESP32。你可以从以下链接获取该库:https://github.com/micropython-IMU/micropython-pca9685如果没有现成的库,也可以直接通过I2C寄存器操作:```pythonfrommachineimportPin,I2Cimporttime#PCA9685地址PCA_ADDR=0x40#寄存器地址MODE1=0x00PRESCALE=0xFE#LED0_ON_L=0x06每个舵机有4个寄存器:LEDx_ON_L,LEDx_ON_H,LEDx_OFF_L,LEDx_OFF_H#我们主要设置OFF时间(即高电平结束时间)#初始化I2Ci2c=I2C(scl=Pin(22),sda=Pin(21),freq=400000)#设置PCA9685的频率(50Hz)defset_pwm_freq(freq):prescale=int(25000000/(4096*freq))-1old_mode=i2c.readfrom_mem(PCA_ADDR,MODE1,1)[0]new_mode=(old_mode&0x7F)|0x10#进入睡眠模式i2c.writeto_mem(PCA_ADDR,MODE1,bytes([new_mode]))i2c.writeto_mem(PCA_ADDR,PRESCALE,bytes([prescale]))i2c.writeto_mem(PCA_ADDR,MODE1,bytes([old_mode]))time.sleep(0.005)i2c.writeto_mem(PCA_ADDR,MODE1,bytes([old_mode|0x80]))#设置舵机角度defset_angle(channel,angle):#计算脉冲宽度(0.5ms-2.5ms)对应的数值pulse=int(102+(angle/180)*410)#0度:102,180度:512#设置OFF时间(ON时间设为0,OFF时间设为pulse)#每个通道有4个寄存器,第一个寄存器地址为0x06+4*channelreg=0x06+4*channel#将pulse拆分为低8位和高4位(因为寄存器是12位)off_low=pulse&0xFFoff_high=(pulse>>8)&0x0F#写入:ON时间全0,OFF时间为pulsei2c.writeto_mem(PCA_ADDR,reg,bytes([0x00,0x00,off_low,off_high]))#初始化:设置频率set_pwm_freq(50)#测试whileTrue:forangleinrange(0,181,5):set_angle(0,angle)time.sleep(0.05)forangleinrange(180,-1,-5):set_angle(0,angle)time.sleep(0.05)```注意:直接操作寄存器的方法更底层,但需要仔细阅读PCA9685的数据手册。引用[3]中提到ESP32的MicroPython中I2C的`readfrom_mem`和`writeto_mem`函数的使用,我们在第二种方法中使用了这些函数。总结:使用ESP32控制PCA9685驱动多路舵机,主要步骤是:1.正确连接硬件(电源、I2C)。2.设置PCA9685的PWM频率为50Hz(舵机标准)。3.将舵机角度转换为PWM占空比(脉冲宽度)并设置到相应通道。注意事项:-舵机的供电:如果使用多个舵机,建议外接5V电源,避免ESP32的5V引脚电流不足。-I2C地址:PCA9685的默认地址是0x40,但可以通过地址引脚改变,所以最好先扫描I2C设备地址(使用`i2c.scan()`)。希望这个示例能帮助你!相关问题:1.如何调整舵机的角度范围(例如,有些舵机不是0-180度)?2.如果我想同时控制多个舵机,代码应该如何修改?3.PCA9685的I2C地址如何更改?如何扫描I2C设备地址?</think>### ESP32 使用 PCA9685 控制多路舵机的实现教程 #### 硬件连接 根据引用[2][4]的硬件连接方案: ``` PCA9685 ── ESP32 VCC → 3.3V 或 5V(建议外接电源) GND → GND SDA → GPIO21(默认I2C SDA) SCL → GPIO22(默认I2C SCL) V+ → 外接5V电源(舵机供电) ``` > 注意:舵机电源建议外接5V电源,避免ESP32供电不足[^4]。 #### 软件实现(MicroPython) 根据引用[3][4]的I2C控制原理: ```python from machine import Pin, I2C import time # 初始化I2C (SDA=GPIO21, SCL=GPIO22) i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000) # PCA9685默认地址0x40 PCA_ADDR = 0x40 # 寄存器地址 MODE1 = 0x00 PRESCALE = 0xFE LED0_ON_L = 0x06 # 设置PWM频率(50Hz适用于舵机) def set_pwm_freq(freq): prescale = int(25000000 / (4096 * freq)) - 1 i2c.writeto_mem(PCA_ADDR, MODE1, b'\x10') # 进入睡眠模式 i2c.writeto_mem(PCA_ADDR, PRESCALE, bytes([prescale])) i2c.writeto_mem(PCA_ADDR, MODE1, b'\x00')) time.sleep(0.005) i2c.writeto_mem(PCA_ADDR, MODE1, b'\xA0')) # 自动递增 # 设置舵机角度(0-180度) def set_servo_angle(channel, angle): pulse = int(102 + (angle / 180) * 410) # 0.5ms-2.5ms -> 102-512 reg = LED0_ON_L + 4 * channel i2c.writeto_mem(PCA_ADDR, reg, b'\x00\x00') # ON时间=0 i2c.writeto_mem(PCA_ADDR, reg + 2, bytes([pulse & 0xFF])) # OFF低字节 i2c.writeto_mem(PCA_ADDR, reg + 3, bytes([pulse >> 8])) # OFF高字节 # 初始化PCA9685 set_pwm_freq(50) # 设置50Hz PWM频率 # 示例:控制0号通道舵机摆动 while True: for angle in range(0, 181, 10): set_servo_angle(0, angle) time.sleep(0.1) for angle in range(180, -1, -10): set_servo_angle(0, angle) time.sleep(0.1) ``` #### 关键点说明 1. **角度转换原理**: - 舵机控制脉冲范围:$0.5\text{ms}$(0°)到 $2.5\text{ms}$(180°) - 计算公式:$\text{pulse} = 102 + \frac{\text{angle}}{180} \times 410$ - 对应PWM占空比:$2.5\%$(0°)到 $12.5\%$(180°)[^2] 2. **I2C通信**: - 使用`writeto_mem()`函数写入寄存器 - 每个舵机占用4个寄存器(ON_L, ON_H, OFF_L, OFF_H) - 通道计算:$ \text{reg\_addr} = \text{LED0\_ON\_L} + 4 \times \text{channel} $[^3] 3. **多路控制**: - 同时控制16路舵机 - 示例:`set_servo_angle(0, 90)` 控制0号通道 - 扩展:添加更多`set_servo_angle()`调用控制其他通道 #### 优化建议 1. 电源隔离:舵机与ESP32使用独立电源,避免电压波动 2. 软件滤波:添加角度平滑过渡算法减少机械抖动 3. 错误处理:增加I2C通信失败重试机制 > 完整项目参考:GitHub搜索"ESP32 PCA9685 Servo Control"获取开源项目示例[^2][^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大家好我是科林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值