Proof of concept: servo speed and rotation

Hi again!

As I was kindly invited to Porvoo to speak at the Point College Internet of Things day, I thought I’d finally formalize a concept I have been thinking about for a while now: servo rotation direction and speed controlled by a potentiometer.

This little combo is not much on its own of course, but as it happens, it can be used for a multitude of things. To get us started with servos and potentiometers, see this two axis camera stand:

This is an older proof of concept in which I use two 180° servos with two potentiometers. Tilting things is a nice application for these semicircular movement servos, but for moving things from one place to another, we need full rotation or 360° servos.

As always I suggest that when you start learning how to use a new tool or device, it’s a good idea to split the project into smaller units. If the main idea is to use a potentiometer to run a servo in two directions at selected speeds, it can be seen as a sum of three smaller things:

  1. How to read values from the potentiometer
  2. How to rotate the servo both ways
  3. How to use the values from the potentiometer to govern direction and speed of the servo

The parts you need are cheap indeed. An Arduino clone sets you back some 5-8 euros, a potentiometer is a couple of euros, and the servo costs maybe 6 euros. Some wires and soldering tools are useful too.

The potentiometer

Arduino and potentiometer

Arduino and potentiometer

This device is merely a resistor with adjustable resistance. It has three pins, voltage in, resistance value, and ground. To see the values it is sending, you can use the Serial Monitor feature in Arduino. This nifty device will show on your computer screen what the potentiometer is sending.

The wiring is as seen on the picture. Pin 1 is Voltage in, so it is stuck in the +5V pin on the Arduino. Pin 2 is the value to be read from the potentiometer, and it can be stuck in any of the six analog ports on the Arduino – Arduino is then programmatically told which pin to read. And the third is the ground, and it can be stuck in one of the three ground pins of the board.

The code is as follows:

int sensorValue;

void setup() {
 Serial.begin(9600);
 pinMode(A0, INPUT);
}

void loop() {
 sensorValue = analogRead(A0);
 Serial.println(sensorValue);
 delay(100);
}

This is a good example of a very simple Arduino program. At the top, a single variable is declared, namely sensorValue. It holds the value read from the potentiometer.

In the setup block we open the connection into the serial monitor for display purposes. Pin A0 is declared as an input pin, and as we stuck the lead from the pot into this pin, it is now available for the Arduino.

The loop block reads the value using analogRead() and stores it in the sensorValue variable. It then waits for the 100 milliseconds and reads again. This gives you ten measurements per second.

When you run this code, Arduino will display the value on the screen as a running set of numbers. You will see that at one end of the potentiometer, the value is 0, and at the other end, 1023. Make note of these values, they will be needed later.

The servo

Arduino and servoThe 360 degree servo is governed by a control pulse. If the length of the pulse is 1200 milliseconds, the servo will run clockwise at full steam. If it is 1800, it will run counterclockwise, at an equally maniacal pace.

Theoretically, if the control pulse is 1500ms, it will stop the servo, but this is subject to individual servo settings. Luckily, with this program, you can easily find out what is the stop value for your servo. Mine stops at 1485ms, incidentally.

Connections are equally easy for this part of the project. Connect the brown wire of the servo to an available ground pin, the red into the 5V pin, and the yellow control wire to a digital pin. I will use 2 for this. The servo can be run off the Arduino if it is the only device connected, but when we add the resistor, the servo will need to be powered from a power source.

The code to use is as follows:

#include <Servo.h>          //use a library for servo control

Servo myTransportServo;     //declare a servo object
int speed = 1200;           //set the starting speed value
int step = 25;              //set the loop stepping value   

void setup() {
 myTransportServo.attach(2);//connect servo to digital pin 2
 Serial.begin(9600);        //open the monitor connection
}

void loop() {
 rollit(speed);             //go to function rollit
 delay(10);                 //wait a little
 if (speed > 1800){         //adjust the step as needed
 step = -25;
 }
 if (speed < 1200){
 step = +25;
 }
 Serial.print("Speed: ");   //print the current speed
 Serial.println(speed);
 speed = speed + step;      //adjust the speed with step
}

void rollit (int rollspeed){ //run the servo at the speed
 myTransportServo.writeMicroseconds(rollspeed);
 delay (500);
}

So this code loops between the full speed rotations in both directions, stopping in the center. If you want to find out the null value for your servo, use 1450 instead of 1200, 1550 instead of 1800, and a step of 1. Then note the value in the serial monitor when the servo stops.

The whole shebang

Arduino and potentiometer and servo

Arduino and potentiometer and servo

This last mile merely connects the two previous parts and merges the code. As I said, you have to supply the power for the servo separately now, because the servo and the resistor will drain Arduino’s power supply. For this purpose I have printed a little box that houses a 9V battery and has both a 2.5mm plug and two pins. It is necessary to have a common ground for Arduino and any devices connected to it, so using this setup is handy in that sense too.

