Controlling a UTV with a joystick

Hello,
I'm working on adding a joystick to a coworkers John Deere gator who has MD. Im going to use servo controlled linear actuators for the accelerator and brake and using the factory electric power steering motor for steering. I created a prototype with two RC servos and a gear motor. I got everything working I am just looking for constructive criticism on what I have written. Eventually I would like to change the joystick response from linear to a curve, add a PID controller for the steering so when the joystick is in the center position the wheels will self center, add code to self calibrate the dead band of the joystick and add a system in case of a fault it will illuminate a light on the dash. Thank you

gator.ino (2.83 KB)

Here's the code. You should post it, rather than attach it. :-

#include <Servo.h>

int left = 12;      // left turn
int right = 13;     // right turn
int rpm = 11;         // turn speed
int accel = 5;        // first servo
int brake = 6;        // second servo
int joyx = A0;        // L/R Parallax Thumbstick
int joyy = A1;        // U/D Parallax Thumbstick
int safety = 4;       // grip safety

int servoa;           // Accelerator Servo
int servob;           // Brake Servo
int emergencybrake;   // grip safety
int SpeedR;           // right turning speed
int SpeedL;           // left turning speed
int Joyx;             // mapped joyx
int Joyy;             // mapped joyy

Servo gaccel;  // create servo object to control a servo
Servo gbrake;  // create servo object to control a servo

void setup()
{

    // Servo
    gaccel.attach(accel);  // attach servo to pin 5
    gbrake.attach(brake);  // attach servo to pin 6

    pinMode(4, INPUT);     // set grip safety pin mode
    pinMode(11, OUTPUT);   // set motor speed pin mode
    pinMode(12, OUTPUT);   // set left motor direction pin mode
    pinMode(13, OUTPUT);   // set right motor direction pin mode

}

void loop()
{
    emergencybrake = digitalRead(safety);  // read grip safety switch status

    if (emergencybrake == LOW)             // system will apply the brake servo to max and set the accel servo to zero and set the steering direction pins to LOW
    {
        gaccel.write(0);
        gbrake.write(180);
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
        return;
    }

    servoa = analogRead(joyx);                    // Read the horizontal joystick pin (value between 0 and 1023)
    servoa = map(servoa, 0, 1023, -1000, 1000);     // map value between -1000 and 1000
    servoa = map(servoa, -1000, -15, 180, 0);     // map it with the servo output (result  between 0 and 180)
    gaccel.write(servoa);                       // sets the servo position according to the scaled value

    servob = analogRead(joyx);
    servob = map(servob, 0, 1023, -1000, 1000);     // map value between -1000 and 1000
    servob = map(servob, -250, 1000, 0, 170);     // scale it to use it with the servo (result between 0 and 180)
    gbrake.write(servob);                       // sets the servo position according to the scaled value

    Joyy = analogRead(joyy);                    // read vertical joystick pin
    Joyy = map(Joyy, 0, 1023, -1000, 1000);     // map value between -1000 and 1000
    SpeedR = map(Joyy, -1000, -25, 255, 0);     // map right steering value between 255 and 0
    SpeedL = map(Joyy, 25, 1000, 0, 255);       // map left steering value between 0 and 255

    if (SpeedR < 25 && SpeedL < 25 )
    {
        digitalWrite(12, LOW);
        digitalWrite(13, LOW);
    }

    if (SpeedR >= 25 )
    {
        analogWrite(11, SpeedR);
        digitalWrite(13, HIGH);
        digitalWrite(12, LOW);
    }

    if (SpeedL >= 25 )
    {
        analogWrite(11, SpeedL);
        digitalWrite(12, HIGH);
        digitalWrite(13, LOW);
    }
    delay(1);
}

In this following snippet, is it possible for the analogRead() of the joystick to return, for example, 700?
If so, then the value written to the servo will be -69. :-

