Replacing servo driver object

I have 2 Ohbots connected to a ESP32, each Ohbot has a PCA9685 servo board. One has the default address of 0x40, the other 0x41. I also have 7 potentiometers connected to the ESP32. By changing which servo driver I use I can control the selected Ohbot with the pots. Eventually there will be 5 Ohbots, this system is just to test that I can control each one using the pots, right now I only have 2 connected. What I am trying to do is to be able to enter the Ohbot I want to control by entering a number from 1 to 5 in the serial monitor and then have the pots control that Ohbot.

I assume I would first have to define the object for each servo board.
Adafruit_PWMServoDriver Head1 = Adafruit_PWMServoDriver();
Adafruit_PWMServoDriver Head2 = Adafruit_PWMServoDriver(0x41);

and begin each one in setup,
Head1.begin();
Head2.begin();
Head1.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
Head2.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates

I would then read the number from the serial monitor and set a object place holder, Ohbot, to the selected head. Right now I'm using this statement, I'll replace that with the read logic later.
strcpy(Ohbot,"Head1");

In the call to the servo I would use this,
Ohbot.setPWM(0, 0, angleToPulse(Pot1Map));

Obviously this isn't working or I wouldn't be asking for help.

Here is my code

//Ohbot manual control with 7 pots
// Replaced Mega with a ESP32


#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
Adafruit_PWMServoDriver Head1 = Adafruit_PWMServoDriver();
Adafruit_PWMServoDriver Head2 = Adafruit_PWMServoDriver(0x41);

#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 60 // Analog servos run at ~50 Hz updates

char BotNum = 1; //Ohbot number to be ontrolled
char Ohbot[6] = "Ohbot";
//char Head1[6] = "Head1";
//char Head2[6] = "Head2";

const int Pot1Pin = 34;    // select the input pin for the potentiometer
int Pot1Value = 0;  // potentiometer 1 value
int Pot1Map = 0; //mapped value of pot 1 for servo angle

const int Pot2Pin = 35;    // select the input pin for the potentiometer
int Pot2Value = 0;  // potentiometer 2 value
int Pot2Map = 0; //mapped value of pot 2 for servo angle

const int Pot3Pin = 32;    // select the input pin for the potentiometer
int Pot3Value = 0;  // potentiometer 3 value
int Pot3Map = 0; //mapped value of pot 3 for servo angle

const int Pot4Pin = 33;    // select the input pin for the potentiometer
int Pot4Value = 0;  // potentiometer 4 value
int Pot4Map = 0; //mapped value of pot 4 for servo angle

const int Pot5Pin = 25;    // select the input pin for the potentiometer
int Pot5Value = 0;  // potentiometer 5 value
int Pot5Map = 0; //mapped value of pot 5 for servo angle

const int Pot6Pin = 26;    // select the input pin for the potentiometer
int Pot6Value = 0;  // potentiometer 6 value
int Pot6Map = 0; //mapped value of pot 6 for servo angle

const int Pot7Pin = 27;    // select the input pin for the potentiometer
int Pot7Value = 0;  // potentiometer 7 value
int Pot7Map = 0; //mapped value of pot 7 for servo angle


void setup() {
  Serial.begin(9600);
  Serial.println("Ohbot control");

  Head1.begin();
  Head2.begin(); 
  Head1.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
  Head2.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
  delay(10);


//************************************************************
// This line will be replaced by the read serial monitor logic
// read 1 = Head1, read 2 = Head2

strcpy(Ohbot,"Head1");

}

