Notifications
Clear all

Help me fully understand PWM, PCA9685, and Servo Control / Calibration

12 Posts
5 Users
2 Reactions
970 Views
(@kdemotorsports)
Member
Joined: 10 months ago
Posts: 5
Topic starter  

I have been working on a robotics project and I was able to follow the video about servos to get the basics working. In the process I encountered an error with servo jitter. Really bad servo jitter. I ended up buying new servos and the same code with the usual "manual tweaks" for min / max values worked. However, I'm really trying to fully understand all of this so it isn't just about getting it working. I've watched lots of videos and read lots of materials but just something isn't clicking for me.

Let's start with an example servo, but again I'm trying to understand this well enough to adapt it to any servo. The one in question has on the specs 1520us/330hz. Now if I try to set 330Hz as the frequency using the Adafruit PCA9685 library this does not behave well at all. I also tried adjusting the min / max values just using the trial and error method. However, this approach to me seems flawed. My understanding is that this approach could damage the servos by driving them too far. Yes you can start with conservative numbers, but even those how are they calculated?

I went further and used a test rig to hook to my oscilloscope and I got a pause width of 1.250ms at a refresh rate of 50Hz which if I understand correctly should equal roughly 90 degrees for this servo I described above. Next I hear the term duty cycle which I cannot explicitly find anywhere for the servo I am currently using. Next the Adafruit PCA9685 has another method for setOscillatorFrequency. Which I kind of understand is the clock frequency of the crystal on the board. The part I'm struggling with is the effect of each of these configuration settings and their relationship to each other. I'm relatively new to electronics but most concepts I've been able to pick up. This one just has me confused. I'm really trying to get a grasp on how to use servos completely in a variety of projects. I've seen example code with various values for MIN and MAX some with a prefix of USMIN and USMAX. I don't understand how there can be so many different terminologies and settings for a device as simple as a DC motor and a potentiometer or maybe that's just my inexperience causing me to think that way.

I'm unsure but if anyone can help describe this is in a very layman way that will help me to get all these concepts, how to use them together, and how to set them correctly for various servos I would greatly appreciate it.


   
Inst-Tech reacted
Quote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7425
 

@kdemotorsports Maybe USMIN is micro-seconds Min. Just a guess on my part.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
Inst-Tech reacted
ReplyQuote
Inst-Tech
(@inst-tech)
Member
Joined: 3 years ago
Posts: 554
 

Posted by: @kdemotorsports

I have been working on a robotics project and I was able to follow the video about servos to get the basics working. In the process I encountered an error with servo jitter. Really bad servo jitter. I ended up buying new servos and the same code with the usual "manual tweaks" for min / max values worked. However, I'm really trying to fully understand all of this so it isn't just about getting it working. I've watched lots of videos and read lots of materials but just something isn't clicking for me.

Let's start with an example servo, but again I'm trying to understand this well enough to adapt it to any servo. The one in question has on the specs 1520us/330hz. Now if I try to set 330Hz as the frequency using the Adafruit PCA9685 library this does not behave well at all. I also tried adjusting the min / max values just using the trial and error method. However, this approach to me seems flawed. My understanding is that this approach could damage the servos by driving them too far. Yes you can start with conservative numbers, but even those how are they calculated?

I went further and used a test rig to hook to my oscilloscope and I got a pause width of 1.250ms at a refresh rate of 50Hz which if I understand correctly should equal roughly 90 degrees for this servo I described above. Next I hear the term duty cycle which I cannot explicitly find anywhere for the servo I am currently using. Next the Adafruit PCA9685 has another method for setOscillatorFrequency. Which I kind of understand is the clock frequency of the crystal on the board. The part I'm struggling with is the effect of each of these configuration settings and their relationship to each other. I'm relatively new to electronics but most concepts I've been able to pick up. This one just has me confused. I'm really trying to get a grasp on how to use servos completely in a variety of projects. I've seen example code with various values for MIN and MAX some with a prefix of USMIN and USMAX. I don't understand how there can be so many different terminologies and settings for a device as simple as a DC motor and a potentiometer or maybe that's just my inexperience causing me to think that way.

I'm unsure but if anyone can help describe this is in a very layman way that will help me to get all these concepts, how to use them together, and how to set them correctly for various servos I would greatly appreciate it.

