HOME - - - - - - - - Table of contents, my Arduino "How To" articles
Other material for programmers     

Using Servos with Arduinos

In general, and in an ESP8266 environment

filename: aht3servo.htm

Before we get too far into this... is it a servo "motor" that you want for your job, I hope? I offer a more general discussion of things to turn electricity into movement, in case you are in any doubt. As is explained more fully there, a servo, at least as I am using the term here, is a device with an arm that rotates on a shaft... like a robust "hand" on a clock. It can more "forward" or "backward", often through most of 360 degrees. Note that I am not aware of any servos that can go "round and round".. all of the servos I am aware of are limited to only part of a full circle's rotation.

The input to the device is a single wire. You put a stream of ons and offs into that wire. (A pulse train If you have short ons, with long offs, the "hand" is rotated to one position. If you have a different duty cycle (ratio of the on time to the off time), the "hand" goes to a different position.

So! Pretty simple! And that, happily, means that using them is also pretty simple... especially as Arduinos can be told to send a pulse train without the need for every detail to be managed by your code.

The "big secret", such as it is, is that you are not free to put servos on whatever pin you wish to. Only some have the capacity of delivering a pulse train for you.

"Ordinary" Arduinos...

To "crawl" before we "walk", here's the core of the code we'll come to in a moment. The following is the heart of just moving one servo's arm to a position. (Change the "85", and the code would move the arm to a different position.)

The #Include <Servo.h> allows the compiler to draw onm material in the standard "Servo" library. It takes care of tedious details for us, and is an "everyday" library... nothing you need to worry about.

#include <Servo.h>
Servo dog; // "Dog" being the "name" of the servo

**const uint8_t servoMax = 1; // Change to suit the number of servos used (max 6)
**uint8_t oldPos[servoMax];
**uint8_t newPos[servoMax];

// **********************************************************************
void setup() {
  //Configure the Arduino to "drive" the servo via pin 9...
  dog.attach(9); // Available pins for the Uno are 3,5,6,9,10,11 (PWM pins)
}

// **********************************************************************
void loop() {
dog.write(85);
}

I've put the "write" in the loop() part of the program in the "cut-down" version, but once that had been executed once, you wouldn't see anything new happen thereafter.

=============
Here's a program that a reader kindly sent for everyone's benefit. It goes a bit beyond the basic basics... It illustrates how you would drive three servos from an Arduino! But the code is nice and clear, and I hope you can take useful things from it. More importantly, it gives you an elegant way to control how quickly the arm moves from one position to another. To "exercise" the servos, author of the program added three potentiometers, which are only there to give the user an easy way to say "Now I want (that) servo to change the direction it's arm points to (this new direction).

The "timing" issues discussed in the comments within the full code are NOT about what the duty cycle will be. The (standard, widely used) "Servo" library takes care of that nuisance.

And... not least... he's used the millis() function in a clever way to frequently re-check the position of the pots, so that the signal to the servos can be changed if necessary... but in a tidy, un-wasteful, non blocking way.!

Lastly: If you haven't met "map" before, it is worth getting to grips with... a generally useful word, nothing connects it directly to servos... it was just "the way to go" here, for converting a reading from the pot to a range of values suitable for the servo.

/*
  Using servo motors at various speeds without delay
  Every 'interval' milliSeconds, we check to see if the servo needs moving
  We then call the relevent subroutine to move the servo 1 degree
  in the correct direction.
  This repeats every 'interval' until we reach the new position
*/

#include <Servo.h>
Servo dog; // Name these as preferred
Servo cat;
Servo mouse;

long previousMillis = 0;
long ramp = 25; // Sets the speed of the servos
                // (good values are 5 [fast] to 50mS [very slow])

const uint8_t servoMax = 3; // Change to suit the number of servos used (max 6)
uint8_t oldPos[servoMax];
uint8_t newPos[servoMax];

// **********************************************************************
void setup() {
  dog.attach(9); // Available pins for the Uno are 3,5,6,9,10,11 (PWM pins)
  cat.attach(10);
  mouse.attach(11);
}

// **********************************************************************
void loop() {
  /*
     Example using pots to position the servos
     The newPos variable can be set by any other means
     Connect the analog inputs to GND if not used
     This will prevent channel crosstalk.
  */
  newPos[0] = map(analogRead(1), 0, 1023, 0, 180);
  newPos[1] = map(analogRead(2), 0, 1023, 0, 180);
  newPos[2] = map(analogRead(3), 0, 1023, 0, 180);
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > ramp) {
    previousMillis = currentMillis;
    if (newPos[0] != oldPos[0]) servo0Move();
    if (newPos[1] != oldPos[1]) servo1Move();
    if (newPos[2] != oldPos[2]) servo2Move();
  }
}

// **********************************************************************
void servo0Move() {
  if (newPos[0] > oldPos[0]) {
    dog.write(oldPos[0] + 1);
    oldPos[0] ++;
  }
  if (newPos[0] < oldPos[0]) {
    dog.write(oldPos[0] - 1);
    oldPos[0] --;
  }
}

// **********************************************************************
void servo1Move() {
  if (newPos[1] > oldPos[1]) {
    cat.write(oldPos[1] + 1);
    oldPos[1] ++;
  }
  if (newPos[1] < oldPos[1]) {
    cat.write(oldPos[1] - 1);
    oldPos[1] --;
  }
}

