Changing the I2C address for a PCA9685

I am writing a program to control the 7 servos in a Ohbot head using an ESP32 with a PCA9685 servo board. The base of the code was Adafruit's PCA9685 servo example. To use the modified code below you enter the element number, 0 to 6, and a - or + to move the servo, this is a test program. This works fine using the default address of 0x40. For this project I will have 5 of these Ohbots. So I changed the incidence for the boards address to 0x41, I also soldered the jumper on the board. I confirmed the address is right by running the I2C scanner example but this program now doesn't work. Do I have to modify something else to get it to work with the different address?

Here's my program:

#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);
// you can also call it with a different address and I2C interface
//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)
#define SERVOMAX  600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN  600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX  2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates

#define NUM_SERVOS 7
int currentServoNum = 0;

typedef struct {
  int servoNum;
  int minAng;
  int maxAng;
  int restAng;
  int currentAng;
} ServoProps;

//properties for each servo 
ServoProps servoProps[NUM_SERVOS] = {
  {0, 0, 120, 55}, //head turn
  {1, -15, 65, 35}, //head nod
  {8, 20, 100, 55}, //eyes horizontal
  {3, 55, 115, 85}, //eyes vertical
  {4, 0, 40, 25}, //eyelids
  {5, -20, 15, 15}, //top lip
  {6, 20, 65, 65}, //bottom lip
};

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

  for (int i=0; i < NUM_SERVOS; i++) {
    servoProps[i].currentAng = servoProps[i].restAng;
  }

  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!
   * The int.osc. for the PCA9685 chip is a range between about 23-27MHz and
   * is used for calculating things like writeMicroseconds()
   * 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.
   * 1) Attach the oscilloscope to one of the PWM signal pins and ground on
   *    the I2C PCA9685 chip you are setting the value for.
   * 2) Adjust setOscillatorFrequency() until the PWM update frequency is the
   *    expected value (50Hz for most ESCs)
   * Setting the value here is specific to each individual I2C PCA9685 chip and
   * affects the calculations for the PWM update frequency. 
   * Failure to correctly set the int.osc value will cause unexpected PWM results
   */
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates

  delay(10);
}

int extra = 0;

void loop() {
  //pose the servos using the current angle settings for each channel
  for (int j=0; j < NUM_SERVOS; j++) {
    pwm.setPWM(servoProps[j].servoNum, 0, angleToPulse(servoProps[j].currentAng));
  }

  // check for serial input, values can be:
  // 0 thru 7 to change servo channel
  // + or - to change servo angle
  // p to print out current pose values
  if (Serial.available() > 0) {
    char input = Serial.read();

    if ((input == '=') || (input == '+')) {
      servoProps[currentServoNum].currentAng += 5;

      if (servoProps[currentServoNum].currentAng > servoProps[currentServoNum].maxAng) {
        servoProps[currentServoNum].currentAng = servoProps[currentServoNum].maxAng;
      }
    } else if (input == '-') {
      servoProps[currentServoNum].currentAng -= 5;

      if (servoProps[currentServoNum].currentAng < servoProps[currentServoNum].minAng) {
        servoProps[currentServoNum].currentAng = servoProps[currentServoNum].minAng;
      }
    } else  if (input == 'p') {
      Serial.println("nod, shake, eyes-hori, eyes-vert, eyelids, top-lip, bottom-lip");
      Serial.print("{");
      for (int i=0; i < NUM_SERVOS; i++) {
        if (i > 0) {
          Serial.print(", ");
        }
        Serial.print(servoProps[i].currentAng);
      }
      Serial.println("}");
    } else {
      currentServoNum = input - '0';
    }

    if (input != 'p') {
      Serial.print(currentServoNum);
      Serial.print(": ");
      Serial.println(servoProps[currentServoNum].currentAng);
    }

  }
 
}

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


Thanks for the help
John

Would think it should work, but I've not used that board. If I were where you are I would removed the solder jumper and verify it still works at 0x40

@JohnRob It's good to hear you think it should work and I haven't missed something obvious but I've unsoldered and resoldered that jumper a couple of times, I've also tried a different board. Although I don't see why it would mater but I'll try a different address as well.

Thanks for your suggestion

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.