Hi @kdemotorsports, I think @zander (Ron) is correct..In your spec, "The one in question has on the specs 1520us/330hz.", the 1520 uS( micro seconds) equals 1.52 mS (milli-second) which is 657.9 hz, where as the 330 hz is 3.03 mS (milli-seconds.. so your min-max range is 300-658 hz.. The PWM duty cycle is the period of time the the pulse is on (high), with regards to the entire pulse width.. for example if the pulse width is 20 mS (50 hz, refresh rate) and the duration of the pulse that is high is 1.52 mS/20 mS= 0.076 ( that's ~ 7.6% duty cycle), and at 3.03 mS/20 mS=0.15 (that's ~ 15% duty cycle)..this is the ~ range that the Servos operate in..

hope this clears this up for you..but don't worry about it too much, as it was very confusing to most of us in the beginning.. but over time, you'll get the gist of it.

regards,

LouisR

 

LouisR


   
ReplyQuote
(@kdemotorsports)
Member
Joined: 10 months ago
Posts: 5
Topic starter  

Thank you all so far for the help. I'm still not getting this though. This code:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pca9685 = Adafruit_PWMServoDriver(0x40);
/* Are these two some calculated percentage of the 1,520us? */
#define SERVOMIN 100 // Still don't understand how this relates to duty cycle, etc...
#define SERVOMAX 6700 // Still don't understand how this relates to duty cycle, etc...
#define SERVO_FREQ 657.9

int minDegrees = 0;
int maxDegrees = 180;
int servonum = 15;
void setup()
{
  Serial.begin(19200);
  delay(500);
  pca9685.begin();
  pca9685.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
  int degrees = map(90, 0, 180, SERVOMIN, SERVOMAX);
  pca9685.setPWM(15, 0, degrees);
}

void loop()
{
}

Produces this on the scope:

Frequency: 675.6Hz

Period: 1.480ms

Mean: 4.40V

Pk-Pk: 5.80V

Minimum: -200mV

Maximum: 5.60V

+Pulse Width: 1.230ms

Rise Time: 10.00us

 

Keep in mind I don't claim to understand all of these values on the scope as again I'm new to all of this. However, based on the description above this seems like it is very close to the spec of the servo yet if I connect the servo it behaves with very limited motion. The values I used to get the servo to function meaning rotate from 0 to 180 is very different it uses 40, 50, or 60Hz max, and min and max values closer to 100 and 600. This is why I'm so confused when trying to relate what I hear, see, and attempting to understand.

Also that seems to align somewhat with this "so your min-max range is 300-658 hz.. The PWM duty cycle is the period of time the the pulse is on (high), with regards to the entire pulse width.. for example if the pulse width is 20 mS (50 hz, refresh rate)" but I'm still lost as to where the 50Hz came from.

 

If I change the code to:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pca9685 = Adafruit_PWMServoDriver(0x40);
/* Are these two some calculated percentage of the 1,520us? */
#define SERVOMIN 300 // Still don't understand how this relates to duty cycle, etc...
#define SERVOMAX 658 // Still don't understand how this relates to duty cycle, etc...
#define SERVO_FREQ 50
void setup()
{
  pca9685.begin();
  pca9685.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
  int degrees = map(90, 0, 180, SERVOMIN, SERVOMAX);
  pca9685.setPWM(15, 0, degrees);
}
void loop()
{
}

The scope reads:

Produces this on the scope:

Frequency: 50Hz

Period: 20ms

Mean: 1.0V

Pk-Pk: 5.80V

Minimum: -200mV

Maximum: 5.60V

+Pulse Width: 2.340ms

Rise Time: 10.00us

 

Obviously this aligns with the explanation above "I think" yet I still can't wrap my head around how this relates to the values above. Sorry I'm sure it all makes sense to those describing this. I'm just not connecting the dots yet. I get that the frequency is over what duration of time X number of pulses are sent. I understand that the the duty cycle refers to the width of each pulse. But there is still some piece I'm missing.

Thank you all for your patience while I try to wrap my head around this. 😀


   
ReplyQuote
(@kdemotorsports)
Member
Joined: 10 months ago
Posts: 5
Topic starter  

@zander Thanks I did verify this is the case in the examples. So that part now makes sense. Although it does cause me to question is it better to use the .writeMicroseconds vs the .setPWM? Is one more accurate than the other?


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7425
 

@kdemotorsports Sorry, I have no practical experience with that but I know someone that does and I am sure he will jump in with an answer.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7425
 

@kdemotorsports Normally, I would recommend researching the libraries available for this device. I would be looking for a library whose API closely matches your requirements. What I mean by that to be simplistic is if you are mainly interested in setting the servo to specific rotation angles from a zero point, then I would look for a library that does that and hides all the other details. Since you appear to have some expertise with a scope, you may prefer to program at the iron level, but after a good many decades of doing that myself, I am more interested in getting the job done quickly. I don't know how many days I have left.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
(@kdemotorsports)
Member
Joined: 10 months ago
Posts: 5
Topic starter  

@zander I’m using the most commonly used library and in fact I’m able to set the positions the way I want. So getting it to work isn’t really what I’m trying to accomplish rather trying to get a good understanding so that if it doesn’t work I can hopefully figure out why. 😂 Thanks for the reply and I’m a novice at the scope just know enough to be dangerous.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 4 years ago
Posts: 7425
 

@kdemotorsports I know what you mean re scope, it's been over 50 years since I last used a scope. I don't remember anything about it. 

If the library gives you what you need then all is good.

First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 3 years ago
Posts: 2552
 

Posted by: @kdemotorsports

getting it to work isn’t really what I’m trying to accomplish rather trying to get a good understanding so that if it doesn’t work I can hopefully figure out why

This forum is probably better suited to helping you get it working than going into a detailed description of how and why they work (or fail). I'd suggest Googling and find a video to help fill in the background.

 

Anything seems possible when you don't know what you're talking about.


   
ReplyQuote
(@davee)
Member
Joined: 3 years ago
Posts: 1795
 

Hi @kdemotorsports,

  Sorry, I can't help you directly, as I haven't got such a servo motor to test out things, and have done very little with servo motors generally. I was hoping some clear answers would emerge, but as you still seem to be partly in the dark, albeit you now think you can make it work, I offer the following suggestions to consider. Please understand, they may well be in error .. they are just suggestions to ponder and test for yourself. Hopefully, even if there are errors, they may help you find the truth.

-------------------

From the little I can see on the web, the "specification" of "1520us/330hz" needs some rather careful interpretation. 

I suspect it is implying a pulsewidth of 1520 microsecs corresponds to the midpoint angle,

with roughly 1000 microsecs pulse width corrresponding to -90 degrees with respect to midpoint,

and roughly 2000 microsecs puse width corresponding to +90 degrees with respect to midpoint

-------

Now I say "roughly", because it seems the exact value is down to chance ... hence code has magic parameters like SERVOMIN to define the values needed for your actual servo. As to how these parameters relate to actual timings, I suggest you try a few variations, and watch on the scope. I suspect some are additions or subtractions, perhaps with regard to each other, but I haven't tried the necessary investigation to figure it out.

Clearly these are specific to the software, whilst the required waveforms are dictated by the servo hardware.

Furthermore, note the +90 and -90 degrees directions may be swapped.

A page I noted that may be helpful is:

https://www.pololu.com/blog/17/servo-control-interface-in-detail

For your investigation of what pulses the servo needs, you might consider writing or obtaining simple pulse generation software, (rather than using a complex library,) that creates the waveform specified directly for easier testing of the hardware, first using your scope to check the waveform matches our expectations, then using it to drive the servo to see the result. Remember most Arduino processors are fairly slow, so don't be surprised if a line of code take a few microseconds.

Obviously, once you have completed the investigation, the more complex library may be more appropriate for the application.

-------

As that reference mentions, and I have seen noted elsewhere, the 50Hz/20 millisecs repetition rate maybe partly historical in that previously, to hold a fixed angle the pulse width had to repeated at a regular interval to avoid the servo 'forgetting' the command. It seems, more modern servos have a more resilient memory, and will hold a commanded position indefinitely, but the 'old habit' of resending the pulse 50 times per second is still common practice.

So the 'duty cycle' may be just a confusion factor, either as a hangover for 'ancient' servos, and/or a consequence of using a PWM driver within the microcontroller to generate a suitable waveform, and PWM waveforms are often specified in terms of a duty cycle.

------------------------

AS I say ... this whole message may be full of misinterpretations on my part .. so please do not treat it as 'factual', but rather as a suggestion to consider and check out for yourself, using all the resources you can muster, including your own setup and the web.

Please note, I have seen many warnings that it is possible to burn out motors and strip gears of servos by commanding them to go beyond their mchanical limits. So please be careful and cautious in your approach. 

Obviously, I take no responsibilities for any breakages or losses for any errors, etc.

Best wishes, Dave


   
ReplyQuote
Inst-Tech
(@inst-tech)
Member
Joined: 3 years ago
Posts: 554
 

@kdemotorsports , Ah.. see see your what your confusion is now with "The  total pulse width is 20 mS, that is 50hz.. freq= 1/time (Freq= 1/T), therefor f=1/.020 seconds = 50 hz.. that where the 50 hz come from..

The PWM circuitry generates the 50 hz pulse, with the duty cycle you program in your sketch. The library function that you are using does that for you..

now the rest of it should be clearer, that is the duty cycle is just a percentage of on time with regards to the total pulse width.. hope this clears it up for you..

regards,

LouisR

LouisR


   
ReplyQuote