servoa = analogRead(joyx);                    // Read the horizontal joystick pin (value between 0 and 1023)
  servoa = map(servoa, 0, 1023, -1000, 1000);     // map value between -1000 and 1000
  servoa = map(servoa, -1000, -15, 180, 0);     // map it with the servo output (result  between 0 and 180)
  gaccel.write(servoa);                       // sets the servo position according to the scaled value

The joystick Im currently using will output a 0-5v signal so I assume yes it will give a reading of 700. Im not sure I follow what your saying about the servo output of -69?

Plug the numbers into your sketch

Yeah it is outputting a negative number to the servo but the servo is functioning. Will that not work?

I would have simply mapped 0-1023 to 0-180 or 180-0, perhaps a little less range, but if that's the way you want it to operate.....

Without knowing for certain the overall mechanical design, I can't tell whether the code is really proper.

For instance, let's say your linear actuators aren't able to be back-driven by the spring pressure of the fuel pedal (or throttle) and the brake mechanism. What happens if the linear actuator's power cable breaks or disconnects in some manner?

For that matter - where in your code are you testing for that possibility (and then going into e-stop mode when it occurs)? I don't see anything about that.

What you are building is the equivalent of a large-scale robot, that happens to have a cargo of a man in it, taking and acting on commands that man gives via some set of controls (joystick or otherwise).

I have some limited experience with working on and refurbishing mobility scooters and wheelchairs. While they may look like simple devices, they are anything but. In fact - they themselves are robots of a sort. As such, they are built with safety first and foremost up front. If the battery voltage varies by any amount, if any potentiometer or other control isn't outputing the proper resistance, voltage, or other signal - if the user isn't sitting in the chair...all of these instantly shuts the machine down, and triggers an error.

You need to design this into your system first. In fact, I would scrap the code you have already written, and then think very carefully about how you intend to modify the vehicle to work with the automated control system, along with what modifications (mechanical or electrical) you can introduce to implement a fail-safe system. Try to think of any or all options; overspeed, roll and pitch angle, loss of steering or braking, stuck accelerator, etc. Try to think of ways to bring the system to a halt instantly - or as quickly as possible - in each scenario. Then try to think of ways to do this with the the Arduino controlling that system.

Also think of ways to have the system detect if a controller malfunctions. Be sure to implement an emergency stop button (or multiple buttons! - and use a real e-stop button that can't be easily reset after it is activated - like those used in factories, etc) - and perhaps implement it in some manner that is electrically based, or has a component separate from the code/Arduino (in case the Arduino fails, for instance!). One way, for instance, would be if the button is pressed, it cuts off power, which causes a valve to close to cut fuel off from the engine, and maybe activates the brake using an electro-mechanical system of some sort.

Once you have come up with a complete plan - go over it with your friend. Go over it with other people. Try to have them pick it apart, see if there are any obvious weak spots. Then fix those spots. Then - take a month off away from the whole system (and don't think about it at all!). Then come back, look it over, and see if you spot anything obvious you missed. You won't necessarily catch everything, and you may not be able to make it perfect (since you are working with a machine that wasn't meant to be modified in such a manner), but you can get very, very close.

You might look into and/or talk to companies who modify vans and other automobiles for disabled people to use, to find out what they do for safety purposes. It couldn't hurt to at least try.

Ultimately, you need to be designing this system from the ground up for safety; if you aren't doing this, you'll be doing your friend a disservice.

You hit the nail on the head, I don't know how to code in fail safes into arduino that looks for bad signals from the sensors or from the outputs. The system is going to use a big red emergency stop button that will kill power to the entire machine if pressed. Once it is installed I'm going to limit the max actuator stroke to prevent the machine from going above 10-12 mph. I'm going to be using a 200 lb linear actuator for the brake system that mounts under the dash and actuates the brake pedal and I'm leaning more toward a regular servo with spring back to 0 for the throttle. Thank you for the incite's.