Last Updated: 20/04/2024

#82 Servo Speed Control with millis()

Components >> #82 Servo Speed Control with millis()

Servo speed control using millis()

I often see beginners struggling to combine servos with other code because the normal servo examples us delay() and so block any other code while running.

I usually use the PCA9685 board for servo control, however for this tutorial I will use the Servo library and showe how it is possible to run multiple servos at different speeds and directions at the same time.

Servo Circuit


If you are just using a single servo you can use the Arduino 5v Supply. However the Arduino will struggle to power more than a single servo so a seperate 5v supply is required as shown below.

For the example code I used pins 8, 9 and 10.

Although the examples are based on an Arduino UNO, a Nano or Mega 2560 will also work without any modifications to the code.

DCC Decoder Circuit

 

Example 1: millisServoV1.ino


Click to Download code: millisServoV1.ino

This sketch controls a single servo, passing it random positions to move to at random speeds.

 

 
/* millisServoV1
   20/04/2024


*/
#include 

Servo servo1;  // create servo object to control a servo
//This will store the data for servo1
unsigned int servo1Data[3];//moveTo, currentPos, speed
unsigned long servo1millis;




unsigned long currentMillis;//Holds the current board time in milliseconds

void setup() {
  Serial.begin(9600);
  Serial.println("millisServoV1");
  servo1.attach(8);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  int servoFinished;
  currentMillis = millis();

  servoFinished = servo1Control();//controls servo 1
  if(servoFinished < 1){//If 0 is returned the servo has reached it's destination
    servo1Data[0] = random(179); //pick a random angle between 0 - 179
    servo1Data[2] = random(1,100); // pick a random speed between 1 and 100...speed in milliseconds per degree moved
    Serial.print("Servo 1 Next Pos: ");
    Serial.print(servo1Data[0]);
    Serial.print(" Servo 1 Next Speed: ");
    Serial.println(servo1Data[2]);
  }

}

int servo1Control(){
  int returnPos;
  returnPos = 0;//return 0 if reached destination
  if(servo1Data[0] > 179){
    servo1Data[0] = 179;//limit check in case soeone tried to move servo more than 179 degrees  
  }
  if(servo1Data[0] != servo1Data[1]){//is there still a distance to move
    if(currentMillis - servo1millis >= servo1Data[2]){//is it time to move
      servo1millis = currentMillis;
      if(servo1Data[0] > servo1Data[1]){
       servo1Data[1]++;
      }else{
       servo1Data[1]--;
      }
      servo1.write(servo1Data[1]);
    }
    returnPos = 1;//return 1 if still moving
  }
  return returnPos;
}

 

Example 2: millisServoV2.ino


Click to Download code: millisServoV2.ino

This sketch expands example 1 to 3 servos. Each is moving independently of the others, all at different speeds and directions.

 

 
/* millisServoV2
   20/04/2024

   This version is controlling 2 servo on independent timings


*/
#include 

Servo servo1;  // create servo object to control a servo
//This will store the data for servo1
unsigned int servo1Data[3];//moveTo, currentPos, speed
unsigned long servo1millis;

Servo servo2;  // create servo object to control a servo
//This will store the data for servo1
unsigned int servo2Data[3];//moveTo, currentPos, speed
unsigned long servo2millis;

Servo servo3;  // create servo object to control a servo
//This will store the data for servo1
unsigned int servo3Data[3];//moveTo, currentPos, speed
unsigned long servo3millis;




unsigned long currentMillis;//Holds the current board time in milliseconds

void setup() {
  Serial.begin(9600);
  Serial.println("millisServoV1");
  servo1.attach(8);  // attaches the servo on pin 8 to the servo object
  servo2.attach(9);  // attaches the servo on pin 9 to the servo object
  servo3.attach(10);  // attaches the servo on pin 10 to the servo object
}