void loop() {
 
 //Head Turn
 // read the value from the Pots:
  Pot1Value = analogRead(Pot1Pin);
  Pot1Map = map(Pot1Value, 0, 4095, 0, 180);
  Pot1Map = constrain(Pot1Map, 10, 155);
  Ohbot.setPWM(0, 0, angleToPulse(Pot1Map));
  //Serial.print(Pot1Value);
  //Serial.print("\t");
  //Serial.println(Pot1Map);

// Nod
  Pot2Value = analogRead(Pot2Pin);
  Pot2Map = map(Pot2Value, 1, 4095, 0, 180);
  Pot2Map = constrain(Pot2Map, 30, 125);
  Ohbot.setPWM(2, 0, angleToPulse(Pot2Map));
  //Serial.print(Pot2Value);
  //Serial.print("\t");
  //Serial.println(Pot2Map);

// Eyes Left / Right
  Pot3Value = analogRead(Pot3Pin);
  Pot3Map = map(Pot3Value, 1, 4095, 0, 180);
  Pot3Map = constrain(Pot3Map, 60, 145);
  Ohbot.setPWM(4, 0, angleToPulse(Pot3Map));
  //Serial.print(Pot3Value);
  //Serial.print("\t");
  //Serial.println(Pot3Map);

//Eyes Up / Down
  Pot4Value = analogRead(Pot4Pin);
  Pot4Map = map(Pot4Value, 1, 4095, 0, 180);
  Pot4Map = constrain(Pot4Map, 65, 140);
  Ohbot.setPWM(6, 0, angleToPulse(Pot4Map));
  //Serial.print(Pot4Value);
  //Serial.print("\t");
  //Serial.println(Pot4Map);

// Eyelids
  Pot5Value = analogRead(Pot5Pin);
  Pot5Map = map(Pot5Value, 1, 4095, 0, 180);
  Pot5Map = constrain(Pot5Map, 0, 50);
  Ohbot.setPWM(8, 0, angleToPulse(Pot5Map));
  //Serial.print(Pot5Value);
  //Serial.print("\t");
  //Serial.println(Pot5Map);

// Top Lip
  Pot6Value = analogRead(Pot6Pin);
  Pot6Map = map(Pot6Value, 1, 4095, 0, 180);
  Pot6Map = constrain(Pot6Map, 35, 75);
  Ohbot.setPWM(10, 0, angleToPulse(Pot6Map));
  //Serial.print(Pot6Value);
  //Serial.print("\t");
  //Serial.println(Pot6Map);


// Bottom Lip
  Pot7Value = analogRead(Pot7Pin);
  Pot7Map = map(Pot7Value, 1, 4095, 0, 180);
  Pot7Map = constrain(Pot7Map, 40, 80);
  Ohbot.setPWM(12, 0, angleToPulse(Pot7Map));
  //Serial.print(Pot7Value);
  //Serial.print("\t");
  //erial.println(Pot7Map);


 /* 
 Serial.print(Pot1Value);
 Serial.print("\t");
 Serial.print(Pot2Value);
 Serial.print("\t");
 Serial.print(Pot3Value);
 Serial.print("\t");
 Serial.print(Pot4Value);
 Serial.print("\t");
 Serial.print(Pot5Value);
 Serial.print("\t");
 Serial.print(Pot6Value);
 Serial.print("\t");
 Serial.println(Pot7Value);
 */

  delay(50);
}


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 all comments and suggestions.
John

I'm not familiar with that library or "ohbots" (what ever in the world THAT is), but the answer would generally be to create an array of Adafruit_PWMServoDriver objects that can be indexed by the number (0 to N-1).

Sorry I should have explained an Ohbot, It's a STEM learning system, geared towards children as a fun way to learn programming, they typically use a Scratch style language. There are 7 servos to control head and eye movement, there's few examples on YouTube. I belong to a robotic group and someone has donated 5 of these we're trying to animate them so they appear to be singing a song.
I've added a picture of one.

Each of the PCA9685 servo boards can control up to 16 servos, they connect to the ESP32 via I2C, I referenced the address of each board earlier. The library creates the object for the driver then you enter the servo number and angle you want the servo to go to. Shown below is the driver object Head1 setting the angle for the servo on channel 0,

Head1.setPWM(0, 0, angleToPulse(Pot1Map));

thanks

So yes, start with an array of Adafruit_PWMServoDriver objects.

Ok, that sounds good, and easier than what I was trying,

Thanks

If you are new to all this and arrays are new and/or challenging, you can just read a value from Serial and then put a lot of if() statements throughout your code such as

 //Head Turn
 // read the value from the Pots:
  Pot1Value = analogRead(Pot1Pin);
  Pot1Map = map(Pot1Value, 0, 4095, 0, 180);
  Pot1Map = constrain(Pot1Map, 10, 155);
  if ( choice == 1 ) {
    Head1.setPWM(0, 0, angleToPulse(Pot1Map));
  } else if ( choice == 2 ) {
    Head2.setPWM(0, 0, angleToPulse(Pot1Map));
  }
  //Serial.print(Pot1Value);
  //Serial.print("\t");
  //Serial.println(Pot1Map);