The connections now are the same as for the part 1 on the potentiometer, but the servo has its power pins plugged to the power source. The servo control pin is again #2.

The code is as follows now:

#include <Servo.h>
#include <Math.h>
Servo myServo;

int sensorValue;
float control;

void setup() {
 Serial.begin(9600);
 pinMode(A0, INPUT);
 digitalWrite(A0, HIGH);
 myServo.attach(2);
}

void loop() {

sensorValue = analogRead(A0);
 delay(10);
 control = map(sensorValue, 14, 1023, 1200, 1800);
 Serial.print(sensorValue);
 Serial.print(" - ");
 Serial.print(control);
 Serial.println();
 myServo.writeMicroseconds(control); //1505
 delay(10); 
}

The new feature of this last program is the introduction of the map function. It takes five parameters: input value, value in low, value in high, value out low, value out high. To visualise this, if you had

control = map(5, 1, 10, 100, 1000),

the value of variable control would be 500.

And now, the control value is mapped from 14-1023 to 1200-1800. The servo will then rotate at full speed one way first, slow down as you move the lever on the pot, then go full speed the other way.

And now you will ask, what is the fun in this? Nothing. It is a proof of concept, void of usability as such. But I can think of three applications for it straight off the box:

  1. a camera dolly, using a worm screw and a nut attached to it
  2. a game of labyrinth, but vertical, two servos moving a horizontal bar supporting the ball
  3. any application where you have to have rotation converted into a two way movement.

And this is by far the most interesting part of using Arduinos – coming up with as many proofs of concept you can think of and assembling a library of them for the day the real need arises.

See it in action here, and stay tuned for the dolly, coming up soon.

6 Comments:

  1. Ziyad Yassar

    Hello sir, i want to ask. How to use buttons, and the speed is constant? I want to connect it to the camera so it takes a very low speed so that the camera catch is not bad

    • Heikki Hietala

      Hi,

      I wonder if I understood you correctly. You want to use the rotating servo to press the trigger on the camera? I think you are better off changing the camera operating system. If it is a Canon, use Canon Hack Development Kit, and there is a similar service for Nikon cameras. See my five part blog on that http://www.sabulo.com/sb/category/8mm-film/

      • Ziyad Yassar

        No sir, i use the servo to rotate the camera only, so i have a car remot project that uses the camera ip to see the circumstances around. I use a continuous servo to move the camera ip to see all sides of the room. I plan to use apps created through mit app inventor to drive the wheel and servo. how I control the servo using 3 buttons are the left button, the stop button and the right button, when the left button is pressed then the servo runs to the left as soon as the right button presses then the servo moves to the right and if the stop is stopped then the servo will stop. whether the above program can be changed to be like that?
        Before thanking me for replying my comment

        • Heikki Hietala

          Okay, if I understand you correctly, you have a 360 degree servo, and a camera mounted on it. You want to be able to rotate camera around clockwise, and counterclockwise. You want to be able to stop camera at any point.

          For this I would use a three position switch, which would have your servo run in either direction, or, in the center, stop altogether.

          The servos I use have a pulse length control. If it is 1485, the servo is stopped. If it is less, it runs counterclockwise, if more than that, clockwise.

          The code is very simple, but please note: I have not an Arduino at hand now, so I cannot test if it works.

          The switch is grounded from the middle pin, and the two others are led to any digital pin, say 3 and 4. The code is then:

          #include <Servo.h> // Include servo library
          Servo myServo; // attach servo
          int countercwPin = 3; // declare counterclockwise pin
          int cwPin = 4; // declare clockwise pin

          void setup() {
          Serial.begin(9600); //start serial monitor
          pinMode (countercwPin, INPUT); //define CCW pin as input
          pinMode(cwPin, INPUT); //Define CW pin as input too
          digitalWrite(countercwPin, HIGH); // make sure it is grounded
          digitalWrite(cwPin, HIGH); // make sure it is grounded
          myServo.attach(2); //attach your servo data to pin 2
          }

          void loop {
          if (HIGH == countercwPin) { //if the switch is in the counterclockwise position…
          myServo.writeMicroseconds(1200); //run servo CCW at a speed
          } else if (HIGH = ccwPin) { //if the switch is in the clockwise position…
          myServo.writeMicroseconds(1800); //run servo CCW at a speed
          }
          else {
          myServo.writeMicroseconds(1485); //if switch is in the middle, don’t run the servo
          }

          So, if the switch is to the one side, it will run at a set speed counterclockwise, run at a set speed clockwise at the other end, and stop with the switch in the middle. You can adjust the speed by editing the value of the writeMicroseconds. Your servo may have a different null value, you may need to experiment a little to find its stop value.

          Good luck!

          • Ziyad Yassar

            Okay sir, i will try to follow your command. thank you for helping me solve my problem. hopefully i can finish it

  2. Heikki Hietala

    No problem, let me know if it works, or if I can help you further.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.