void loop() {
  int servoFinished;
  currentMillis = millis();

  servoFinished = servo1Control();//controls servo 1
  if(servoFinished < 1){//If 0 is returned the servo has reached it's destination
    servo1Data[0] = random(179); //pick a random angle between 0 - 179
    servo1Data[2] = random(1,100); // pick a random speed between 1 and 100...speed in milliseconds per degree moved
    Serial.print("Servo 1 Next Pos: ");
    Serial.print(servo1Data[0]);
    Serial.print(" Servo 1 Next Speed: ");
    Serial.println(servo1Data[2]);
  }

  servoFinished = servo2Control();//controls servo 2
  if(servoFinished < 1){//If 0 is returned the servo has reached it's destination
    
    if(servo2Data[0] > 0){
      servo2Data[0] = 0;
    }else{
      servo2Data[0] = 179;
    }
    servo2Data[2] = 30; // speed
    Serial.print("Servo 2 Next Pos: ");
    Serial.print(servo2Data[0]);
    Serial.print(" Servo 2 Next Speed: ");
    Serial.println(servo2Data[2]);
  }

  servoFinished = servo3Control();//controls servo 3
  if(servoFinished < 1){//If 0 is returned the servo has reached it's destination
    
    if(servo3Data[0] > 0){
      servo3Data[0] = 0;
    }else{
      servo3Data[0] = 100;
    }
    servo3Data[2] = 10; // speed
    Serial.print("Servo 3 Next Pos: ");
    Serial.print(servo3Data[0]);
    Serial.print(" Servo 3 Next Speed: ");
    Serial.println(servo3Data[2]);
  }

  

}

int servo1Control(){
  int returnPos;
  returnPos = 0;//return 0 if reached destination
  if(servo1Data[0] > 179){
    servo1Data[0] = 179;//limit check in case soeone tried to move servo more than 179 degrees  
  }
  if(servo1Data[0] != servo1Data[1]){//is there still a distance to move
    if(currentMillis - servo1millis >= servo1Data[2]){//is it time to move
      servo1millis = currentMillis;
      if(servo1Data[0] > servo1Data[1]){
       servo1Data[1]++;
      }else{
       servo1Data[1]--;
      }
      servo1.write(servo1Data[1]);
      
    }
    returnPos = 1;//return 1 if still moving
  }
  return returnPos;
}

int servo2Control(){
  int returnPos;
  returnPos = 0;//return 0 if reached destination
  if(servo2Data[0] > 179){
    servo2Data[0] = 179;//limit check in case soeone tried to move servo more than 179 degrees  
  }
  if(servo2Data[0] != servo2Data[1]){//is there still a distance to move
    if(currentMillis - servo2millis >= servo2Data[2]){//is it time to move
      servo2millis = currentMillis;
      if(servo2Data[0] > servo2Data[1]){
       servo2Data[1]++;
      }else{
       servo2Data[1]--;
      }
      servo2.write(servo2Data[1]);
      
    }
    returnPos = 1;//return 1 if still moving
  }
  return returnPos;
}

int servo3Control(){
  int returnPos;
  returnPos = 0;//return 0 if reached destination
  if(servo3Data[0] > 179){
    servo3Data[0] = 179;//limit check in case soeone tried to move servo more than 179 degrees  
  }
  if(servo3Data[0] != servo3Data[1]){//is there still a distance to move
    if(currentMillis - servo3millis >= servo2Data[2]){//is it time to move
      servo3millis = currentMillis;
      if(servo3Data[0] > servo3Data[1]){
       servo3Data[1]++;
      }else{
       servo3Data[1]--;
      }
      servo3.write(servo3Data[1]);
    }
    returnPos = 1;//return 1 if still moving
  }
  return returnPos;
}


 

Additional Resource Links

Lesson 11: Arrays 28/08/2021

State Machine Examples 08/03/2023

Comments


To ask a question please comment on YouTube or email the address in this image: and use #82 Servo Speed Control with millis() as a reference.