WAVEGO-PCA9685
PCA9685 Controls Servo
Introduction
PCA9685 is an LED control chip based on IIC bus control for generating 16-channel PWM signals. The frequency and duty cycle of the PWM wave can be freely adjusted at each LED output.
The servo is a position (angle) servo for control systems that require continuous control of angle change and hold.
This chapter mainly introduces how to change the PWM to achieve the effect of controlling the rotation of the servo through the PCA9685. There is a PCA9685 chip on the ESP32, the main control board of this product, and the servo communicates with the ESP32 through GPIO.
Through the study of this chapter, you can basically master how to send PWM signals through the PCA9685 to control the servo rotation.
Principle
- In this product, the on-board ESP32 controls the PCA9685 module through IIC communication (GPIO32→SDA, GPIO33→SCL), and then the PCA9685 can generate 16-channel PWM pulse signals to control the servo and the rotation angle of the servo can be adjusted by adjusting the duty cycle of the 16-channel PWM pulses generated by the PCA9685.
Servo Number & Position
- The demos in this tutorial are all implemented with servo #0, so you will need to remove the leg linkage from both servo #0 and servo #1 before running the demos.
Note: The white swing arm does not need to be removed.
Sample Demo
Code
Servo Simple Rotation
- Download the sample demo and unzip it.
- Open the sample demo, select the servo simple rotation, and use Arduino IDE to open PCA9685_Servo1.ino.
- Use the USB cable to connect WAVEGO and the computer, select the correct parameters and COM port, and click to upload.
- When running the demo, rotate the demo by the following commands:
pwm.setPWM(0,0,286); pwm.setPWM(0,0,386);
- Full demo codes are shown below:
#include "Servo1.h" //Import the library function Servo1.h TwoWire IIC = TwoWire(0); //Initialize the IO port of the IIC Servo1 pwm = Servo1(0x40, IIC); //Instantiating pwm #define S_SCL 33 //Define the IO port of the clock cable as GPIO33 #define S_SDA 32 //Define the IO port of the data line as GPIO32 #define LEG0 0 #define LEG1 1 #define SERVO_FREQ 50 void ServoSetup(){ IIC.begin(S_SDA, S_SCL, 26000000); //Open the IIC channel pwm.begin(); pwm.setOscillatorFrequency(26000000); pwm.setPWMFreq(SERVO_FREQ); //the refresh rate is 50Hz Wire.setClock(100000); //Modify the IIC clock frequency as 100KHz delay(10); } void setup() { ServoSetup(); pwm.setPWM(1,0,386); //In order to prevent the No. 0 servo from being hindered by the No. 1 servo during the swinging process, the No. 1 servo needs to be set to a certain angle to reserve space for the No. 0 servo first. } void loop() { pwm.setPWM(0,0,286); delay(500); pwm.setPWM(0,0,386); delay(500); }
Demo Code Analysis
- The servo communicates with the PCA9685 using the IIC.
TwoWire IIC = TwoWire(0); //Initialize the IIC's IO port Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, IIC); //Instantiating pwm #define S_SCL 33 //Define the IO port of the clock line as GPIO33 #define S_SDA 32 //Define the IO port of the data line as GPIO32
- The function is for enabling the IIC channel and initializing the servo.
void ServoSetup(){ IIC.begin(S_SDA, S_SCL, 26000000); //Enabling the IIC channel pwm.begin(); pwm.setOscillatorFrequency(26000000); pwm.setPWMFreq(SERVO_FREQ); //The refreshing rate is 50Hz Wire.setClock(100000); //Modify the IIC clock frequency as 100KHz delay(10); }
The servoID is the servo number, fill in the corresponding servo number to control the corresponding servo, and rotate the servo by changing the PWM, the value of PWM is 86~484, the angle control has the corresponding angle, and the calculation method.
Facing the swing arm side, the servo swing arm does a counterclockwise rotation as the value of PWM increases.
In order to prevent the No. 0 servo from being obstructed by the No. 1 servo during the swinging process, it is necessary to set the No. 1 servo to swing to a certain position to ensure that the No. 0 servo will not be obstructed.
pwm.setPWM(servoID, 0, pwm);
Demo Running Effect
- The No. 0 servo swing arm swings from side to side within a 45-degree range.
Servo Angle Control
- Select Servo Angle Control and open PCA9685_Servo2.ino with the Arduino IDE.
- Connect the WAVEGO to the PC with the USB cable, select the correct parameters and COM port, and upload the demo.
- In this demo, the code to realize the rotation of the servo is the same as the code for the simple rotation of the servo, the difference is that in this demo there is an introduction to how to control the servo angle with pwm.
The complete code is as follows:
#include "Servo1.h" //Import the the header file Servo1.h TwoWire IIC = TwoWire(0); //Initialize the IIC's IO port Servo1 pwm = Servo1(0x40, IIC); //Instantiating pwm #define S_SCL 33 //Define the IO port of the clock line as GPIO33 #define S_SDA 32 //Define the IO port of the data line as GPIO32 #define LEG0 0 #define LEG1 1 #define SERVO_FREQ 50 void ServoSetup(){ IIC.begin(S_SDA, S_SCL, 26000000); //Enable the IIC channel pwm.begin(); pwm.setOscillatorFrequency(26000000); pwm.setPWMFreq(SERVO_FREQ); //The refresh rate is 50Hz Wire.setClock(100000); //Modify the IIC clock frequency is 100KHz delay(10); } void setup() { ServoSetup(); pwm.setPWM(1,0,386); //In order to prevent the No. 0 servo from being hindered by the No. 1 servo during the swinging process, the No. 1 servo needs to be set to a certain angle to reserve space for the No. 0 servo first. } void loop() { pwm.setPWM(0,0,86); //Servo 0 swings to 0 degrees. delay(1000); pwm.setPWM(0,0,186); //Servo 0 swings to 45 degrees. delay(1000); pwm.setPWM(0,0,286); //Servo 0 swings to 90 degrees. delay(1000); pwm.setPWM(0,0,386); //Servo 0 swings to 135 degrees. delay(1000); pwm.setPWM(0,0,484); //Servo 0 swings to 180 degrees. delay(1000); }
Demo Analysis
- Servo control generally requires a 20ms time base pulse, and the high-level part of this pulse is generally the angle control pulse part in the range of 0.5ms to 2.5ms. The PCA9685 uses a 12-bit register to control the PWM duty cycle, and the value of the register is calculated using the following method:
Pulse High Time | Angle | Theotical pwm | Actual pwm |
0.5ms | 0 Degree | 0.5/20*(2^12-1)=102 | 86 |
1.0ms | 45 Degrees | 1.0/20*(2^12-1)=205 | 186 |
1.5ms | 90 Degrees | 1.5/20*(2^12-1)=307 | 286 |
2.0ms | 135 Degrees | 2.0/20*(2^12-1)=410 | 386 |
2.5ms | 180 Degrees | 2.5/20*(2^12-1)=512 | 484 |
There are errors in actual use, and the PWM is measured to take values of 86~484 in the servo of this product.
Demo Running Effect
- The servo swing arm swings to 0 degree, 45 degrees, 90 degrees, 135 degrees, 180 degrees, and then back to 0 degree after reaching 180 degrees.
Servo stepping operation
- Select Servo Angle Control and open PCA9685_Servo3.ino with Arduino IDE, and connect WAVEGO to the computer with USB.
- Select the correct parameters and COM port, and then upload the demo.
- In this demo, the new variable Offset is defined, and this variable is used as an offset value to cause the PWM to keep +1 until it reaches 484 for stepping operations.
- The full demo code is shown below:
#include "Servo1.h" //Import the library function Servo1.h TwoWire IIC = TwoWire(0); //Initialize the IIC's IO port Servo1 pwm = Servo1(0x40, IIC); //Instantiating pwm #define S_SCL 33 //Define the IO port for the clock cable as GPIO33 #define S_SDA 32 //Define the IO port for the data cable as GPIO32 #define SERVO_FREQ 50 #define LEG0 0 #define LEG1 1 //Setting the initial position of the servo swing arm int Position = 86; //Initialize the servo void ServoSetup(){ IIC.begin(S_SDA, S_SCL, 26000000); //Enable the IIC channel pwm.begin(); pwm.setOscillatorFrequency(26000000); pwm.setPWMFreq(SERVO_FREQ); //The refresh rate is 50Hz Wire.setClock(100000); //Modify the IIC clock frequency as 100KHz delay(10); } //Rotate the servo swing arm void servoDebug(byte servoID, int offset){ if(Position<=484){ //Start stepping operation when original PWM is less than or equal to 484 Position += offset; //The servo swings in the original position offset pwm.setPWM(servoID, 0, Position); //Make the specified servo swing to the specified position. }else{ Position = 86; pwm.setPWM(servoID,0,Position); } } void setup() { ServoSetup(); pwm.setPWM(1,0,386); //In order to prevent the No. 0 servo from being hindered by the No. 1 servo during the swinging process, the No. 1 servo needs to be set to a certain angle to reserve space for the No. 0 servo first. pwm.setPWM(0,0,86); //Initialize servo swing arm position } void loop() { servoDebug(0,1); //Servo #0 steps in offset 1. delay(50); //System pause 50ms }
Demo Code Analysis
- Determine whether pwm is less than or equal to 484, when true, execute the step operation:
Position += offset;
pwm.setPWM(servoID, 0, Position)
If false, an else statement is executed to reset the pwm value to 86.
void servoDebug(byte servoID, int offset){ if(Position<=484){ //Start stepping operation when original pwm is less than or equal to 484 Position += offset; //The servo swings in the original position offset pwm.setPWM(servoID, 0, Position); //Make the specified servo swing to the specified position. }else{ Position = 86; //Reset the pwm to 86 when the original pwm is greater than or equal to 484 and turn the servo to the 0-degree position pwm.setPWM(servoID,0,Position); } }
Demo Running Effect
- The servo pendulum arm swings from 0 degrees, with an offset value of 1 for pwm constant +1 step operation.
Summary
- As can be seen in this chapter, the servo can be controlled by changing the PWM signal from the PCA9685.