Then after doing this, it may motivate you to learn to use arrays since it would be easier :slight_smile:

@blh64 My first thought was to use the if statement, and may have to in the end, but it didn't seem to me to be an efficient way to write code. You are right in that I am not overly familiar with arrays or working with strings, but you have to learn sometime and no time like the present.

So I made two attempts this morning, neither worked. I did make an array, right or wrong for my application, I at least don't get compiling errors.
char Ohbot[] = {'Head1', 'Head2', 'Head3', 'Head4', 'Head5'};

I then added the element into the servo channel statement.
Ohbot[BotNum].setPWM(0, 0, angleToPulse(Pot1Map));

I have BotNum equal to 1 so this should be "Head2"
I get the following error,
Compilation error: request for member 'setPWM' in 'Ohbot[BotNum]', which is of non-class type 'char'

Next I added ".setPWM" to the array elements
char Ohbot[] = {'Head1.setPWM', 'Head2.setPWM', 'Head3.setPWM', 'Head4.setPWM', 'Head5.setPWM'};

Added that to the servo channel call statement
Ohbot[BotNum](0, 0, angleToPulse(Pot1Map));

and get this error,
Compilation error: 'angleToPulse' was not declared in this scope

I'm thinking I may not be able to do what I want and use the if statement as you suggested.

Here is the code, as it is today,

//Ohbot manual control with 7 pots
// Replaced Mega with a ESP32


#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
Adafruit_PWMServoDriver Head1 = Adafruit_PWMServoDriver();
Adafruit_PWMServoDriver Head2 = Adafruit_PWMServoDriver(0x41);

#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 60 // Analog servos run at ~50 Hz updates

int BotNum = 1; //Ohbot number to be ontrolled
char Ohbot[] = {'Head1', 'Head2', 'Head3', 'Head4', 'Head5'};

const int Pot1Pin = 34;    // select the input pin for the potentiometer
int Pot1Value = 0;  // potentiometer 1 value
int Pot1Map = 0; //mapped value of pot 1 for servo angle

const int Pot2Pin = 35;    // select the input pin for the potentiometer
int Pot2Value = 0;  // potentiometer 2 value
int Pot2Map = 0; //mapped value of pot 2 for servo angle

const int Pot3Pin = 32;    // select the input pin for the potentiometer
int Pot3Value = 0;  // potentiometer 3 value
int Pot3Map = 0; //mapped value of pot 3 for servo angle

const int Pot4Pin = 33;    // select the input pin for the potentiometer
int Pot4Value = 0;  // potentiometer 4 value
int Pot4Map = 0; //mapped value of pot 4 for servo angle

const int Pot5Pin = 25;    // select the input pin for the potentiometer
int Pot5Value = 0;  // potentiometer 5 value
int Pot5Map = 0; //mapped value of pot 5 for servo angle

const int Pot6Pin = 26;    // select the input pin for the potentiometer
int Pot6Value = 0;  // potentiometer 6 value
int Pot6Map = 0; //mapped value of pot 6 for servo angle

const int Pot7Pin = 27;    // select the input pin for the potentiometer
int Pot7Value = 0;  // potentiometer 7 value
int Pot7Map = 0; //mapped value of pot 7 for servo angle


void setup() {
  Serial.begin(9600);
  Serial.println("Ohbot control");

  Head1.begin();
  Head2.begin(); 
  Head1.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
  Head2.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates
  delay(10);



}

