Help with 16 x 12-bit PWM & Servo Shield

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
annietcu
 
Posts: 2
Joined: Tue Sep 02, 2014 5:02 pm

Help with 16 x 12-bit PWM & Servo Shield

Post by annietcu »

Please Help.

My project I am connecting a 16 x 12-bit PWM & Servo Shield to 3-4 servos control each by a button to my Servo Shield. I am having trouble finding an example code to help me get started. (I delete my old one on accident). I just need the example for turning on and off servos by pressing one button per servo. If you have an example code I'd appreciate it to help me get idea of how to write the code and get started on my project.

Thanks,
Annie
Attachments
moving art 2.jpeg
moving art 2.jpeg (261.68 KiB) Viewed 811 times

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

What exactly do you want the button to do? What exactly should a servo do when the button is pressed? What should the servo do when the button is released?

User avatar
annietcu
 
Posts: 2
Joined: Tue Sep 02, 2014 5:02 pm

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by annietcu »

I would like the servos to move from 0 degrees to 180 degrees when the button is pressed. If one presses the button for a second time the servo horn would go from 180 degrees back to 0 degrees.
Thank you for getting back to me so fast Rick!
-Annie

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

This tutorial shows how to move servos using the Adafruit PWM Servo Library
https://learn.adafruit.com/16-channel-p ... it-library

Go through the tutorial and make sure you can control the servos with the 'servo' example sketch.

This tutorial will show you how to hook up a button
https://learn.adafruit.com/adafruit-ard ... tal-inputs

When you have those both working, you want to combine them into your actual sketch. Use this debounce routine to read the button presses:

Code: Select all

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}
Assuming your button is connected to pin 2, your code for a single button and servo will look something like this:

Code: Select all

uint8_t buttonState = HIGH;
uint8_t previousButtonState = HIGH;
void loop()
{
  buttonState = debounceRead(2);
  if ((LOW == buttonState) and (HIGH == previousButtonState))
  {
    moveServo(servonum, SERVOMIN, SERVOMAX);
  }
  if ((HIGH == buttonState) and (LOW == previousButtonState))
  {
    moveServo(SERVOMAX, SERVOMIN);
  }
  previousButtonState = buttonState;
}

void moveServo(int servonum, int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }
}

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}
That should be enough to get you started.

User avatar
richard905
 
Posts: 7
Joined: Fri May 25, 2012 6:28 pm

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by richard905 »

Thank you, Rick & Annie, your code is very helpful for me, my application is very similar.
I'd like to drive 5 servos, by using one pushbutton,(PIN2) , when the button is pressed, all 5 servos move from 0 degree to 100 degrees; when the button is pressed for a second time, all 5 servos move from 100 degrees back to 0 degree.

How to modify your code? (Could you post the complete code?) appreciate!

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

I would modify the moveServo function to move all five servos at once:

Code: Select all

uint8_t buttonState = HIGH;
uint8_t previousButtonState = HIGH;
void loop()
{
  buttonState = debounceRead(2);
  if ((LOW == buttonState) and (HIGH == previousButtonState))
  {
    moveServos(SERVOMIN, SERVOMAX);
  }
  if ((HIGH == buttonState) and (LOW == previousButtonState))
  {
    moveServos(SERVOMAX, SERVOMIN);
  }
  previousButtonState = buttonState;
}

void moveServos(int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
}

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}

User avatar
richard905
 
Posts: 7
Joined: Fri May 25, 2012 6:28 pm

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by richard905 »

Hi Rick:
Thank you very much for your help, the code works! but when the button is pressed, the servos move back & forth once rather than 0 degree to 100 degrees; another issue is little noise. (I use Tower Pro SG90 micro 9g servos). Here is my complete code, Could you check for me? Thanks again.

Code: Select all

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN  150 
#define SERVOMAX  600 
uint8_t servonum = 0;

uint8_t buttonState = HIGH;
uint8_t previousButtonState = HIGH;

