Pages: [1]   Go Down
Author Topic: Differential Steering using a joystick / programming question....  (Read 1696 times)
0 Members and 1 Guest are viewing this topic.
Derbyshire, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Hello Everyone!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Guys,

I am brand new here, so please forgive my "noobie"ness.  This should be quite a simple problem, but it is driving me loopy...

Basically, I want to control two motors (forward fast / slow and steering via differential speed).

The inputs are: X-axis potentiometer (turn) is connected to pin A1 and Y-axis (move) pot is connected to A0.
0,-128 is bottom left and 255,128 is top right.  There is a "forward only" strip in the centre from -10 to +10, where turning signal is ignored (just to make it not too squirrely).

Outputs are: left motor digital pin 10 and right motor digital pin 9.

I have written a sketch which sort of works, but whenever the "turn" value is greater than the "move" value, it starts behaving erratically.  

I have been trying to figure this out all day, and am starting to lose the plot!!  Please find the code below... any ideas? This is my first real go at programming, so please be kind....  :-)   Thanks, Tim


/* This script is intended to operate a differential steering system, but is
a little buggy.  Whaenever the Y value is greater than the X value, it reverses
it's operation.
*/

const int LMotor=10;
const int RMotor=9;
int val = 0;
int off = 0;

int move;
int turn;

  

  


void setup() {
  
 pinMode(A0, INPUT);
 pinMode(A1, INPUT);
  
  
  pinMode(LMotor,OUTPUT);
  pinMode(RMotor,OUTPUT);
  
  Serial.begin(9600);
}

void loop() {
  // read the X (turning) input on analog pin A1 and Y (ahead) input
  //on analog pin A0:

  int  aheadY = analogRead(A0);
  int  turnX = analogRead(A1);


  move = map(aheadY, 0,1023, 0, 255);
  move = constrain(move, 0, 255);
  
  turn = map(turnX, 0,1023,-128,127);
  turn = constrain(turn, -128,127);
  
  Serial.print("Move   ");
  Serial.println(move);
  
  Serial.print("              Turn     ");
  Serial.println(turn);
  
  if (turn >=-10 && turn <=10)  // go forward
  {
  analogWrite (LMotor,move);
  analogWrite (RMotor,move);
 }
  if (turn > move)  //  this sequence seems to
  {
    analogWrite (LMotor,0);  // have absolutely no effect..
    analogWrite (RMotor,0);
  }
  
  if (turn <-10)   // forward left
  {
  analogWrite (LMotor,move + turn);    
  analogWrite (RMotor,move);
  }
  
  if (turn >10)     // forward right
  {
  analogWrite (LMotor,move);
  analogWrite (RMotor,move - turn);
  }
 }


Logged

Derbyshire, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Hello Everyone!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a photo of the offending item....


* Joystick Testbed.jpg (1498.25 KB, 1936x2592 - viewed 132 times.)
Logged

BCC AZ USA
Offline Offline
Edison Member
*
Karma: 33
Posts: 1146
It gets hot so it must be working
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your circuit will only turn the motor on or off.  there is no way to get reverse with that circuit.  a one one the Arduino output will turn the motor one,  zero off.  you will need  an H-bridge to get forward and reverse.  there are lots of examples for dc motor control.
Logged

Derbyshire, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Hello Everyone!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi GF,

Thanks for the reply.

For this application, I don't need reverse, just to be able to control speed and rate of turn.   

If I was really clever, I would even be able to program the radius of turn at a given speed, but I am just not that smart.....  :-(


:-)

Tim


Logged

Phoenix, Arizona USA
Offline Offline
Faraday Member
**
Karma: 39
Posts: 5551
Where's the beer?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm going to try to explain something - and once I do, it will either get your brain running again - or it just might be a "doh!" moment...

You have two axes on the joystick - an x-axis and a y-axis, right? So - let's imagine you have the potentiometers of each axis connected to an analog input on the Arduino. So - what happens then if you push the joystick all the way up into the upper-left hand corner?

That's right - your Arduino is going to read "0" for the x-axis, and "0" for the y-axis (note: I am ignoring any possibility that calibration of the joystick will be needed - in reality, this is most likely - I don't know if you are old enough or not to remember old DOS games, and how you had to calibrate the analog joystick before playing a game - the routine was a part of the game itself).

Now - what happens if you then push the joystick to the lower-right corner?

Yes - your Arduino will read "1023" for the x-axis, and "1023" for the y-axis...

So - what does this mean? Well - here are the values (more or less):


0,0     511,0   1023,0
  \       |       /
   \      |      /
    \     |     /
     \    |    /
      \   |   /
       \  |  /
        \ | /
         \|/
0,511-----+-----1023,511
         /|\    
        / | \        
       /  |  \
      /   |   \
     /    |    \
    /     |     \
   /      |      \
  /       |       \
0,1023 511,1023 1023,1023


Now - if you subtract 511 from each axis - that'll "center-up" the values - which means that the upper-left will be "-511,-511", the center will be "0,0", and the lower-right will be "512, 512"...and the other values will change similarly - understand?

