注意!!!下面例子需要用到外部库文件,如果你IDE没有
16路舵机驱动板资料(内含模块级联说明):https://pan.baidu.com/s/1gfhFGDP
把下载文件放入如下位置:
PCA9685是16路12位PWM信号发生器,可用于控制舵机、led、电机等设备,采用I2C通信。主机只需要I2C接口即可实现16路舵机控制。
PCA9685的I2C地址默认0x40,如果需要改变地址,则需要将板上A0-A5焊通即可对应的bit置1,此时地址为:0x40+A5:A0。这也意味着主机可以通过I2C地址控制64个PCA9685模块,从而实现最大16*64路舵机控制。
AIN4 ------- SDA
AIN5 ------- SCL
5V -------- VCC
3.3V -------- V+
GND -------- GND
舵机线按照颜色对应接模块0控制口。
V+是舵机电源,试验采用的是9g小舵机,所以也可以用3.3V带动,但是mg995这种大舵机,则需要5V以上才能带动。
VCC是模块的电源,用于PCA9685芯片。
舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:
0.5ms————–0度;
1.0ms————45度;
1.5ms————90度;
2.0ms———–135度;
2.5ms———–180度;
PCA9685可以设置更新频率,时基脉冲周期20ms相当于50HZ更新频率。PCA9685采用12位的寄存器来控制PWM占比,对于0.5ms,相当于0.5/204096=102的寄存器值。以此类推如下:
0.5ms————–0度:0.5/204096 = 102
1.0ms————45度:1/204096 = 204
1.5ms————90度:1.5/204096 = 306
2.0ms———–135度:2/204096 = 408
2.5ms———–180度:2.5/204096 =510
但是实际使用的时候,还是有偏差,除了0度以及180度,其他需要乘以0.915系数。最后的寄存器值如下:
0.5ms————–0度:0.5/204096 = 102
1.0ms————45度:1/204096 = 204 * 0.915 = 187
1.5ms————90度:1.5/204096 = 306 * 0.915 = 280
2.0ms———–135度:2/204096 = 408 * 0.915 = 373
2.5ms———–180度:2.5/20*4096 =510
16路舵机同时转动。原理是定义脉宽最大和最小,通过改变0-15号舵机的脉宽大小实现角度转动:
#include
#include
// 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);
//也可以用不同的地址调用它
/* 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中)
// 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
////模拟伺服在60赫兹更新下运行
}
// 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. its not precise!
//如果您想以秒为单位设置脉冲长度,则可以使用此函数。
//例如SET伺服脉冲(0,0.001)是一个1毫秒的脉冲宽度。它不是
void setServoPulse(uint8_t n, double pulse) {
double pulselength;//精度浮点数
pulselength = 1000000; // 1,000,000 us per second 每秒100万
pulselength /= 60; // 60 Hz
Serial.print(pulselength); Serial.println(" us per period");
pulselength /= 4096; // 12 bits of resolution 12位分辨率
Serial.print(pulselength); Serial.println(" us per bit");
pulse *= 1000;
pulse /= pulselength;
Serial.println(pulse);
pwm.setPWM(n, 0, pulse);
}
void loop() {
// Drive each servo one at a time
//Serial.println(servonum);
//每次驱动一个伺服驱动器
//串行打印(伺服);
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm.setPWM(0, 0, pulselen);
pwm.setPWM(1, 0, pulselen);
pwm.setPWM(2, 0, pulselen);
pwm.setPWM(3, 0, pulselen);
pwm.setPWM(4, 0, pulselen);
pwm.setPWM(5, 0, pulselen);
pwm.setPWM(6, 0, pulselen);
pwm.setPWM(7, 0, pulselen);
pwm.setPWM(8, 0, pulselen);
pwm.setPWM(9, 0, pulselen);
pwm.setPWM(10, 0, pulselen);
pwm.setPWM(11, 0, pulselen);
pwm.setPWM(12, 0, pulselen);
pwm.setPWM(13, 0, pulselen);
pwm.setPWM(14, 0, pulselen);
pwm.setPWM(15, 0, pulselen);
}
delay(500);
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm.setPWM(0, 0, pulselen);
pwm.setPWM(1, 0, pulselen);
pwm.setPWM(2, 0, pulselen);
pwm.setPWM(3, 0, pulselen);
pwm.setPWM(4, 0, pulselen);
pwm.setPWM(5, 0, pulselen);
pwm.setPWM(6, 0, pulselen);
pwm.setPWM(7, 0, pulselen);
pwm.setPWM(8, 0, pulselen);
pwm.setPWM(9, 0, pulselen);
pwm.setPWM(10, 0, pulselen);
pwm.setPWM(11, 0, pulselen);
pwm.setPWM(12, 0, pulselen);
pwm.setPWM(13, 0, pulselen);
pwm.setPWM(14, 0, pulselen);
pwm.setPWM(15, 0, pulselen);
}
delay(500);
}
控制程序使用串口通讯接受指令,实现0/45/90/135/180度,总共5种角度的控制。
#include
#include
// 默认地址 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVO_0 102
#define SERVO_45 187
#define SERVO_90 280
#define SERVO_135 373
#define SERVO_180 510
// our servo # counter
uint8_t servonum = 0;
char comchar;
void setup() {
Serial.begin(9600);
Serial.println("8 channel Servo test!");
pwm.begin();
pwm.setPWMFreq(50); // 50HZ更新频率,相当于20ms的周期
delay(10);
}
void loop() {
while(Serial.available()>0){
comchar = Serial.read();//读串口第一个字节
switch(comchar)
{
case '0':
pwm.setPWM(0, 0, SERVO_0);
Serial.write(comchar);
break;
case '1':
pwm.setPWM(0, 0, SERVO_45);
Serial.write(comchar);
break;
case '2':
pwm.setPWM(0, 0, SERVO_90);
Serial.write(comchar);
break;
case '3':
pwm.setPWM(0, 0, SERVO_135);
Serial.write(comchar);
break;
case '4':
pwm.setPWM(0, 0, SERVO_180);
Serial.write(comchar);
break;
default:
Serial.write(comchar);
break;
}
}
}
#include
#include
//默认地址 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
//9g舵机 高电平宽度在20ms内通过控制脉冲宽度范围0.5ms~2.5ms
#define SERVOMIN 102 // this is the 'minimum' pulse length count (out of 4096) 0度
#define SERVOMAX 512 // this is the 'maximum' pulse length count (out of 4096) 180度
void setup() {
Serial.begin(9600);
Serial.println("16 channel Servo test!");
pwm.begin();
pwm.setPWMFreq(50); //频率 50Hz,最高60Hz
}
void setServoPulse(uint8_t n, double pulse) {
double pulselength;
pulselength = 1000000; // 1,000,000 us per second
pulselength /= 50; // 50 Hz
Serial.print(pulselength); Serial.println(" us per period");
pulselength /= 4096; // 12 bits of resolution
Serial.print(pulselength); Serial.println(" us per bit");
pulse *= 1000;
pulse /= pulselength;
Serial.println(pulse);
pwm.setPWM(n, 0, pulse);
}
//设置9g舵机角度
void servo_9g_write(uint8_t n,int Angle)
{
double pulse = Angle;
pulse = pulse/90 + 0.5;
setServoPulse(n,pulse);//0到180度映射为0.5到2.5ms
}
void loop()
{
unsigned char serialRead;
if (Serial.available() > 0)
{
serialRead = Serial.read();
servo_9g_write(0,serialRead);//控制第一路度数
}
}