void setup() {
  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(uint8_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 loop()
{
  buttonState = debounceRead(2);
  if ((LOW == buttonState) and (HIGH == previousButtonState))
  {
    moveServos(SERVOMIN, SERVOMAX);
  }
  if ((HIGH == buttonState) and (LOW == previousButtonState))
  {
    moveServos(SERVOMAX, SERVOMIN);
  }
  previousButtonState = buttonState;
}

void moveServos(int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
}

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}
Last edited by adafruit_support_rick on Sun Nov 09, 2014 7:14 pm, edited 1 time in total.
Reason: please use code tags (</> button)when posting code

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

Code: Select all

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN  150 
#define SERVOMAX  600 
uint8_t servonum = 0;

uint8_t buttonState = HIGH;
uint8_t previousButtonState = HIGH;

int servoState = SERVOMIN;

void setup() {
  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(uint8_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 loop()
{
  buttonState = debounceRead(2);
  if ((LOW == buttonState) and (HIGH == previousButtonState))
  {
    if (servoState == SERVOMIN) {
      moveServos(SERVOMIN, SERVOMAX);
      servoState = SERVOMAX;
    }
    else {
      moveServos(SERVOMAX, SERVOMIN);
      servoState = SERVOMIN;
    }
  }
  previousButtonState = buttonState;
}

void moveServos(int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
}

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}

User avatar
richard905
 
Posts: 7
Joined: Fri May 25, 2012 6:28 pm

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by richard905 »

Rick, I'd like to drive 2x5 servos(2 groups) for my project, by using two pushbutton,(PIN2, PIN3) ,

when the button1 is pressed, Only Group-A 5 servos(0,1,2,3,4) move from 0 degree to 100 degrees;
when the button1 is pressed for a second time, those 5 servos move from 100 degrees back to 0 degree;

when the button2 is pressed, Only Group-B 5 servos(5,6,7,8,9) move from 0 degree to 100 degrees;
when the button2 is pressed for a second time, those 5 servos move from 100 degrees back to 0 degree;

I modify the code, seems some mistake, Could you check for me again? Thanks so much again!

Code:

Code: Select all

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN  150
#define SERVOMAX  600
uint8_t servonum = 0;

uint8_t buttonState1 = HIGH;
uint8_t previousButtonState1 = HIGH;
uint8_t buttonState2 = HIGH;
uint8_t previousButtonState2 = HIGH;


int servoState = SERVOMIN;

void setup() {
  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(uint8_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 loop()
{
  buttonState1 = debounceRead(2);
  buttonState2 = debounceRead(3);
  if ((LOW == buttonState1) and (HIGH == previousButtonState1));
     ((LOW == buttonState2) and (HIGH == previousButtonState2));
  {
    if (servoState == SERVOMIN) {
      moveServos(SERVOMIN, SERVOMAX);
      servoState = SERVOMAX;
    }
    else {
      moveServos(SERVOMAX, SERVOMIN);
      servoState = SERVOMIN;
    }
  }
  previousButtonState1 = buttonState1;
  previousButtonState2 = buttonState2;
}

void moveServos(int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
    pwm.setPWM(5, 0, pulselen);
    pwm.setPWM(6, 0, pulselen);
    pwm.setPWM(7, 0, pulselen);
    pwm.setPWM(8, 0, pulselen);
    pwm.setPWM(9, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
    pwm.setPWM(5, 0, pulselen);
    pwm.setPWM(6, 0, pulselen);
    pwm.setPWM(7, 0, pulselen);
    pwm.setPWM(8, 0, pulselen);
    pwm.setPWM(9, 0, pulselen);
  }
}

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}
Last edited by adafruit_support_rick on Sat Nov 15, 2014 9:58 am, edited 1 time in total.
Reason: please use Code tags when posting code (</> button)

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

The easiest thing is to just duplicate all of the relevant code in loop. And you need a separate routine for each group of servos:

Code: Select all

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN  150
#define SERVOMAX  600
uint8_t servonum = 0;

uint8_t buttonState1 = HIGH;
uint8_t previousButtonState1 = HIGH;
uint8_t buttonState2 = HIGH;
uint8_t previousButtonState2 = HIGH;


int servoState1 = SERVOMIN;
int servoState2 = SERVOMIN;

void setup() {
  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(uint8_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 loop()
{
  //Check button for servo group 1
  buttonState1 = debounceRead(2);
  if ((LOW == buttonState1) and (HIGH == previousButtonState1))
  {
    if (servoState1 == SERVOMIN) {
      moveServoGroup1(SERVOMIN, SERVOMAX);
      servoState1 = SERVOMAX;
    }
    else {
      moveServoGroup1(SERVOMAX, SERVOMIN);
      servoState1 = SERVOMIN;
    }
  }
  previousButtonState1 = buttonState1;
  
  //check button for servo group 2
  buttonState2 = debounceRead(3);
  if  ((LOW == buttonState2) and (HIGH == previousButtonState2))
  {
    if (servoState2 == SERVOMIN) {
      moveServoGroup2(SERVOMIN, SERVOMAX);
      servoState2 = SERVOMAX;
    }
    else {
      moveServoGroup2(SERVOMAX, SERVOMIN);
      servoState2 = SERVOMIN;
    }
  }
  previousButtonState2 = buttonState2;
}

//Servo group 1 is servos 0, 1, 2, 3, 4
void moveServoGroup1(int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(0, 0, pulselen);
    pwm.setPWM(1, 0, pulselen);
    pwm.setPWM(2, 0, pulselen);
    pwm.setPWM(3, 0, pulselen);
    pwm.setPWM(4, 0, pulselen);
  }
}

//Servo group 2 is servos 5, 6, 7, 8, 9
void moveServoGroup2(int from, int to)
{
if (from < to)
  for (uint16_t pulselen = from; pulselen < to; pulselen++) {
    pwm.setPWM(5, 0, pulselen);
    pwm.setPWM(6, 0, pulselen);
    pwm.setPWM(7, 0, pulselen);
    pwm.setPWM(8, 0, pulselen);
    pwm.setPWM(9, 0, pulselen);
  }
else
  for (uint16_t pulselen = from; pulselen > to; pulselen--) {
    pwm.setPWM(5, 0, pulselen);
    pwm.setPWM(6, 0, pulselen);
    pwm.setPWM(7, 0, pulselen);
    pwm.setPWM(8, 0, pulselen);
    pwm.setPWM(9, 0, pulselen);
  }
}

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}

User avatar
richard905
 
Posts: 7
Joined: Fri May 25, 2012 6:28 pm

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by richard905 »

Rick: Based on your post "duplicate all of the relevant code in loop. And you need a separate routine for each group of servos", I tried different modified codes, unfortunately, all failed, I am mechanical guy, not good at Arduino code, Could you give me hints? appreciate!!

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

Did you try running the code I posted?

User avatar
richard905
 
Posts: 7
Joined: Fri May 25, 2012 6:28 pm

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by richard905 »

Rick, Your code works great! Thank you so much!!

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Help with 16 x 12-bit PWM & Servo Shield

Post by adafruit_support_rick »

You're welcome!

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

Return to “Arduino Shields from Adafruit”