Here I am going to explain how to use PCA9685 with Arduino to control 3 servo motors to mimic robotic arm. I will explain how to interface PCA9685 with Arduino using the I2C pins, wiring the servos to the PCA9685 and how to wire large capacitor so that the 3 servos work without problems.
In this circuit, we are using the PCA9685 16-channel PWM controller to drive three servo motors representing a robotic arm (Base, Shoulder, and Elbow) using only two I2C pins from an Arduino Nano. This setup is ideal for robotics because it offloads the PWM processing from the microcontroller and provides 12-bit resolution for incredibly smooth motion.
Key Technical Features:
The Controller (PCA9685): The IC (U1) manages the servo signals. Notice that pins A0-A5 are tied to Ground, setting the I2C address to its default 0x40.
I2C Communication: The SDA (Pin 27) and SCL (Pin 26) are connected to the Nano's A4 and A5 pins. Two 4.7kΩ pull-up resistors (R1 & R2) are included to ensure stable data transmission.
Output Enable (OE) Logic: The active low OE pin (Pin 23) is connected to Digital Pin D4 on the Nano. This allows the code to "kill" power to all servos instantly for safety or to prevent jitter during startup.
The Robotic Arm Servos:
- The Base: Connected to LED0 (Pin 6).
- The Shoulder: Connected to LED1 (Pin 7).
- The Elbow: Connected to LED2 (Pin 8).
Power Management & Filtering: The circuit uses a 5V Battery (B1) to power both the Nano and the Servos. A massive 1000µF decoupling capacitor (C1) is placed across the power rails. This is critical for absorbing current spikes when the arm motors move simultaneously, preventing the Arduino from resetting.
Program Code:
Following is the Arduino code for conrolling the robotic arm, that is the three servo motors.
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
const int oePin = 4; // D4 connected to OE as per your image
// Define "Safe" positions for your arm
#define BASE_CENTER 375
#define SHOULDER_UP 200
#define SHOULDER_DN 450
#define ELBOW_FLAT 375
void setup() {
pinMode(oePin, OUTPUT);
digitalWrite(oePin, HIGH); // Disable outputs during boot
pwm.begin();
pwm.setPWMFreq(60);
// Initialize servos to "Home" position before enabling power
pwm.setPWM(0, 0, BASE_CENTER);
pwm.setPWM(1, 0, SHOULDER_UP);
pwm.setPWM(2, 0, ELBOW_FLAT);
delay(1000);
digitalWrite(oePin, LOW); // Power on servos safely
}
void loop() {
// 1. Rotate Base to the right
moveServo(0, BASE_CENTER, 500, 20);
delay(500);
// 2. Lower Shoulder to "Pick"
moveServo(1, SHOULDER_UP, SHOULDER_DN, 25);
delay(1000);
// 3. Raise Shoulder back up
moveServo(1, SHOULDER_DN, SHOULDER_UP, 25);
delay(500);
// 4. Return Base to Center
moveServo(0, 500, BASE_CENTER, 20);
delay(4000); // Wait 4 seconds before repeating
}
// Smooth movement function to prevent the arm from shaking/jerking
void moveServo(int channel, int start, int end, int speed) {
if (start < end) {
for (int p = start; p <= end; p += 2) {
pwm.setPWM(channel, 0, p);
delay(speed);
}
} else {
for (int p = start; p >= end; p -= 2) {
pwm.setPWM(channel, 0, p);
delay(speed);
}
}
}
Code explanation:
The code controls the robot arm by using the Adafruit PWM library to send I2C commands from the Arduino Nano to the PCA9685 chip, which translates degree positions into 12-bit PWM "ticks" (typically between 150 and 600) to drive the servos. To ensure safety and smooth operation, the script utilizes the OE (Output Enable) pin on D4 as a master kill-switch to prevent erratic movements during startup, while a custom moveServo function uses for loops to increment positions slowly rather than snapping instantly. This modular approach allows the Arduino to choreograph complex "pick and place" motions for the Base, Shoulder, and Elbow without the CPU-intensive task of managing timing pulses for multiple motors simultaneously.
The following video demonstrates how the circuit works:
Related tutorials:
- Controlling a Hobby Servo Motor with L293D Motor Shield and Arduino
- Controlling a Servo Motor with a RAMPS Shield and Potentiometer
- Adding and Checking Ultrasonic Sensor and Servo Motor: Arduino RoboMaster
- How to control Servo Motor Control using Arduino Nano
- Controlling Servo Motors with PIC16F877A: Applications in Robotics
- Joystick controlled Robotic Arm with Arduino: Wiring Diagram, Code, Interactive 3D Web Simulation
- Servo Motor control with ATmega328p
- How to control a servo with a potentiometer?
