How to control many servo motor with PCA9685

Here im using this code to control one servo motor with EMG sensor so when i contract the muscle and it exceed the certin threshold the motor rotat . How can i do that with many servo motor using PCA9685 .Here is the sample code i use to control one servo motor with the EMG sensor


#include <Servo.h>

//Threshold for servo motor control with muscle sensor. 
//You can set a threshold according to the maximum and minimum values of the muscle sensor.
#define THRESHOLD 250

#define EMG_PIN 0

//Pin number where the servo motor is connected. (Digital PWM 3)
#define SERVO_PIN 3

//Define Servo motor
Servo SERVO_1;

/*-------------------------------- void setup ------------------------------------------------*/

void setup(){
  
  //BAUDRATE set to 115200, remember it to set monitor serial properly. 
  //Used this Baud Rate and "NL&CR" option to visualize the values correctly.
  Serial.begin(115200);
  
  //Set servo motor to digital pin 3
  SERVO_1.attach(SERVO_PIN);
}

/*--------------------------------  void loop  ------------------------------------------------*/

void loop(){

  //The "Value" variable reads the value from the analog pin to which the sensor is connected.
  int value = analogRead(EMG_PIN);

  //If the sensor value is GREATER than the THRESHOLD, the servo motor will turn to 170 degrees.
  if(value > THRESHOLD){
    SERVO_1.write(170);
  }

  //If the sensor is LESS than the THRESHOLD, the servo motor will turn to 10 degrees.
  else{
    SERVO_1.write(10);
  }

  //You can use serial monitor to set THRESHOLD properly, comparing the values shown when you open and close your hand.
  Serial.println(value);
}

Does each have an EMG sensor or are they all controlled by a single EMG sensor?

single EMG sensor with 5 servo motors @johnwasser

Let me guess, you've powered the servo board from the 5V output of the Arduino, right? Tell us now if you don't want to hear why you shouldn't do this, because you've asked a narrow question, but I expect the project needs a wholistic review.


Here is the wiring look i deleted some components @camsysca

To start, you don't use the Servo library. You need a PCA9685 library. That will probably come with an example of how to control servos. Possibly many servos. The rest is the same: Tell your servos where to go when you want them to move to a new position.

syntax code when using PCA9685 is different that why i dont know to to integrate it togther with the EMG sensor

Have you got the Adafruit PWM Servo Driver library installed ?

It comes with examples

ya i installed that library driver

Have you tried the examples ?

This the example of the code but i dont understand it so that why i cant modify it according to by requirements

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 8 servos, one after the other on the
  first 8 pins of the PCA9685

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815
  
  These drivers use I2C to communicate, 2 pins are required to  
  interface.

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#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

// our servo # counter
uint8_t servonum = 0;

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

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

// You can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  
  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= SERVO_FREQ;   // Analog servos run at ~60 Hz updates
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000000;  // convert input seconds to us
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}

void loop() {
  // Drive each servo one at a time using setPWM()
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);

  // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding!
  // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. 
  for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);
  for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);

  servonum++;
  if (servonum > 7) servonum = 0; // Testing the first 8 servo channels
}

When you write() to a servo using the normal Servo library what you are doing is to write() a value representing the angle that you want the servo to move to. What the Servo is expecting is a signal with a pulse width between 1000 and 2000 microseconds long. 100 microseconds will move the servo to 0 degrees and 2000 microseconds will move it to 180 degrees. The Servo library does all of the conversion between degrees and microseconds for you. The Servo library also has a write(Microseconds() function if you want to do the conversion yourself.

The reason that you might want to do that is because ther are only 180 discrete angles between 0 and 180 but 2000 different microseconds values that you could write. So, if the servo is mechanically capable of doing that many steps you can have finer control of its position

So, with that background, look at the code for the PWM driver board example. If you have followed the above explanation of how a servo works then this line of code in the example that you posted should make more sense

pwm.writeMicroseconds(servonum, microsec);

What it does is to write a pulse of length microsec to servo number servonum. As that line is in a for loop the result is that the servo sweeps through an angle

The bulk of the code in the example is concerned with setting up the board to drive a servo with that name on a pin on the interface board and you can just borrow it and change any parameters that you need to, such as the pin number and the servo name

But for my case i just want all the 5 servo motor to rotat 180 degress once the signal is given to it and return to 0 degree once the signal is off simple as that the things you examplined are so complicated and i dont understand it

If you want to keep it simple then don't use the PWM driver board. Connect the 5 servos directly to the Arduino, power them from an external source and use the normal Servo write() function to control them

Is there a reason why you are using the PWM driver board ?

arduino uno contains only 5 analogue pins and i need to use them for EMG sensor so that why i choosed servo driver is there any other opstion

You can use the Servo library to control servos on any digital pin. Exactly which pins have you used for the rest of the project ?

Assuming that "analof" means analogue, then you can use any pin, analogue or digital, you are not restricted to a specific type of pin.
See
https://www.arduino.cc/reference/en/libraries/servo/

The Servo library supports up to 12 motors on most Arduino boards.

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