Introduction: Arduino: Joystick and Motors (H-Bridge / Servo)

About: ERROR 404: NOT FOUND

Joystick module can be used for controlling motors and it's really simple to do. In this instructable I will teach you how to use it with classic DC motor and Servo motor with help of Arduino. Tutorial will be divided into small sections. First section will teach you how joystick works, second one how to use it with H-Bridge and third Servo.

Step 1: Understanding How Joystick Works

Joystick has 2 main potentiometers. One for each axis. Potentiometers are just classic resistors with third pin that can slide over resistive material. One end of resistive material is connected to ground and other to positive. By sliding the third contact we can get voltage between ground and positive potential.

Joystick is kept in middle by 2 springs. One spring for each axis. Now if we move mushroom, potentiometers will also change position and voltage will change on output pins (X and Y). If VCC is 5V and GND is 0V then we will have output voltage range from 0V to 5V depending on position of mushroom.

When joystick is in idle position, voltage on both X and Y pins will be 2.5V. It's because potentiometer pin is exactly in middle and we will get half of input voltage on output pins. If we start moving mushroom to the right we are changing position of Y axis potentiometer and moving it towards end that is connected to positive and we are getting higher and higher voltage on output of Y axis. Moving it in left is the same just in reverse, voltage is going down. For X axis if we go up voltage goes up and if we go down voltage goes down.

Let's use X axis for this example: When its all the way up its output voltage is 1 multiplied by input voltage, when its all the way down its output voltage will be 0 multiplied by input voltage. If we let it go in idle position output voltage will be 1/2 multiplied by input voltage. Rule is the same for Y axis, left is 0, right is 1 and middle is 1/2.

There is also push button between ground and KEY pin. So you should use pull-up of Arduino if you are planning to use it.

Step 2: Adding H-Bridge and Servo

Arduino's ADC is 10bit, that means it will split input voltage to 1024 (2 to the power of 10) pieces starting with 0. So input range is from 0 to 1023. 0 = 0V and 1023 = 5V.

If we connect joysticks axis to analog pins and apply the rule from before we will have value of 0 when Y axis is down, 1023 when it is up and 511 when its in middle.

My plan is to use Y axis for Servo motor and X axis for DC motor driven by H-Bridge.

My H-Bridge has 2 inputs, forward and reverse, when both are on same logic level motor wont move. It will move forward if our reverse is pulled low while forward is pulled high and reverse if our forward is pulled high while the reverse is pulled low.

I dont want motor to move when X axis is in idle position. When i move it up i want motor to start going forwards with speed control and same for reverse.

We can do it by using map function. But first we have to set up thresholds for both axis. Threshold is point where the movement starts, i want it to be at 491 for lower part and 531 for higher part( Middle(511) +/- 20 ).

Lets do it like this:

#define MIDDLE 511
#define LOW_THD 491
#define HIGH_THD 531

int X_AXIS = analogRead(X_AXIS_PIN);

Now we can add if function to tell Arduino what to do if Joystick is in idle position:
if(X_AXIS > LOW_THD && X_AXIS < HIGH_THD)
{
// do some stuff here when joystick is not touched (idle), lets stop dc motor
stopMotor(); //some code for my H-Bridge to stop motor...
}

Lets set up forward movement:
if(X_AXIS >= HIGH_THD)
{
int pwmFWD = map(X_AXIS, HIGH_THD, 1023, 0, 255) //convert range from HIGH_THD-1023 to 0-255 for pwm
pwmForward(pwmFWD);
}

Lets set up reverse movement:
if(X_AXIS <= LOW_THD)
{
int pwmREV = map(X_AXIS, 0, LOW_THD, 255, 0) //convert range from 0-LOW_THD to 255-0 for pwm
pwmReverse(pwmREV);
}

That was all about using X axis for forward and reverse speed control, now lets do it for servo. Servo has rotation angle of 180 degrees and middle is 90.

#define MIDDLE 511
#define LOW_THD 491
#define HIGH_THD 531
#define SERVO_MIN 0
#define SERVO_MIDDLE 90
#define SERVO_MAX 180

