Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
tigress303
 
Posts: 4
Joined: Thu May 21, 2015 12:00 am

Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by tigress303 »

I'll preface this by saying yes, I probably did bite off more than I can chew here. I am working on a project for my engineering class and have decided to use a series of servos to make a self playing xylophone. Each servo will have a small mallet attached to it and the plan is to make them quickly sweep forward and back to hit the keys. I have never used an Arduino before this project and am not familiar with coding. I am using an Arduino Uno with the 16-Channel PWM controller to control my servos. I did install the library for it but have been struggling to find servo basics.
For example:
What is a tick?
What does the servo min and max mean?
What does a low/high point of a sweep mean?

I have had experience with basic python and understand some of the logic of coding. Any help understanding the basics so I can get my code up and running would be helpful!

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by adafruit_support_mike »

The PWM controller has an internal 12-bit counter. Each time that counter increments, it's called a 'tick'.

More specific words don't apply because you can adjust the length of a tick pretty widely. For servos, you want a whole 4096-tick cycle to happen about 50 times per second, so each tick is slightly less than 5 microseconds. If you wanted to update 100 times per second, the duration of a tick would be about 2.5 microseconds.

The signal that tells a servo what to do is a pulse between 1ms and 2ms long. A 1.5ms pulse tells the servo to move to its center position. A 1ms pulse tells the servo to move to its extreme left rotation, and a 2ms pulse tells the servo to move to its extreme right rotation.

The PWM driver only knows ticks and counting though, so we have to run the math ourselves to find the number of ticks that correspond to 1ms and 2ms. In this case, 205 ticks last about 1ms and 410 ticks last about 2ms. Using those numbers, you can calculate the tick count for any servo position. The 1ms count is called servoMin, the 2ms tick count is called servoMax.

I'm not sure exactly what 'high point' and 'low point' indicate, but would guess that they refer to the smallest and largest tick counts for the motion that just happened.

User avatar
tigress303
 
Posts: 4
Joined: Thu May 21, 2015 12:00 am

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by tigress303 »

Thank you that clears quite a bit up.

User avatar
tigress303
 
Posts: 4
Joined: Thu May 21, 2015 12:00 am

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by tigress303 »

One more question: I have figured out what different parts of the code mean. Now my objective is to create a function that will move a single selected servo from its min to its max. This way, I can control the individual servos to move when needed. How does one control individual servos? This is my code so far.

Code: Select all

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

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define SERVOMIN  150 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  350 // this is the 'maximum' pulse length count (out of 4096)

// our servo # counter
uint8_t servonum = 0;
Servo servo1;

void setup() {
  servo1.attach(0);
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

  pwm.begin();
  
  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
}

// 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. its not precise!
void setServoPulse(uint16_t n, double pulse) {
  double pulselength;
  
  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= 60;   // 60 Hz
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000;
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}

void hit()
{
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen); //Controls servo arm out
  }
  delay (500); //This can be adjusted for faster or slower strikes
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen); //Controls servo arm back in
  }
  delay(500);
}

void loop() 
hit();

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by adafruit_support_mike »

In the line:

Code: Select all

    pwm.setPWM(servonum, 0, pulselen); //Controls servo arm out
the value 'servonum' identifies the servo.

User avatar
tigress303
 
Posts: 4
Joined: Thu May 21, 2015 12:00 am

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by tigress303 »

Ah I see. Is there a way to set seronum to different servos in the loop? For example having servo one use the hit function then servo three, etc.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by adafruit_support_mike »

Yes.

User avatar
orchard800
 
Posts: 48
Joined: Fri Apr 17, 2015 9:25 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by orchard800 »

Your 'learn' article on this states:
This function sets the start (on) and end (off) of the high segment of the PWM pulse on a specific channel. You specify the 'tick' value between 0..4095 when the signal will turn on, and when it will turn of. Channel indicates which of the 16 PWM outputs should be updated with the new values.
Why would you want to control where in the cycle the pulse starts and ends? Why not just the beginning and end?

User avatar
orchard800
 
Posts: 48
Joined: Fri Apr 17, 2015 9:25 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by orchard800 »

Ps. I think these are the high and low points the poster was referring to.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by adafruit_support_mike »

orchard800 wrote:Why would you want to control where in the cycle the pulse starts and ends? Why not just the beginning and end?
Power management. Let's say you have 16 LEDs and want to run them at a 25% duty cycle:

If you have them all on during counts 0-1023, the power supply has to deliver 400mA for that time, then nothing for the rest of the cycle.

If you divide the LEDs into four groups and power them on the following counts:

set 1 - 0-1023
set 2 - 1024 - 2047
set 3 - 2048 - 3071
set 4 - 3072 - 4095

The power supply sees a more or less constant load of 100mA. That isn't such a big deal for 16 LEDs, but can make the difference between a small, simple power supply and a large/heavy/complex one if you're running a hundred LEDs or so.

User avatar
orchard800
 
Posts: 48
Joined: Fri Apr 17, 2015 9:25 pm

Re: Using the Adafruit 16-Channel 12-bit PWM/Servo Shield

Post by orchard800 »

Aaaah!!!!! I get it. Thank-you.

So where the pulse happens in the cycle doesn't affect the operation of each device but allows you to not run everything at the same moment.

Perfect for the hexapod I'm building with a ras pi, 2x servo hats and 18 tower pro servos!

Thanks!

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

Return to “General Project help”