void loop() {
 
 //Head Turn
 // read the value from the Pots:
  Pot1Value = analogRead(Pot1Pin);
  Pot1Map = map(Pot1Value, 0, 4095, 0, 180);
  Pot1Map = constrain(Pot1Map, 10, 155);
  Ohbot[BotNum].setPWM(0, 0, angleToPulse(Pot1Map));
  //Serial.print(Pot1Value);
  //Serial.print("\t");
  //Serial.println(Pot1Map);

// Nod
  Pot2Value = analogRead(Pot2Pin);
  Pot2Map = map(Pot2Value, 1, 4095, 0, 180);
  Pot2Map = constrain(Pot2Map, 30, 125);
  Ohbot[BotNum].setPWM(2, 0, angleToPulse(Pot2Map));
  //Serial.print(Pot2Value);
  //Serial.print("\t");
  //Serial.println(Pot2Map);

// Eyes Left / Right
  Pot3Value = analogRead(Pot3Pin);
  Pot3Map = map(Pot3Value, 1, 4095, 0, 180);
  Pot3Map = constrain(Pot3Map, 60, 145);
  Ohbot[BotNum].setPWM(4, 0, angleToPulse(Pot3Map));
  //Serial.print(Pot3Value);
  //Serial.print("\t");
  //Serial.println(Pot3Map);

//Eyes Up / Down
  Pot4Value = analogRead(Pot4Pin);
  Pot4Map = map(Pot4Value, 1, 4095, 0, 180);
  Pot4Map = constrain(Pot4Map, 65, 140);
  Ohbot[BotNum].setPWM(6, 0, angleToPulse(Pot4Map));
  //Serial.print(Pot4Value);
  //Serial.print("\t");
  //Serial.println(Pot4Map);

// Eyelids
  Pot5Value = analogRead(Pot5Pin);
  Pot5Map = map(Pot5Value, 1, 4095, 0, 180);
  Pot5Map = constrain(Pot5Map, 0, 50);
  Ohbot[BotNum].setPWM(8, 0, angleToPulse(Pot5Map));
  //Serial.print(Pot5Value);
  //Serial.print("\t");
  //Serial.println(Pot5Map);

// Top Lip
  Pot6Value = analogRead(Pot6Pin);
  Pot6Map = map(Pot6Value, 1, 4095, 0, 180);
  Pot6Map = constrain(Pot6Map, 35, 75);
  Ohbot[BotNum].setPWM(10, 0, angleToPulse(Pot6Map));
  //Serial.print(Pot6Value);
  //Serial.print("\t");
  //Serial.println(Pot6Map);


// Bottom Lip
  Pot7Value = analogRead(Pot7Pin);
  Pot7Map = map(Pot7Value, 1, 4095, 0, 180);
  Pot7Map = constrain(Pot7Map, 40, 80);
  Ohbot[BotNum].setPWM(12, 0, angleToPulse(Pot7Map));
  //Serial.print(Pot7Value);
  //Serial.print("\t");
  //erial.println(Pot7Map);


 /* 
 Serial.print(Pot1Value);
 Serial.print("\t");
 Serial.print(Pot2Value);
 Serial.print("\t");
 Serial.print(Pot3Value);
 Serial.print("\t");
 Serial.print(Pot4Value);
 Serial.print("\t");
 Serial.print(Pot5Value);
 Serial.print("\t");
 Serial.print(Pot6Value);
 Serial.print("\t");
 Serial.println(Pot7Value);
 */

  delay(50);
}


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

That's pretty far off the mark. Here's a very rough skeleton that might get you started:


#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver bots[] {0x40, 0x41};
const size_t numBots {sizeof(bots) / sizeof(bots[0])};

void setup() {
  const float servoFreq = 60.0;

  // Loop through all bots in array to initialize them
  for (size_t botNumber = 0; botNumber < numBots; botNumber++) {
    bots[botNumber].begin();
    bots[botNumber].setPWMFreq(servoFreq);
  }
}

void loop() {
  // Loop through all bots in array to set position
  for (size_t botNumber = 0; botNumber < numBots; botNumber++) {
    // Set bot #botNumber, servo #0 PWM to xxxxx, yyyyy
    bots[botNumber].setPWM(0, xxxxx, yyyyy);

    // Set bot #botNumber, servo #2 PWM to xxxxx, yyyyy
    bots[botNumber].setPWM(2, xxxxx, yyyyy);

    // Set bot #botNumber, servo #4 PWM  to xxxxx, yyyyy
    bots[botNumber].setPWM(4, xxxxx, yyyyy);
  }
}

LOL, I told you I didn't know what I was doing. I'll try to make the changes tonight or in the morning.

Thanks for looking it over and giving me some suggestions.

@Delta_G I do a lot of trying to figure things out on my own, online courses, books, YouTube and have gotten a lot of help on the forums. I've been programming industrial machinery for about 50 years, I've made a lot of Arduino systems, and a few Raspberry pi. Almost all of it I've figured out for myself for there's no school for this or what I do at work. I'll look into what you and @gfvalvo have suggested.

Thanks

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