Now - given that - what can you do?

Well - what if you said "my x-axis value will drive my left wheel" and "my y-axis value will drive my right wheel" - and then you scaled the values for the PWM, and based on the sign of the value, switched the PWM from one side or the other of the h-bridge...

So - let's suppose positive values mean "forward" and negative values mean "reverse". So now, at rest - the joystick (auto-centered) would read "0,0" - and a PWM values of "0" would be sent to each motor, and they would remain "off".

Then, when you pushed the joystick to the bottom-right corner, you are reading "512,512", then after scaling and sign checking - you apply PWM values of "255,255" to both motors - you're now going forward!

If you pushed the joystick to the upper-left corner, you are reading "-511, -511", then scaled and sign checked to mean "apply PWM values of 255,255 to the other pin of the h-bridge" to drive both motors in the opposite direction - and you're going backward!

So what happens if you push the joystick to the *upper-right* side? Well, you would then read "512, -511" - and after scaling and sign-checking - hey look! One motor turning one way, and the other the opposite! Turning in place, so to speak. For the "lower-left" side, you would read "-511, 512" - wow! Spinning in the opposite direction.

Take a look at the other ordinal points - and notice what they do: That's right, you can turn one motor off, and have the other spinning - that is, one wheel moving, and the other stationary - so instead of turning on the center-point of the "axle" between the wheels, you are now rotating around the center of one of the wheels.

All fine and well - for the most part - but! Everything is on a diagonal - how can I use my joystick this way (you're asking yourself)? Simple:

Rotate the joystick 135 degrees counter-clockwise - so that the normally "bottom-right" corner of the joystick faces "up"...

Note that this isn't a perfect solution; it has it's bugs - but maybe you (or someone else) can make use of it. I hope it helps, or at least gives you some ideas. It's an example of thinking outside of the box (the main part being to not look at the joystick as needing to be explicitly oriented in an X/Y position as given by the potentiometers).

Good luck with your project!

smiley-grin

« Last Edit: June 17, 2013, 11:49:48 pm by cr0sh » Logged

I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

Derbyshire, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Hello Everyone!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

cr0sh, you are a genius, mate.

I have done what you suggested (turned the stick by 45 degrees) and have a "stick plan" which looks like this:
                                L    R
                 max        255,255
left wheel    /
pot here    /
         min/                   |
               L   R             |               L   R
              255,0         - - + - -          0,255
           max                  |
              \                    |
rt wheel    \
pot here     \                L R
                min             0,0

One potentiometer controls the left wheel, and the other controls the right.  There is currently no reverse, although by remapping the pots  to say, -10 to 245 and using an if statement that could easily be handled.

The right stick values ("R" in the diagram) are then fed to the left motor, and the left stick values ("L" in the diagram) are then fed to the right motor.....  simples!

It works a treat, the only thing it needs now is some way of "proportionaly slowing it down"...  in other words, having both motors reading 255 and running at full chat is fine, but having one reading 0 and stopped and the other reading 255 and at running full blat is a bit harsh.  I have tried subtracting the 2 values and dividing them, but I'm just not getting it right....

Anyway, here is the code if anyone needs it....


// This script operates a differential steering system. By Tim Coyne


const int LMotor=10;
const int RMotor=9;
int val = 0;

void setup() {
 
 pinMode(A0, INPUT); // connects #1 potentiometer which senses stick inputs on the right of center to Arduino
 pinMode(A1, INPUT); // connects #2 potentiometer which senses stick inputs on the left of center
 
 
  pinMode(10,OUTPUT);  // connects left motor to Arduino
  pinMode(9,OUTPUT);   // connects right motor
 
  Serial.begin(9600);  // sends stick left and right values back to computer
}

void loop() {
 
  int  leftStick = analogRead(A0);  // reads leftStick inputs
  int  rightStick = analogRead(A1);  // reads rightStick inputs

  leftStick = map(leftStick, 0,1023, 0, 255);  // changes 1023 steps to 256 steps which Arduino can read
  leftStick = constrain(leftStick, 0, 255);
 
  rightStick = map(rightStick, 0,1023, 0,255);  // changes 1023 steps to 256 steps which Arduino can read
  rightStick = constrain(rightStick, 0,255);
 
  Serial.print("Left Stick   ");    // This makes the left and right values easier to read on the computer screen.
  Serial.println(leftStick);
  Serial.print("                   Right Stick     ");
  Serial.println(rightStick);       
 
  {
  analogWrite (LMotor,rightStick);  // the left motor is driven by right stick value
  analogWrite (RMotor,leftStick);   // the right motor is driven by left stick value
  }}
 
  // simples.  :-)


* Joystick Testbed.jpg (1498.25 KB, 1936x2592 - viewed 87 times.)
« Last Edit: June 18, 2013, 07:38:38 am by TimCoyne » Logged

Pages: [1]   Go Up
Jump to: