phoenixgarage.org

 Robotics: How To Use An Analog Joystick With The Arduino
Posted on 2011-06-18 @ 02:19:35 by r00t

Analog joysticks are fairly easy to hook up and use with the Arduino. In this tutorial, I will describe the basics of hooking up such a joystick to the Arduino, and give some hints and tips on using the position values read from the potentiometers to control a basic vehicle using Ackermann Steering geometry, as well as to control a vehicle using Differential Steering geometry (like on a tank or bulldozer). Pictures and code provided!

What is an analog joystick?

Basically, an analog joystick is a couple of potentiometers hooked together mechanically in such a manner so that a small stick can control both at the same time:


The Analog Joystick
Questions or Comments?

Each potentiometer (one on the upper right quadrant - the Y-Axis, the other on the lower right quadrant - the X-Axis) is simply connected to an individual analog input on the Arduino. Notice the three pins on the X-Axis potentiometer? The center pin is routed to an analog input, while one of the side pins is connected to +5V, and the other side pin is connected to ground. The other potentiometer is connected in the same manner, just to a different analog input pin. See this link on how you connect potentiometers to the Arduino:

Arduino Potentiometer Tutorial

From here, you just need to write code to use the value read from the X-Axis analog input for one purpose (in the case of this tutorial, we'll use it for steering), and the value read from the Y-Axis analog input for another purpose (for this tutorial, throttle).

The code would check both of these analog values (which will range from 0-1023); when the stick is centered, each analog input will read approximately 511-513 (or maybe a little more on both ends or more on one side than the other - so if you saw 510-514 or 511-515, that would be OK) - this is due to the fact that these potentiometer joysticks aren't generally precision controls, so there will be an error percentage. Your code will have to take this into account, to decide on "center" (back in the days of analog joysticks on PCs, there would generally be a "joystick setup/calibrate" portion in games, where the computer would have you move your joystick around in various spots, to determine the center-point, as well as the extreme left/right/up/down positions - you could do something similar with your code, provided you provide some kind of feedback to the user). For the purposes of this tutorial, though, I'm going to ignore implementation of such a procedure; just realize it might be something you'll want in your code.

How to control the R/C car

Now, let's pretend that the values being read from both analog pins are ultimately controlling the steering of an R/C car using a servo, and the speed (and direction) of the same car with an R/C PWM motor controller. Certain assumptions are going to be made for this tutorial, but the basic idea is that when the joystick is at rest at the "center" position, the R/C car would be stopped, with the wheels pointed straight ahead. When you moved the stick to the left or the right, you would use the value obtained to alter the position of the front wheels of the car to point them left or right accordingly. If you pushed the stick forward, you would use the value obtained to make the car move forward, at a speed proportional to the amount read from the potentiometer (so the further forward the stick is moved, the faster the car would move in that direction). Similarly for the reverse direction (by pulling the stick back towards you).

The basics of the code would look like the following:

#include <Servo.h>
 
Servo steering; // instantiate a steering servo object
Servo throttle; // instantiate a throttle servo object
 
void setup() {
  steering.attach(9);  // attach steering servo object to pin 9
  throttle.attach(10); // attach throttle servo object to pin 10
}
 
loop() {
  int x_axis = AnalogRead(0); // value of X-Axis joystick (0-1023, 512 = centered)
  int y_axis = AnalogRead(1); // value of Y-Axis joystick (0-1023, 512 = centered)

  // filter out a centered joystick - no action
  if (x_axis < 510 || x_axis > 514) {
    if (y_axis < 510 || y_axis > 514) {
      // Map values from potentiometers to a smaller range for the servos (0-255)
      x_axis = map(x_axis, 0, 1023, 0, 255);
      y_axis = map(y_axis, 0, 1023, 0, 255);

      steering.write(x_axis); // here we assume that values > 128 = right, and < 128 = left for the steering servo
      throttle.write(y_axis); // here we assume that values > 128 = forward, and < 128 = reverse for the motor controller
    }
  }

  // center both servos if the joystick is centered
  if (x_axis >= 510 || x_axis <= 514) {
    if (y_axis >= 510 || y_axis <= 514) {
      throttle.write(128);
      steering.write(128);
    }
  }
}

Note that the code above makes some assumptions that may not hold up in "the real world"; you may have to adjust certain numbers and parameters used. Also, if your steering or direction is opposite of what you command (that is, you push your joystick forward, and the car goes in reverse), you can either change the logic in the code, or you can swap around the connections on the outer pins of the potentiometer for the axis that isn't working correctly.

BTW, the steering method just described, which is common to regular automobiles and most R/C cars, is known as Ackermann Steering geometry.

How to control an R/C tank - Skid Steering

If you plan on controlling an R/C tank type vehicle with differential steering - also known as skid steering, you have to do things differently. In this case, the position and value of the Y-Axis will determine how much speed (forward or reverse) to apply to both "tracks" (I'm going to call them tracks, although they could also be wheels) on either side of the robot. The position and value of the X-Axis, however, will determine how much power to reduce the same side by (so, pushing the X-Axis to the right will affect the right-hand side track of the robot, and vice-versa). Note that by reducing the power on the side the stick points to, you effectively cause the robot to turn in that direction.

The basics of the code for this control system would look like the following:

#include <Servo.h>
 
Servo l_track; // instantiate a servo object for the left track motor controller
Servo r_track; // instantiate a servo object for the right track motor controller
 
void setup() {
  l_track.attach(9);  // attach left track servo object to pin 9 (PWM)
  r_track.attach(10); // attach right track servo object to pin 10 (PWM)
}
 
loop() {
  int x_axis = AnalogRead(0); // value of X-Axis joystick (0-1023, 512 = centered)
  int y_axis = AnalogRead(1); // value of Y-Axis joystick (0-1023, 512 = centered)

  // filter out a centered joystick - no action
  if (x_axis < 510 || x_axis > 514) {
    if (y_axis < 510 || y_axis > 514) {
      // Map values from potentiometers to a smaller range for the PWM motor controllers (0-255)
      x_axis = map(x_axis, 0, 1023, 0, 255);
      y_axis = map(y_axis, 0, 1023, 0, 255);

      int ly_axis = y_axis;
      int ry_axis = y_axis;

      if (x_axis < 126) { // turning left, so slow-down left track
        if (y_axis > 130) { // moving forward
          ly_axis -= (255 - x_axis); // decreasing the value - moving it closer to the center-point - slows it down
        }

        if (y_axis < 126) { // moving in reverse
          ly_axis += (255 - x_axis); // increasing the value - moving it closer to the center-point - slows it down
        }
      }

      if (x_axis > 130) { // turning right, so slow-down right track
        if (y_axis > 130) { // moving forward
          ry_axis -= (255 - x_axis); // decreasing the value - moving it closer to the center-point - slows it down
        }

        if (y_axis < 126) { // moving in reverse
          ry_axis += (255 - x_axis); // increasing the value - moving it closer to the center-point - slows it down
        }
      }

      l_track.write(ly_axis); // here we assume that values > 128 = forward, and < 128 = reverse for the left track motor controller
      r_track.write(ry_axis); // here we assume that values > 128 = forward, and < 128 = reverse for the right track motor controller
    }
  }

  // center both PWM values if the joystick is centered (bringing both motor controllers and tracks to a stop)
  if (x_axis >= 510 || x_axis <= 514) {
    if (y_axis >= 510 || y_axis <= 514) {
      l_track.write(128);
      r_track.write(128);
    }
  }
}

Once again, note that the code above makes some assumptions that may not hold up in "the real world"; you may have to adjust certain numbers and parameters used.

The drawback with the method of control described above is that there isn't any way to cause the robot to "pivot" about its center-point. This is because the system described does a form of control mixing, due to the nature of the joystick. Here's a couple of possibilities to get around this issue (I'll leave them to you to implement):

  1. Use two joysticks, and only use the output from the Y-Axis of each, side by side. Push one forward makes that side go faster, pull it back makes it move in reverse, center is "stopped". Do that for both tracks, and you can control such a tracked vehicle fairly easily.
  2. Use a single joystick, but make a "crescent" shaped region at the extreme left and right travels on the X-Axis indicate "spin clockwise or counterclockwise", depending on which way the joystick is pushed.

If you want to know more about differential steering in robots, this link will give you some more information:

Differential Wheeled Robot

There are also many other steering methods available. Each has its good points and each has its drawbacks, but it's good to understand them in case you need to solve a particular steering problem in robotics.

Finally...


The Analog Joystick
Questions or Comments?

...notice the button underneath the peg, on the left-hand side of the picture? When the joystick is pressed down, this causes the peg to press down on the button, and the contacts of the button are closed. You could hook up the button to a digital input on the Arduino, for instance...

Have fun!

Share This Article

    

Questions or Comments?

If you have any questions or comments about this article, please contact me...

Referencing Articles:
0 comment(s) posted
Post New Thread