// **********************************************************************
void servo2Move() {
  if (newPos[2] > oldPos[2]) {
    mouse.write(oldPos[2] + 1);
    oldPos[2] ++;
  }
  if (newPos[2] < oldPos[2]) {
    mouse.write(oldPos[2] - 1);
    oldPos[2] --;
  }
}

... and here are some data from a slightly modified version of the above...

(image of servo program timings)

To quote the person who did this for us... "I did some timing measurements to satisfy my curiosity. The repeat rate is set to 20mS. From the display above, we can see that the time taken in the servo-n-Move() routine is 52uS."

He was using a 16MHz Arduino Mega, and furtehr rremarks: "I have software timers set up like industrial PLC timers (actual, preset and control registers). I then check the status of the timers in the interrupt routine (checked at 52uS), and set a flag to take appropriate actions inside the loop routine."

And... "By the way, I think I may be wrong about the number of servos. I got that information from the net. I was reading the servo.cpp file and that says 12 servos. It seems you can attach any pin to it. More checking required. Also, do not try to use servo.write within an interrupt routine as the servo library also uses interrupts."

To save you looking it up, the gorgeous logic analyser costs over $250. But if you want to give me one, I won't complain. Remember: The program, AND the timings data came from a kind reader.



For the Sparkfun ESP8266 Thing Dev...

For the Sparkfun ESP8266 Thing Dev, I found that pins 2, 5 and 13 worked. Others may work, too... but I am pretty sure that the number that will is limited... the pin has to have PWM generation functionality. Pins that did not work for me: 4, 14, A0.

Here's some code I wrote... don't blame the author of the above for anything in this...

//ESP8266Thing-Servo-basic
//Written with Arduino IDE 1.8.1
//Put in a Sparkfun ESP8266 "Thing Dev" (WRL-13711)
//Started 16 Mar 19

#define sPrgm "ESP8266Thing-Servo-basic" //no ; here
#define sVers "16Mar19"

//MOSTLY "works"... just once in a while, especially when starting
//  up, the movement is hesitant. This may be due to running it on
//  3v3. I hope that's all it is!

//Successfully used "Micro Servo 9g / SG90" using the 3v3 from the ESP8266,
//  and 3v3 PWM signal.

//Thanks to ...
//https://circuits4you.com/2019/01/12/esp8266-servo-motor-control/
//.. for much of what is here.

#include <Servo.h>/(Ordinary one)

//"#define ServoPin 14   //D5 is GPIO14" << Didn't work, despite being pp
//https://circuits4you.com/2019/01/12/esp8266-servo-motor-control/
//#define ServoPin D5 //Wouldn't compile
//Also did not work: 14, A0,
//#define ServoPin 2 //Worked!
//Also worked: 5,13 //(5 has on-board LED on it.
//           13 needed for SPI if you want to use that.
#define ServoPin 2// no ; here

Servo MyServo;  // create servo object to control a servo

void setup() {
  delay(500);
  Serial.begin(19200);
  delay(200);
  Serial.println();
  Serial.println("Welcome to servo motor on Sparkfun ESP8266 Dev Thing demo.");
  Serial.println("Program name: ");
  Serial.print(sPrgm);
  Serial.print(", version: ");
  Serial.println(sVers);
  Serial.println();

  MyServo.attach(ServoPin); // attaches the servo
    delay(200);//without this, the servo sometimes
  //"stutters" a bit before it "gets going" with
  //what loop() tells it to do. Only briefly.
  //This only tested on 3v3 so far. Stutter may
  //disappear on 5v Vcc and data to servo.
}

void loop() {
  // put your main code here, to run repeatedly:
MyServo.write(10);   // tell servo to go to position
  delay(800);
MyServo.write(50);   // tell servo to go to position
  delay(800);
  }




   Search this site or the web        powered by FreeFind
 
  Site search Web search
Site Map    What's New    Search

The search engine is not intelligent. It merely seeks the words you specify. It will not do anything sensible with "What does the 'could not compile' error mean?" It will just return references to pages with "what", "does", "could", "not".... etc.
In addition to the tutorials for which this page serves as Table of Contents, I have other sites with material you might find useful.....

Sequenced set of tutorials on Arduino programming and electronics interfacing.
Tutorials about the free database supplied with Open Office/ Libre Office.

Some pages for programmers.
Using the parallel port of a Windows computer.


If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service.




Ad from page's editor: Yes.. I do enjoy compiling these things for you... hope they are helpful. However.. this doesn't pay my bills!!! If you find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!

Click here to visit editor's Sheepdog Software freeware, shareware pages.. Material on this page © TK Boyd 3/19


And if you liked that, or want different things, here are some more pages from the editor of these tutorials....

Click here to visit the homepage of my biggest site.

Click here to visit the homepage of Sheepdogsoftware.co.uk. Apologies if the "?FrmAht" I added to that link causes your browser problems. Please let me know, if so?

Click here to visit editor's pages about using computers in Sensing and Control, e.g. weather logging.



To email this page's editor, Tom Boyd.... Editor's email address. Suggestions welcomed!


Valid HTML 4.01 Transitional Page has been tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes.

AND passes... Valid CSS!


Why does this page cause a script to run? Because of the Google panels, and the code for the search button. Why do I mention the script? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....