Making a joystick control for two servos to hold position

Hi All

I am new to Arduino Programming and I want to build a simple pan tilt camera system with use of a simple playstation like joystick. So far I have managed to build the system using two servos, each for pan and tilt arrangement. I have written the code using the example code "knob" and the system works fine.
But, the problem is the servos come back to the start position with the joystick. For example, the way I wanted it to work is if I move the joystick to a certain position the servo should move to some angle and stays there even if the joystick comes to rest via the spring action it has. It should move again if I move to joystick.
Currently it just comes back with the joystick.
Could anyone help me with this situation. I spent so many days figuring out how to do it. even found one video in which the guy does the way I want but unfortunately it is just a video but no information on how to achieve it.

I want the Control 2 as shown in the video.

Need a push button to signify when the hold position is reached.
Push again to tell the system you want to 'unlock' and move to a new positon.

Alternatively, you could design your sketch so that joystick movements away from center move the servos in the corresponding direction, and movements back towards center are ignored.

the link to the video I have mentioned in my post does deploy some kind of push button arrangement. But he used the push button as a toggle mode to run the arrangement in different control.
In Control 1 the system runs the way my system is running.
In Control 2 he presses the button the and LED goes of. Now when he PAN/TILTS the servos with the joystick , they hold the previous position until they are again triggered with the joystick.

Hi msdhillon

Can you post your code? Use the code tags ('#' button above the row of smileys when you post) so that it is easier for us to read.

Also please give some details of how you have interfaced the joystick to the Arduino.

EDIT And can you confirm if you want both Control 1 mode and Control 2 mode from the video, or just Control 2 mode?

From the video, it looks as if the speed of pan and tilt is proportional to how far the joystick is moved from centre position.



There was a long Thread a while back started by a guy building a model excavator and he wanted to use joysticks that would return to centre without bringing the servos back with them. I can't immediately find the Thread now.

I wrote this suggestive code for the Thread. It may give you some ideas. Basically if the joystick moves beyond a certain point it causes the motor to move a short extra distance in that direction.

#include <Servo.h>

#define mainArm 0
#define jib 1
#define bucket 2
#define slew 3

Servo servo[4];

byte angle[4] = {90, 90, 90, 90};

byte potPin[4] = {A0, A1, A2, A3};
byte servoPin[4] = {12, 11, 10, 9};

