1

I am having a problem with Servo Buzz that I have ascertained is from the millis() function using too much time for Arduino to generate a steady pulse for the servos.

I looked at this thread but was unable to figure out a solution from the code (I'm a novice)

Stack Exchange Servo Buzz

I am including my code even though it is very large, the only time I need to servos to run smoothly is in case 4 of my switch/case.

#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
#include <Adafruit_MotorShield.h> //LIBRARY FOR MOTOR DRIVER SHIELD
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h> //LIBRARY FOR SERVOS

Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); 
Adafruit_StepperMotor *myStepper = AFMS.getStepper(200, 2);
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
#define WHITE 0x7


Servo pan;
Servo tilt;//DECLARE SERVOS
int yy = 0; //STEP COUNTER
//declares ints
uint8_t i=0; //BUTTON INPUTS
int x = 1; //case statement movement
int input_stage = 0;
int time = millis(); //time from when the thing turned on

//user inputs
int total_hour = 0;
int total_minute = 0;
int slide_min = 0;
int slide_max = 0;
int pan_min = 800 ;
int pan_max = 2200;
int tilt_min = 800;
int tilt_max = 2200;


//Integers used for calculations for later
int total_steps = yy;
long total_time = 0;
long step_duration = 0;
int total_pan = 0;
int total_tilt = 0;
long pan_duration = 0;
long tilt_duration = 0;
long step_millis = 0;
long pan_millis = 0;
long tilt_millis = 0;
int step_percent = 0;

// Integers for real time program sliding action
int cur_step = 0;
int pan_pos = 0;
int tilt_pos = 0;
long run_dur = 0;
long start_time = 0;
int total_slide = 0;
long display_refresh = millis();
long display_dur = 1000;
int d = 1;
long end_time = millis();
int m = 0;

void setup(){  
  lcd.begin(16, 2);
  lcd.setBacklight(WHITE);
  lcd.print("Welcome to LapsR");//initialize
  delay(2000);

  AFMS.begin();  //initialize motor shield
  pan.attach(10); //attach servos to pins
  tilt.attach(9);

  myStepper->setSpeed(30); // set speed

  lcd.setCursor(0, 0);
  lcd.print("By Doug E FresH!");
  delay(2500);
  lcd.setCursor(0, 1);
  lcd.print("Thanks to: Dave");
  delay(2000);
  lcd.setCursor(0, 1);
  lcd.print("Thanks to:  Max");
  delay(2000);
  pan.writeMicroseconds(1500); //set pan and tilt servos to centre ish
  tilt.writeMicroseconds(1500); 
  delay(5000);
  pan.writeMicroseconds(1000); //Jitter Test
  tilt.writeMicroseconds(1000); 
  delay(5000);
  pan.writeMicroseconds(2000); //Jitter Test
  tilt.writeMicroseconds(2000); 
  delay(5000);
}

