Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

Arduino UNO and PCA9685 PWM Servo Controller for Joystick-Controlled Robotic Arm

View and Edit Project In Cirkit DesignerImage of Arduino UNO and PCA9685 PWM Servo Controller for Joystick-Controlled Robotic Arm

Circuit Documentation

Summary

This circuit is designed to control three micro servos using an Arduino UNO and a PCA9685 PWM Servo Breakout. The servos are controlled via two joystick modules, allowing for precise movement. The circuit is powered by a 9V battery.

Component List

  1. Adafruit PCA9685 PWM Servo Breakout

    • Description: A 16-channel PWM driver that can control up to 16 servos or LEDs.
    • Pins: 5.0V, GND, PWRIN, PWM0-PWM15, VCC, SDA, SCL, OE
  2. Arduino UNO

    • Description: A microcontroller board based on the ATmega328P.
    • Pins: UNUSED, IOREF, Reset, 3.3V, 5V, GND, Vin, A0-A5, SCL, SDA, AREF, D0-D13
  3. Micro servo 9G

    • Description: A small and lightweight servo motor.
    • Pins: GND, +5V, PWM
  4. Joystick module

    • Description: A module with two potentiometers and a push button, used for controlling servos.
    • Pins: SW, VRY, VRX, VCC, GND
  5. 9V Battery

    • Description: A standard 9V battery used to power the circuit.
    • Pins: -, +

Wiring Details

Adafruit PCA9685 PWM Servo Breakout

Arduino UNO

Micro servo 9G

Micro servo 9G

Micro servo 9G

Joystick module

Joystick module

9V Battery

Code Documentation

#include <Servo.h>

// Servo objects
Servo shoulderServo, elbowServo, gripperServo;

// Joystick pins
const int shoulderJoystickPin = A0;
const int elbowJoystickPin = A1;
const int gripperJoystickPin = A2;

// Servo pins
const int shoulderServoPin = 9;
const int elbowServoPin = 10;
const int gripperServoPin = 11;

// Default servo positions
const int startShoulderPosition = 90;
const int startElbowPosition = 90;
const int startGripperPosition = 180;

// Dead zone settings
int deadZoneCenter = 512;       // Center point of the joystick
const int deadZoneRange = 50;   // Range considered as the dead zone

// Debugging toggle
const bool debugEnabled = true;

// Calibration button pin (optional, connect to a push button or jumper)
const int calibrateButtonPin = 7;

// Setup function
void setup() {
    // Attach servos to pins
    shoulderServo.attach(shoulderServoPin);
    elbowServo.attach(elbowServoPin);
    gripperServo.attach(gripperServoPin);

    // Initialize servos to start positions
    moveServoToPosition(shoulderServo, startShoulderPosition);
    moveServoToPosition(elbowServo, startElbowPosition);
    moveServoToPosition(gripperServo, startGripperPosition);

    // Setup serial for debugging
    if (debugEnabled) {
        Serial.begin(9600);
        Serial.println("System initialized.");
    }

    // Calibrate joystick dead zone
    pinMode(calibrateButtonPin, INPUT_PULLUP); // Pull-up for button
    deadZoneCenter = calibrateJoystickCenter();
    if (debugEnabled) {
        Serial.print("Calibrated Dead Zone Center: ");
        Serial.println(deadZoneCenter);
    }
}

// Main loop
void loop() {
    // Check for recalibration request
    if (digitalRead(calibrateButtonPin) == LOW) {
        deadZoneCenter = calibrateJoystickCenter();
        if (debugEnabled) {
            Serial.println("Joystick recalibrated.");
        }
    }

    // Control servos
    controlServoWithJoystick(shoulderJoystickPin, shoulderServo, "Shoulder");
    controlServoWithJoystick(elbowJoystickPin, elbowServo, "Elbow");
    controlServoWithJoystick(gripperJoystickPin, gripperServo, "Gripper");

    delay(20); // Stabilization delay
}

// Function to control a servo using joystick
void controlServoWithJoystick(int joystickPin, Servo &servo, const char *servoName) {
    int joystickValue = smoothAnalogRead(joystickPin);

    // Check dead zone
    if (abs(joystickValue - deadZoneCenter) < deadZoneRange) {
        if (debugEnabled) {
            Serial.print(servoName);
            Serial.println(": Joystick in dead zone, holding position.");
        }
        return; // Do nothing if in dead zone
    }

    // Map joystick value to servo angle
    int servoAngle = map(joystickValue, 0, 1023, 0, 180);
    moveServoToPosition(servo, servoAngle);

    // Debugging
    if (debugEnabled) {
        Serial.print(servoName);
        Serial.print(" Joystick Value: ");
        Serial.print(joystickValue);
        Serial.print(" -> Servo Angle: ");
        Serial.println(servoAngle);
    }
}

// Function to move a servo to a position
void moveServoToPosition(Servo &servo, int position) {
    servo.write(position