void setup() {

  Serial.println("Starting DiggerCode.ino");

  for (byte n = 0; n < 4; n++) {

void loop() {

void readPotentiometers() {
  int potVal;
  for (byte n = 0; n < 4; n++) {
    potVal = analogRead(potPin[n]);
    if (potVal < 450) {
      angle[n] += 1;
      if (angle[n] > 170) {
        angle[n] = 170;
    if (potVal > 570) {
      angle[n] -= 1;
      if (angle[n] < 10) {
        angle[n] = 10;


void moveServos() {
  for (byte n = 0; n < 4; n++) {


I don't think you want to be sending a command to the servo directly. You should be writing to a variable called "currentCMD"
and when the servo is where you want it to stay, you need to push a button or somehow tell the system to stop moving the servo.
It doesn't know where you want it to stay, It is simply tracking your joystick movement. How could it possibly know that it should stop moving at some point unless you tell it by pushing a button. When you push the "savePOS" button the code stops updating the servo from the variable because the "savePos" button clears the upDATE flag telling the program to stop reading the currentCMD varaiable and sending the commands to the servo. With the upDATE flag , cleared, the loop that normally reads the currentCMD variable gets to the line where it says if (upDATE == true) => read currentCMD ==> send command to servo, and because the upDATE flag is false, it exits the loop and that's it until you press toggle the savePOS button which sets the upDATE flag and the servo will start tracking the joystick again.

#include <Servo.h>

int joy1 = A0;          // joystick x axis
int joy2 = A1;         // joystick y axis

int servoH = 7;     // servo 1
int servoV = 6;     // servo 2

int value1 = 90;     // middle point of servo1 @ 90 degree
int value2 = 90;     // middle point of servo 2 @ 90degree

Servo servo1;         // defining servo objects
Servo servo2;

int jsvalue1;             // joystick value
int jsvalue2;

int val1;              // another variable
int val2;

void setup() {


void loop() {
  jsvalue1 = analogRead(joy1);           // to read joystick value 

  if (jsvalue1 > 520 || jsvalue1 < 500)          // the joystick rests at 515 when in rest position. I made a range out of which the value  will be considered.)
    val1 = map(jsvalue1, 0, 1023, 0, 180);        // mapping the value to val1 variable.
    value1 = value1 + val1;                                     // adding the mapped value to 90 degree
    if (value1 < 180)                                                //  if the mapped value + value 1 exceeds 180 for the servo it is neglected.
    servo1.write(value1);                                     // write the under 180 degree value to servo 1

// same code for the second servo. but i have not written it here.

that's so far I have managed, it should work but it does not at least according to me. :([/code]

I just want the control 2 as shown in the video. I have been searching internet for the last 3 days but nothing so far.

Hi there

    val1 = map(jsvalue1, 0, 1023, 0, 180);        // mapping the value to val1 variable.
    value1 = value1 + val1;                                     // adding the mapped value to 90 degree

Each time round the loop (if the joystick is outside the central "dead zone") you are adding 0 .. 180 degrees to the previous position. So I guess the servo rapidly hits the end stop.

For "Control 2" mode, you need to add a small positive or negative number to the previous servo position each time you loop. A refinement is to add a different number depending how far you push the joystick from centre position. You could start experimenting by changing the map parameters to map to a small positive / negative range, something like:

val1 = map(jsvalue1, 0, 1023, -5, +5);

Then, look at the BlinkWithoutDelay example sketch to understand how to test the joystick position at regular intervals and update the servo position accordingly (rather than using delay()).

And it would be good to use clearer names for your variables. I'm guessing that "value1" may have started life as a constant definition, judging by the comment ...

int value1 = 90;     // middle point of servo1 @ 90 degree

Now you are using it, I think, to hold the last servo position. If you still need the mid point, declare something like:

const int servo01MidPoint = 90;

Have a different variable for last position, something like:

int servo01LastPosition = servo01MidPoint;



Not sure if this will help find other resources, but the "Control 2" mode is like a jog shuttle control that is found on some audio and video equipment.

As far as I know the code I posted earlier does exactly what you want. Have you tried it?

(It won't care if you only have 2 servos connected)



Hi there
Yes, I tried the code. The servo moves only in one direction towards from 515 to 1023 of the joystick value and it comes back with the joystick. It does not move at all to the other direction i.e. from 515 to 0.

i pasted the code as it is except changed the input values for the servos. Does not work. :frowning:

What do you mean by "changed the input values for the servos" ?

How are your joysticks and servos connected when using my code?

I will check my code later to make sure it still works.


I just changed the input pin number to the ones I have servos connected to in your code.

Instead of byte servoPin[4] = {12, 11, 10, 9};

I put byte servoPin[4] = {7, 6, 10, 9};

That shouldn't make any difference.

What pin is the Joystick wiper connected to - indeed what pins are all the joystick connection on?

I just tested my code. It works fine. When the pot is in the centre nothing happens - turn it one way and the servo starts moving. Turn it back to centre and the servo stays at its last position. Turn it the other way and the servo reverses.


I have x axis of axis connected to A0, y axis of joystick connected to A1, servo 1 connected to pin 7, servo 2 connected to pin 6.

I will try it again.

It Works !!!
It Works!!!

I just changed the dead zone values from 200 to 550. Now it works.

Apparently the middle value of the joystick on the x axis is around 214 while on the y axis is around 515 which is wierd. It should both be around 515. So when I changed the lower limit to 200 and upper limit to 550 it started working.

Thanks very much. Now I will try to understand what is happening in the code and learn something from it. :slight_smile:

Glad to hear it.


Would you mind posting the revised code for others to benefit from ?