int Y_AXIS = analogRead(Y_AXIS_PIN);

When joystick is idle we want servo to be at 90 degrees:
if(Y_AXIS > LOW_THD && Y_AXIS < HIGH_THD)
{
myservo.write(SERVO_MIDDLE); //set servo to mid-point
}

Lets set up left angle:
if(Y_AXIS <= LOW_THD)
{
int angleLeft = map(Y_AXIS, 0, LOW_THD, 0, 90); //convert range from 0-LOW_THD to angle 0-90
myservo.write(angleLeft);
}

Lets set up right angle:
if(Y_AXIS >= HIGH_THD)
{
int angleRight = map(Y_AXIS, HIGH_THD, 1023, 90, 180); //convert range from HIGH_THD-1023 to angle 0-180
myservo.write(angleRight);
}

Those are just some examples of using joystick to control Servo and H-Bridge not whole code. In last part, where we put angle left and right, we put our imaginary 0 degree point at servos mid-point so we can go 90 degrees to left and 90 degrees to right.

Step 3: Example Code That I Used for My DIY RC Car

#include <Servo.h>

#define H_BRIDGE_FWD 5
#define H_BRIDGE_REV 6
#define SERVO_PIN 9
#define SERVO_POT_PIN A0 // Y AXIS
#define MOTOR_POT_PIN A1 // X AXIS

#define JOYSTICK_LOW_THD 491
#define JOYSTICK_HIGH_THD 531

#define JOYSTICK_MIDDLE 511

#define SERVO_MIN 0
#define SERVO_MIDDLE 90
#define SERVO_MAX 180

Servo myservo;

int SERVO_ANALOG, MOTOR_ANALOG;

void setup()
{
pinMode(H_BRIDGE_FWD, OUTPUT);
pinMode(H_BRIDGE_REV, OUTPUT);
myservo.attach(SERVO_PIN);
}

void loop()
{
readAxis();
if (MOTOR_ANALOG <= JOYSTICK_LOW_THD)
{
int revPWM = map(MOTOR_ANALOG, 0, JOYSTICK_LOW_THD, 255, 0)
reverse(revPWM);
}
if (MOTOR_ANALOG >= JOYSTICK_HIGH_THD)
{
int fwdPWM = map(MOTOR_ANALOG, JOYSTICK_HIGH_THD, 1023, 0, 255)
forward(fwdPWM);
}
if (MOTOR_ANALOG > JOYSTICK_LOW_THD && MOTOR_ANALOG < JOYSTICK_HIGH_THD)
{
stopMotor();
}
if (SERVO_ANALOG <= JOYSTICK_LOW_THD)
{
int angleLeft = map(SERVO_ANALOG, 0, JOYSTICK_LOW_THD, SERVO_MIN, SERVO_MIDDLE);
myservo.write(angleLeft);
}
if (SERVO_ANALOG >= JOYSTICK_HIGH_THD)
{
int angleRight = map(SERVO_ANALOG, JOYSTICK_HIGH_THD, 1023, SERVO_MIDDLE, SERVO_MAX);
myservo.write(angleRight);
}
if (SERVO_ANALOG > JOYSTICK_LOW_THD && SERVO_ANALOG < JOYSTICK_HIGH_THD)

{
myservo.write(SERVO_MIDDLE);
}
delay(10);
}

void readAxis()
{
MOTOR_ANALOG = analogRead(MOTOR_POT_PIN);
SERVO_ANALOG = analogRead(SERVO_POT_PIN);
}

void forward(int PWM)
{
analogWrite(H_BRIDGE_FWD, PWM);
digitalWrite(H_BRIDGE_REV, 0);
}

void reverse(int PWM)
{
digitalWrite(H_BRIDGE_FWD, 0);
analogWrite(H_BRIDGE_REV, PWM);
}

void stopMotor()
{
digitalWrite(H_BRIDGE_FWD, 0);
digitalWrite(H_BRIDGE_REV, 0);
}