void loop(){  
  uint8_t buttons = lcd.readButtons();  //read lcd buttons
  lcd.blink(); //set cursor to blink
  int limit1 = 4;  //declare limit switch
  pinMode(limit1, INPUT_PULLUP);  // sets pin mode to button



  //begin case statement
  switch(x){
  case 1:

   if(m==0){ //move slider backwards until it finds a limit switch
    if((digitalRead(limit1) == HIGH)){ // digital read reads the limit switch pin - HIGH means the switch is open 
      myStepper->step(2,BACKWARD,DOUBLE);
      lcd.clear();
      lcd.print("stage 1");
      delay(10);   
    }
    else{ //move to the next step
      myStepper->release(); //release motor
      m = 1; //set program to 2nd stage
    }
  }
  if(m==1){ // moving ahead jus a bit so there is some pad for innacuracy
    yy = 50; //step counter is initialized
    lcd.clear();
    lcd.print("stage 2");
    delay(1000); 
    myStepper->step(50,FORWARD,SINGLE); //move forward 50 steps
    m = 2;//move to the next step
  } 
  if(m==2){ //stage 3 dawg
    if((digitalRead(limit1) == HIGH)){//count steps til limit is hit
      myStepper->step(1,FORWARD,SINGLE);//move forward 1 step
      lcd.clear();
      lcd.print("stage 3");   
      yy++; //step counter move up one
      delay(10); 
    }
    else{  //display step percentage and total steps
      x=2;
      lcd.clear();
      lcd.print("step %");lcd.print((yy-100)/100);
      delay(5000);
      lcd.clear();
      lcd.print("total: ");lcd.print(yy-100);
      delay(5000);

      myStepper->step((yy - 50),BACKWARD,SINGLE); // reset to start position (minus 50 steps for pad)
      myStepper->release(); // release motor
      step_percent = (yy-100)/100; //make calculations
      total_steps = yy-100;
    }
  }  


break;

  case 2:

    if(input_stage == 0){ //enter duration
      if(d==1){
        lcd.clear();
        lcd.print("Total Duration?");//start asking for inputs - start with total overall duration hours
        lcd.setCursor(0, 1);
        lcd.print("H: ");
        lcd.print(total_hour);
        lcd.print("  M: ");
        lcd.print(total_minute);
        lcd.setCursor(3,1);
        display_refresh = millis();
        d = 0;
      }
      if (buttons & BUTTON_UP) {  //sets hour up - slight debounce delay
        total_hour = total_hour++;
        delay(250);
        d=1;
      }  
      if (buttons & BUTTON_DOWN) { //sets hour down 
        total_hour = total_hour--;
        delay(250);
        d = 1;
      }   
      if (buttons & BUTTON_SELECT){
        input_stage++;delay(250); //select button moves to next stage
        lcd.clear();
        d=1;
      }
    }  
    if(input_stage == 1){
      uint8_t buttons = lcd.readButtons();
      if(d==1){  //when d == 1 update display
        lcd.clear();
        lcd.print("Total Duration?");//ask for minutes
        lcd.setCursor(0, 1);
        lcd.print("H: ");
        lcd.print(total_hour);
        lcd.print("  M: ");
        lcd.print(total_minute);
        lcd.setCursor(9,1);
        d=0;
      }
      if (buttons & BUTTON_UP) {
        total_minute = total_minute++;  //set minutes
        delay(100);
        d=1;
      }
      if (buttons & BUTTON_DOWN) {
        total_minute = total_minute--; //set minutes
        d=1;
        delay(100);
      }
     if (buttons & BUTTON_SELECT){
       input_stage++; // select moves to next stage
       delay(250);
       lcd.clear();
       d=1;
     }
     if (buttons & BUTTON_LEFT){
       input_stage--; //back moves to previous stage
       delay(250);
       d=1;
     }
   }
   if(input_stage == 2){
     uint8_t buttons = lcd.readButtons();
     if(d==1){
       lcd.clear();
       lcd.print("Slide%start-fin");//ask for minimum slide percentage
       lcd.setCursor(0, 1);
       lcd.print("S: ");
       lcd.print(slide_min);
       lcd.print("  F: ");
       lcd.print(slide_max);
       lcd.setCursor(3,1);
       d=0;
     }
     if (buttons & BUTTON_UP && slide_min < 100) {
       slide_min = slide_min++; // select start position in percentgae
       d=1;
       delay(100);
       myStepper->step(step_percent, FORWARD, DOUBLE); //move forward one percent - allows user to preview positions
     }
     if (buttons & BUTTON_DOWN && slide_min > 1) { // do not allow motor to move below 0 percent
       slide_min = slide_min--;
       myStepper->step(step_percent, BACKWARD, DOUBLE);//move forward one percent - allows user to preview positions
       d=1;
       delay(100);
     }
     if (buttons & BUTTON_SELECT){ //moves to next stage
       input_stage++;
       delay(250);
       lcd.clear();
       slide_max = slide_min; //sets ending position to set min position
       d=1;
     }
     if (buttons & BUTTON_LEFT){
       input_stage--;delay(250); // previous stage
       d=1;
     }
   }
   if(input_stage == 3){
     uint8_t buttons = lcd.readButtons();
     if(d==1){
       lcd.clear();
       lcd.print("Slide%start-fin");//ask for max slide percentage
       lcd.setCursor(0, 1);
       lcd.print("S: ");
       lcd.print(slide_min);
       lcd.print("  F: ");
       lcd.print(slide_max);
       lcd.setCursor(9,1);
       d=0;
     }
     if (buttons & BUTTON_UP && slide_max < 100) {
       slide_max = slide_max++;
       d=1;delay(100);
       myStepper->step(step_percent, FORWARD, DOUBLE);  //shows set stepper position
     }
     if (buttons & BUTTON_DOWN  && slide_max > 1) {
       slide_max = slide_max--;
       myStepper->step(step_percent, BACKWARD, DOUBLE);
       d=1;
       delay(100);
     }
     if (buttons & BUTTON_SELECT){ //moves to next stage
       input_stage++;
       delay(250);
       lcd.clear();
       myStepper->step((step_percent*slide_max), BACKWARD, DOUBLE); //sets platform back to home position
       d=1;
       myStepper->release(); 
     }
     if (buttons & BUTTON_LEFT){
       input_stage--; //moves to previous stage
       delay(250);
       d=1;
     }
   }
   if(input_stage == 4){
     uint8_t buttons = lcd.readButtons();
     if(d==1){
       lcd.clear();
       lcd.print("Pan start-fin");//ask for min pan
       lcd.setCursor(0, 1);
       lcd.print("S: ");
       lcd.print(pan_min);
       lcd.print("  F: ");
       lcd.print(pan_max);
       lcd.setCursor(3,1);
       d=0;
     }
     if (buttons & BUTTON_UP) {
       pan_min = pan_min + 10;  //sets displays pan parameters
       pan.writeMicroseconds(pan_min);
       d=1;
       delay(10);
     }
     if (buttons & BUTTON_DOWN) {
       pan_min = pan_min - 10;
       d=1;
       delay(10);
       pan.writeMicroseconds(pan_min);
     }
     if (buttons & BUTTON_SELECT){
       input_stage++;
       delay(50);      
       lcd.clear();
       pan_max=pan_min; //sets max to min to not cause a brownout
       d=1;
     }
     if (buttons & BUTTON_LEFT){
       input_stage--;
       delay(50);
       d=1;
     }
   }
   if(input_stage == 5){
     uint8_t buttons = lcd.readButtons();
     if(d==1){
       lcd.clear();
       lcd.print("Pan start-fin");//ask for max pan
       lcd.setCursor(0, 1);
       lcd.print("S: ");
       lcd.print(pan_min);
       lcd.print("  F: ");
       lcd.print(pan_max);
       lcd.setCursor(9,1);
       d=0;
     }
     if (buttons & BUTTON_UP) {
       pan_max = pan_max + 10;
       d=1;
       delay(10);
       pan.writeMicroseconds(pan_max);
     }
     if (buttons & BUTTON_DOWN) {
       pan_max = pan_max - 10;
       pan.writeMicroseconds(pan_max);
       d=1;
       delay(10);
     }
     if (buttons & BUTTON_SELECT){
       input_stage++;
       delay(250);
       lcd.clear();
       d=1;
     }
     if (buttons & BUTTON_LEFT){
       input_stage--;
       delay(250);
       d=1;
     }
   }
   if(input_stage == 6){
     uint8_t buttons = lcd.readButtons();
     if(d==1){
       lcd.clear();
       lcd.print("tilt start-fin");//ask for min tilt
       lcd.setCursor(0, 1);
       lcd.print("S: ");
       lcd.print(tilt_min);
       lcd.print("  F: ");
       lcd.print(tilt_max);
       lcd.setCursor(3,1);
       d=0;
     }
     if (buttons & BUTTON_UP) {
       tilt_min = tilt_min + 10;
       d=1;
       delay(10);
       tilt.writeMicroseconds(tilt_min);
     }
     if (buttons & BUTTON_DOWN) {
       tilt_min = tilt_min - 10;
       tilt.writeMicroseconds(tilt_min);
       d=1;
       delay(10);
     }
     if (buttons & BUTTON_SELECT){
       input_stage++;
       delay(250);
       tilt_max=tilt_min;
       lcd.clear();
       d=1;
     }
     if (buttons & BUTTON_LEFT){
       input_stage--;
       delay(250);
       d=1;
     }
   }
   if(input_stage == 7){
     uint8_t buttons = lcd.readButtons();
     if(d==1){
       lcd.print("tilt start-fin");//ask for max tilt
       lcd.setCursor(0, 1);
       lcd.print("S: ");
       lcd.print(tilt_min);
       lcd.print("  F: ");
       lcd.print(tilt_max);
       lcd.setCursor(9,1);
       d=0;
     }
     if (buttons & BUTTON_UP) {
       tilt_max = tilt_max + 10;
       tilt.writeMicroseconds(tilt_max);
       d=1;
       delay(10);
     }
     if (buttons & BUTTON_DOWN) {
       tilt_max = tilt_max - 10;
       delay(10);      
       tilt.writeMicroseconds(tilt_max);
       d=1;
      }
      if (buttons & BUTTON_SELECT){
        input_stage++;delay(250);
      }
      if (buttons & BUTTON_LEFT){
        input_stage--;delay(250);
      }
    }
    if(input_stage == 8){   //confirm parameters
      lcd.noBlink();
      uint8_t buttons = lcd.readButtons();
      lcd.clear();
      lcd.print("SL: ");
      lcd.print(slide_min);
      lcd.print(" - ");
      lcd.print(slide_max);
      lcd.setCursor(0,1);
      lcd.print("PN: ");
      lcd.print(pan_min);
      lcd.print(" - ");
      lcd.print(pan_max);
      delay(2500);
      lcd.clear();
      lcd.print("TI: ");
      lcd.print(tilt_min);
      lcd.print(" - ");
      lcd.print(tilt_max);
      lcd.setCursor(0,1);
      lcd.print("Dur: ");
      lcd.print(total_hour);
      lcd.print(":");
      lcd.print(total_minute);
      delay(2500);
      lcd.clear();
      lcd.print("Left for back");
      lcd.setCursor(0,1);
      lcd.print("Select to go");
      delay(2500);
      if (buttons & BUTTON_SELECT){
        x = 3; //if user is happy with set parametres - continue to run move program
      }
      if (buttons & BUTTON_LEFT){
        input_stage--;delay(50); // if user made a mistake they can press left to go back
      }
    }

break;

    case 3:

    //calculate moving time durations
    total_time = total_hour*60;
    total_time = total_time + total_minute;
    total_time = total_time*60000;
    total_slide = slide_max - slide_min;
    step_duration = total_time/(total_slide*step_percent);
    total_pan = pan_max - pan_min;
    total_tilt = tilt_max - tilt_min;
    pan_duration = total_time/total_pan;
    tilt_duration = total_time/total_tilt;

    //display values for debuging
    lcd.clear();
    lcd.print("total time");
    lcd.setCursor(0,1);
    lcd.print(total_time);
    delay(5000);    
    lcd.clear();
    lcd.print("total slide");
    lcd.setCursor(0,1);
    lcd.print(total_slide);
    delay(5000);    
    lcd.clear();
    lcd.print("step duration");
    lcd.setCursor(0,1);
    lcd.print(step_duration);
    delay(5000);    
    lcd.clear();
    lcd.print("total pan");
    lcd.setCursor(0,1);
    lcd.print(total_pan);
    delay(5000);    
    lcd.clear();
    lcd.print("total tilt");
    lcd.setCursor(0,1);
    lcd.print(total_tilt);
    delay(5000);  
    lcd.clear();
    lcd.print("pan duration");
    lcd.setCursor(0,1);
    lcd.print(pan_duration);
    delay(5000);    
    lcd.clear();
    lcd.print("tilt duration");
    lcd.setCursor(0,1);
    lcd.print(tilt_duration);
    delay(5000); 
    step_millis = millis();
    pan_millis = millis();
    tilt_millis = millis();
    pan_pos = pan_min;
    pan.write(pan_pos);
    tilt_pos = tilt_min;
    tilt.write(tilt_min);


    //sets pedestal to user input slide min position
    myStepper->step((step_percent*slide_min), FORWARD, DOUBLE);
    x = 4;
    start_time = millis();
    end_time = millis() + total_time;

break;

    case 4:
    long remaining = end_time - millis(); //make a couple of run time calculations
    run_dur = millis() - start_time;

    if(millis() - step_millis > step_duration){ //take one step after step duration
      myStepper->step(1, FORWARD, SINGLE);
      cur_step++;
      step_millis = millis();  //resets step duration
      myStepper->release(); 
    }
    if(millis() - pan_millis > pan_duration){ //same as slide
      pan_pos++;
      pan.writeMicroseconds(pan_pos);
      pan_millis = millis();
    }
    if(millis() - tilt_millis > tilt_duration){//same as slide
      tilt_pos++;
      tilt.writeMicroseconds(tilt_pos);
      tilt_millis = millis();
    }
   if(run_dur > total_time){   //resets to top of user input once total duration runs out
     x = 0;
     input_stage = 0;
     myStepper->step(cur_step, BACKWARD, DOUBLE); //sets motor back to home position
     myStepper->release(); //release motor
    }
  }
}
1
  • 1
    The thread says the underlying implementation of millis is to blame, not the actual use of the millis function. Even if you never call millis, the interrupt, that is used to count the milliseconds in the background, is still running.
    – Gerben
    Feb 8 '15 at 12:14
1

You're calling millis() a lot in case 4. A very simple improvement would be to call it once at the start of loop(), storing the result in a variable. Throughout the rest of the function, simply use the value stored in that variable instead of calling millis() directly.

I doubt it will solve the problem entirely, but hopefully it will improve it a little.

1
  • 1
    It will also eliminate the probable bug of times not matching because millis() has rolled over during the execution. Feb 9 '15 at 7:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy