Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C interf

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C interf

Post by chicken_pot_pie »

Hi,

I purchased a couple of Adafruit 16-Channel 12-bit PWM/Servo Driver - I2C interface - PCA9685. It is connected to an Uno board and runs the demo(s) just fine. I installed the Adafruit library, again the servos run with the demo(s) just fine.

I purchased the PWM boards so I would not have to use the Servo.h library and also have the ability to chain PWM boards. Having read through the library docs, and numerous failed sketches, I'm not clear on how to configure it to work in the context of the example sketch below. (which works ok as-is) Can someone please modify the sketch, showing me how to get a single channel/servo1 working with PWM/Servo Driver board. At that point, I should be able to understand it and apply it to the other 5 channels in the sketch. Ultimately, there will be 7 servos connected, (6) 180* and (1) continuous, another reason I want to use this PWM board.

Thanks, in advance, for your help. Much appreciated!

Modified servo example sketch included to give you context on what I'm trying to do: (independently control (6) servos with a pot for now)

Code: Select all

#include <Servo.h> 

Servo servo0;              //1st servo
Servo servo1;              //2nd servo
Servo servo2;              //3rd servo
Servo servo3;              //4th servo
Servo servo4;              //5th servo
Servo servo5;              //6th servo

int potPin0 = A0;           //pot1 connected to analog input 0
int potVal0;                // variable for servo0 analog value
int potPin1 = A1;           //pot2 connected to analog input 1
int potVal1;                // variable for servo1 analog value
int potPin2 = A2;           //pot3 connected to analog input 2
int potVal2;                // variable for servo2 analog value
int potPin3 = A3;           //pot4 connected to analog input 3
int potVal3;                // variable for servo3 analog value
int potPin4 = A4;           //pot5 connected to analog input 4
int potVal4;                // variable for servo4 analog value
int potPin5 = A5;           //pot6 connected to analog input 5
int potVal5;                // variable for servo5 analog value


void setup() {           //SETUP*********************************************************************************************************
  
  pinMode(3, OUTPUT);    //set D3 PWM as an output
  pinMode(5, OUTPUT);    //set D5 PWM as an output
  pinMode(6, OUTPUT);    //set D6 PWM as an output
  pinMode(9, OUTPUT);    //set D9 PWM as an output
  pinMode(10, OUTPUT);   //set D10 PWM as an output
  pinMode(11, OUTPUT);   //set D11 PWM as an output
  
  servo0.attach(3);      //attaches servo0 (1st servo) to PWM D3 output
  servo1.attach(5);      //attaches servo1 (2nd servo) to PWM D5 output
  servo2.attach(6);      //attaches servo2 (3rd servo) to PWM D6 output
  servo3.attach(9);      //attaches servo3 (4th servo) to PWM D9 output
  servo4.attach(10);      //attaches servo4 (5th servo) to PWM D10 output
  servo5.attach(11);      //attaches servo5 (6th servo) to PWM D11 output
      
}

void loop() {              //LOOP************************************************************************************************************
                          
  potVal0 = analogRead(potPin0);                //reads potentiometer0 value between 0 and 1023
  potVal0 = map(potVal0, 0, 1023, 0, 180);      //scale it to use it with the servo rotation value between 0-180 degrees
  servo0.write(potVal0);                        //sets the servo0 position according to the scaled value 

  potVal1 = analogRead(potPin1);                //reads potentiometer1 value between 0 and 1023
  potVal1 = map(potVal1, 0, 1023, 0, 180);      //scale it to use it with the servo rotation value between 0-180 degrees
  servo1.write(potVal1);                        //sets the servo1 position according to the scaled value 
  
  potVal2 = analogRead(potPin2);                //reads potentiometer2 value between 0 and 1023
  potVal2 = map(potVal2, 0, 1023, 0, 180);      //scale it to use it with the servo rotation value between 0-180 degrees
  servo2.write(potVal2);                        //sets the servo2 position according to the scaled value  
  
  potVal3 = analogRead(potPin3);                //reads potentiometer3 value between 0 and 1023
  potVal3 = map(potVal3, 0, 1023, 0, 180);      //scale it to use it with the servo rotation value between 0-180 degrees
  servo3.write(potVal3);                        //sets the servo3 position according to the scaled value 
  
  potVal4 = analogRead(potPin4);                //reads potentiometer4 value between 0 and 1023
  potVal4 = map(potVal4, 0, 1023, 0, 180);      //scale it to use it with the servo rotation value between 0-180 degrees
  servo4.write(potVal4);                        //sets the servo4 position according to the scaled value 
  
  potVal5 = analogRead(potPin5);                //reads potentiometer5 value between 0 and 1023
  potVal5 = map(potVal5, 0, 1023, 0, 180);      //scale it to use it with the servo rotation value between 0-180 degrees
  servo5.write(potVal5);                        //sets the servo5 position according to the scaled value 
 }
Last edited by adafruit_support_bill on Fri Oct 10, 2014 6:30 am, edited 1 time in total.
Reason: please use the </> button when submitting code. press </>, then paste your code between the [code] [/code] tags.

User avatar
adafruit_support_bill
 
Posts: 88140
Joined: Sat Feb 07, 2009 10:11 am

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by adafruit_support_bill »

First calibrate your servos as described in the tutorial: https://learn.adafruit.com/16-channel-p ... it-library

Then change this:

Code: Select all

potVal0 = map(potVal0, 0, 1023, 0, 180);
To this:

Code: Select all

potVal0 = map(potVal0, 0, 180, SERVOMIN, SERVOMAX);
And change this:

Code: Select all

  servo0.write(potVal0); 
To this:

Code: Select all

  pwm.setPWM(0, 1024, potVal0)

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

Thank you, will do.

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

Thanks again. I made the changes you suggested.

I've enabled PWM channel 0 in the code and the servo is responding to the pot (0). However, the servo responds full-scale to a minor input from the pot. Generally, I get a 0 to ~160* deflection from 11 to 1 o'clock on the pot. (I confirmed it's roughly the same travel as when using SERVO.H, without the PWM board). I've tweaked the SERVOMIN/SERVOMAX settings a little (and a lot), nothing seems to scale on the pot properly. I'm using a digital MG996R for testing, so I apologize if the analog/digital pots will have a negative impact. If so, I can test an analog pot later, when I have access to it. Also, I'm using a Pololu A-Star 32U4 Mini SV (5V), SCL(3), SDA(2), should that make a difference.

New sketch attached. I've commented out the other channels, but I did a quick test on channel(1) and it worked fine, with the same pot scaling issue, of course.

Code: Select all

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

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#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)

int potPin0 = A0;           //pot1 connected to analog input 0
int potVal0;                // variable for servo0 analog value
int potPin1 = A1;           //pot2 connected to analog input 1
int potVal1;                // variable for servo1 analog value
int potPin2 = A2;           //pot3 connected to analog input 2
int potVal2;                // variable for servo2 analog value
int potPin3 = A3;           //pot4 connected to analog input 3
int potVal3;                // variable for servo3 analog value
int potPin4 = A4;           //pot5 connected to analog input 4
int potVal4;                // variable for servo4 analog value
int potPin5 = A5;           //pot6 connected to analog input 5
int potVal5;                // variable for servo5 analog value


void setup() {           //SETUP*********************************************************************************************************
  
  pwm.begin();
  pwm.setPWMFreq(60);      // Analog servos run at ~60 Hz updates  
      
}

void loop() {              //LOOP************************************************************************************************************
                          
  potVal0 = analogRead(potPin0);                //reads potentiometer0 value between 0 and 1023
  potVal0 = map(potVal0, 0, 180, SERVOMIN, SERVOMAX);
  pwm.setPWM(0, 1024, potVal0);

  /*
  potVal1 = analogRead(potPin1);                //reads potentiometer1 value between 0 and 1023
  potVal1 = map(potVal1, 1, 180, SERVOMIN, SERVOMAX);
  pwm.setPWM(1, 1024, potVal1);
 
  potVal2 = analogRead(potPin2);                //reads potentiometer2 value between 0 and 1023
  potVal2 = map(potVal2, 2, 180, SERVOMIN, SERVOMAX);
  pwm.setPWM(2, 1024, potVal2);
  
  potVal3 = analogRead(potPin3);                //reads potentiometer3 value between 0 and 1023
  potVal3 = map(potVal3, 3, 180, SERVOMIN, SERVOMAX);
  pwm.setPWM(3, 1024, potVal3);
  
  potVal4 = analogRead(potPin4);                //reads potentiometer4 value between 0 and 1023
  potVal4 = map(potVal4, 4, 180, SERVOMIN, SERVOMAX);
  pwm.setPWM(4, 1024, potVal4);
  
  potVal5 = analogRead(potPin5);                //reads potentiometer5 value between 0 and 1023
  potVal5 = map(potVal5, 5, 180, SERVOMIN, SERVOMAX);
  pwm.setPWM(5, 1024, potVal5);
  */
 
}
Last edited by adafruit_support_bill on Fri Oct 10, 2014 5:06 pm, edited 1 time in total.
Reason: pl

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

To clarify, when using SERVO.H sketch, the pot/servo has the correct behavior, scales properly. When using the PWM board and appropriate sketch, I get a full-scale deflection of the servo with a narrow window of the pot, generally between 11 and 1 o'clock. Outside of that window, the behavior is erratic, dependent on the min/max settings, but nothing I want.

User avatar
adafruit_support_bill
 
Posts: 88140
Joined: Sat Feb 07, 2009 10:11 am

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by adafruit_support_bill »

Sorry, the mapping was wrong. For analog pin input, it should use the Arduino 10-bit analog range:

Code: Select all

potVal0 = map(potVal0, 0, 1023, SERVOMIN, SERVOMAX);

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

No worries, thanks again.

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

I made the changes and found the pot no longer makes the servo move, unless the values are increased to something like 700/2000. Strangely, when I run the Servo example, using the default 150/600 min/max settings, the servo moves full-range, as it should. When I use those settings in the sketch below, no movement when I rotate the pot. Here's what the sketch looks like now:

Code: Select all

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

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#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)

int potPin0 = A0;           //pot1 connected to analog input 0
int potVal0;                // variable for servo0 analog value
int potPin1 = A1;           //pot2 connected to analog input 1
int potVal1;                // variable for servo1 analog value
int potPin2 = A2;           //pot3 connected to analog input 2
int potVal2;                // variable for servo2 analog value
int potPin3 = A3;           //pot4 connected to analog input 3
int potVal3;                // variable for servo3 analog value
int potPin4 = A4;           //pot5 connected to analog input 4
int potVal4;                // variable for servo4 analog value
int potPin5 = A5;           //pot6 connected to analog input 5
int potVal5;                // variable for servo5 analog value


void setup() {           //SETUP*********************************************************************************************************
  
  pwm.begin();
  pwm.setPWMFreq(60);      // Analog servos run at ~60 Hz updates  
      
}

void loop() {              //LOOP************************************************************************************************************
                          
  potVal0 = analogRead(potPin0);                //reads potentiometer0 value between 0 and 1023
  potVal0 = map(potVal0, 0, 1023, SERVOMIN, SERVOMAX);
  pwm.setPWM(0, 1024, potVal0);

  /*
  potVal1 = analogRead(potPin1);                //reads potentiometer1 value between 0 and 1023
  potVal1 = map(potVal1, 0, 1023, SERVOMIN, SERVOMAX);
  pwm.setPWM(1, 1024, potVal1);
 
  potVal2 = analogRead(potPin2);                //reads potentiometer2 value between 0 and 1023
  potVal2 = map(potVal2, 0, 1023, SERVOMIN, SERVOMAX);
  pwm.setPWM(2, 1024, potVal2);
  
  potVal3 = analogRead(potPin3);                //reads potentiometer3 value between 0 and 1023
  potVal3 = map(potVal3, 0, 1023, SERVOMIN, SERVOMAX);
  pwm.setPWM(3, 1024, potVal3);
  
  potVal4 = analogRead(potPin4);                //reads potentiometer4 value between 0 and 1023
  potVal4 = map(potVal4, 0, 1023, SERVOMIN, SERVOMAX);
  pwm.setPWM(4, 1024, potVal4);
  
  potVal5 = analogRead(potPin5);                //reads potentiometer5 value between 0 and 1023
  potVal5 = map(potVal5, 0, 1023, SERVOMIN, SERVOMAX);
  pwm.setPWM(5, 1024, potVal5);
  */
 }
Last edited by Franklin97355 on Sun Oct 12, 2014 4:15 pm, edited 1 time in total.
Reason: Added missing [code] tags. Please use the </> button and add code between tags.

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

I think it's sorted out now, at least it's working, scaling normally. I changed:

pwm.setPWM(0, 1024, potVal0);

to

pwm.setPWM(0, 0, potVal0);

Is the 2nd value (1024) a "starting" value? (use 0 for min, use the potVal0 for max?) If so, then this makes sense. If not, please let me know the format.

Thanks again.

User avatar
adafruit_support_bill
 
Posts: 88140
Joined: Sat Feb 07, 2009 10:11 am

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by adafruit_support_bill »

The first parameter is the servo channel,
The second is the starting time for the pulse (out of the 4096 divisions of the basic PWM clock rate)
The third parameter is the end time for the pulse.

So yes. 0 makes more sense for the second parameter when used with servos.

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

Ok, thanks again. I appreciate the helpful support. Much appreciated. Everything's working good, PWM board is great.

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

The PWM board appears to have failed tonight. It's been working for the past few days, no problems, then after a few hours of random use during development, the servos appeared not to work. The rest of the system (MCU, display, etc.) all seem fine, they power on, can program the MCU, etc. No problems.

What I've measured/observed:

-I have the board connected per the instructions on the web site. Also, per the instructions, I connected the 5V from external suppy to the terminal block to supply the servos via the PWM board headers, been working for days, no issues.

-The PWM board power LED works fine when power is applied to the entire system.

-With NO servos attached to the headers, 5.0 VDC is measured at each header, using the header GND/5V pins.

-When any of the (6) servos (PowerHD 1501MG) is attached to any of the headers, the voltage sags to 2.9 to 3.2 VDC, regardless if the servo is new or one that I've been using recently. The sag is at the headers, NOT the terminal block/input or the supply. So, 5V at the terminal blocks while there's ~ 3 volts at the headers, servos are not moving or in use.

-I replaced the PWM board cap with a new, 470uF, same deal, voltage sag when any servo is connected.

Since I'm using this on a project, I'm very concerned about using this board now - and it's been designed into a larger PCB. :| Are there any issues with these boards I should know about? If so, please let me know.

What can I do about this board?

Thanks for your help.

User avatar
adafruit_support_bill
 
Posts: 88140
Joined: Sat Feb 07, 2009 10:11 am

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by adafruit_support_bill »

When any of the (6) servos (PowerHD 1501MG) is attached to any of the headers, the voltage sags to 2.9 to 3.2 VDC,
I'm not familiar with the PowerHD 1501MG, but it sounds like a high torque model. It is possible that the reverse-voltage protection circuit was overloaded. This is the 3-pin device near the C2 capacitor. It can typically handle about 3A continuous. Some high torque servos will pull 1A or more under load.

It is possible to bypass this device - if you are careful about the polarity of your power supply. If you connect your 5v supply direct to the V+ pin on one of the end-headers, it does not pass through the reverse-polarity MOSFET.

User avatar
chicken_pot_pie
 
Posts: 17
Joined: Thu Oct 09, 2014 7:19 pm

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by chicken_pot_pie »

Thanks.

Is there a substitute, higher current part I can put on the board? One that will drop on? What is existing part number?

User avatar
adafruit_support_bill
 
Posts: 88140
Joined: Sat Feb 07, 2009 10:11 am

Re: Servos & The 16-Channel 12-bit PWM/Servo Driver - I2C in

Post by adafruit_support_bill »

The part is an IRLML6401. It is possible to bypass it - but you do need to be more careful with polarity then. I can check with the designer about substitute parts.

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”