Okay, here goes :
DISCLAIMER: I DO NOT HAVE THE ROBOT IN POSSESSION RIGHT NOW. THIS IS ALL THEORETICAL.
My robotic vehicle is supposed to be controlled wireless-ly through a two-axis joystick. I, having no experience in differential steering, used an algorithm by Dustin Maki as a template.
Here is his algorithm:
#define START_BUTTON 21 // not a momentary switch, a toggle switch will work
#define JOYSTICK_BUTTON_PIN 10 // hold joystick with 'tail' toward you. side with holes on sparkfun breakout board
#define JOYSTICK_X_PIN A0 //full left is 1023, full right is 0
#define JOYSTICK_Y_PIN A1//full forward is 1023, full backward is 0
#define LEFT_PWM_PIN 14
#define LEFT_DIRECTION_PIN 13
#define RIGHT_PWM_PIN 24
#define RIGHT_DIRECTION_PIN 23
#define HALF_DEADBAND 3 //adjust till desired deadband is achieved
#define XRAW_CENTERED 525 // set to whatever "x joystick value is: " on the serial monitor
#define YRAW_CENTERED 493 // set to whatever "y joystick value is: " on the serial monitor
#define DEBUG true // set to false to stop serial messages
{
// capture joystick position
yraw = analogRead(JOYSTICK_Y_PIN);
xraw = analogRead(JOYSTICK_X_PIN);
// scale x and y axis so that both are zeroed at natural center of potentiometer, implement deadband
if(yraw > YRAW_CENTERED + HALF_DEADBAND)//forward
{
throttle = map(yraw, YRAW_CENTERED + HALF_DEADBAND, 1023, 0, 255);
if(xraw > XRAW_CENTERED + HALF_DEADBAND)//left
{
steering = map(xraw, XRAW_CENTERED + HALF_DEADBAND, 1023, -0, -255);// reverse pot coordinates to agree with cartesian
}
else if(xraw < XRAW_CENTERED - HALF_DEADBAND)// right
{
steering = map(xraw, XRAW_CENTERED - HALF_DEADBAND, 0, 0, 255);// reverse pot coordinates to agree with cartesian
}
else // in X deadband
{
steering = 0;
}
}
else if(yraw < YRAW_CENTERED - HALF_DEADBAND)//reverse
{
throttle = map(yraw, YRAW_CENTERED - HALF_DEADBAND, 0, -0, -255);
if(xraw > XRAW_CENTERED + HALF_DEADBAND)//left
{
steering = map(xraw, XRAW_CENTERED + HALF_DEADBAND, 1023, -0, -255);// reverse pot coordinates to agree with cartesian
}
else if(xraw < XRAW_CENTERED - HALF_DEADBAND)// right
{
steering = map(xraw, XRAW_CENTERED - HALF_DEADBAND, 0, 0, 255);// reverse pot coordinates to agree with cartesian
}
else// in X deadband
{
steering = 0;
}
}
else //in Y deadband
{
throttle = 0;
if(xraw > XRAW_CENTERED + HALF_DEADBAND)//left
{
steering = map(xraw, XRAW_CENTERED + HALF_DEADBAND, 1023, -0, -255);// reverse pot coordinates to agree with cartesian
}
else if(xraw < XRAW_CENTERED - HALF_DEADBAND)// right
{
steering = map(xraw, XRAW_CENTERED - HALF_DEADBAND, 0, 0, 255);// reverse pot coordinates to agree with cartesian
}
else// in X deadband
{
steering = 0;
}
}
//transfer from x,y to l,r
leftSpd = throttle + steering;
rightSpd = throttle - steering;
//leftSpd and rightSpd will contain a number from -255 to 255 that gets updated each time the loop runs.
//-255 equates to full reverse. 0 equates to anywhere within the deadband. 255 is full forward.
// The next 2 sections can be replaced to use with servos, stepper motors, BLDCs or whatever drive you like.
//write direction pin
if (leftSpd < 0)
digitalWrite(LEFT_DIRECTION_PIN, LOW);
else if (leftSpd > 0)
digitalWrite(LEFT_DIRECTION_PIN, HIGH);
if (rightSpd < 0)
digitalWrite(RIGHT_DIRECTION_PIN, LOW);
else if (rightSpd > 0)
digitalWrite(RIGHT_DIRECTION_PIN, HIGH);
//write PWM pin
analogWrite(LEFT_PWM_PIN, leftSpd);
analogWrite(RIGHT_PWM_PIN, rightSpd);
if (DEBUG)
{
Serial.print("x joystick value is: ");
Serial.println(xraw);
Serial.print("y joystick value is: ");
Serial.println(yraw);
Serial.print("throttle is: ");
Serial.println(throttle);
Serial.print("steering is: ");
Serial.println(steering);
Serial.print("leftSpd is: ");
Serial.println(leftSpd);
Serial.print("rightSpd is: ");
Serial.println(rightSpd);
delay(250);
}
}
The joystick he uses has full left=1023 and full up=1023; so the same setup as my joystick.
I have attached a little diagram that maps out the position and values returned from my joystick.
Also, instead of the servos used in the template, my robotic vehicle uses dc motors controlled by a motor driver, which takes in speeds from -400 to 400. Taking that into account, I edited the algorithm to match my needs :
#define XRAW_CENTERED 517 //centered joystick x value
#define YRAW_CENTERED 501 //centered joystick y value
#define HALF_DEADBAND 2 //joystick deviation
void MotorSpeed(int xraw, int yraw){
//sets brake whenvever joystick is centered
if(abs(xraw - XRAW_CENTERED) <= 2 && abs(yraw - YRAW_CENTERED) <= 2 && leftSpeed != 0 && rightSpeed != 0){
md.setBrakes(200,200);
}
if(yraw > YRAW_CENTERED + HALF_DEADBAND)//forward
{
throttle = map(yraw, YRAW_CENTERED + HALF_DEADBAND, 1023, 0, 400);
if(xraw > XRAW_CENTERED + HALF_DEADBAND)//left
{
steering = map(xraw, XRAW_CENTERED + HALF_DEADBAND, 1023, -0, -400);// reverse pot coordinates to agree with cartesian
}
else if(xraw < XRAW_CENTERED - HALF_DEADBAND)// right
{
steering = map(xraw, XRAW_CENTERED - HALF_DEADBAND, 0, 0, 400);// reverse pot coordinates to agree with cartesian
}
else // in X deadband
{
steering = 0;
}
}
else if(yraw < YRAW_CENTERED - HALF_DEADBAND)//reverse
{
throttle = map(yraw, YRAW_CENTERED - HALF_DEADBAND, 0, -0, -400);
if(xraw > XRAW_CENTERED + HALF_DEADBAND)//left
{
steering = map(xraw, XRAW_CENTERED + HALF_DEADBAND, 1023, -0, -400);// reverse pot coordinates to agree with cartesian
}
else if(xraw < XRAW_CENTERED - HALF_DEADBAND)// right
{
steering = map(xraw, XRAW_CENTERED - HALF_DEADBAND, 0, 0, 400);// reverse pot coordinates to agree with cartesian
}
else// in X deadband
{
steering = 0;
}
}
else //in Y deadband
{
throttle = 0;
if(xraw > XRAW_CENTERED + HALF_DEADBAND)//left
{
steering = map(xraw, XRAW_CENTERED + HALF_DEADBAND, 1023, -0, -400);// reverse pot coordinates to agree with cartesian
}
else if(xraw < XRAW_CENTERED - HALF_DEADBAND)// right
{
steering = map(xraw, XRAW_CENTERED - HALF_DEADBAND, 0, 0, 400);// reverse pot coordinates to agree with cartesian
}
else// in X deadband
{
steering = 0;
}
}
//transfer from x,y to l,r
leftSpeed = throttle + steering;
rightSpeed = throttle - steering;
md.setSpeeds(leftSpeed,rightSpeed);
}
Now for the problem, or supposed problem:
When the joystick is fully up, the formula returns a value of left speed 400 and right speed 400 which is correct.
When the joystick is fully down, the formula returns a value of left speed -400 and rightspeed -400 which is correct.
When the joystick is to the left only, the formula returns a value of left speed -400 and right speed -400 which is correct.
When the joystick is to the right, the formula returns a value of left speed 400 and right speed -400 which is right.
However, the problem arises when the joystick is for example diagonally to the top right such that the y value is 1023 and the x value is 0.
According to my calculations using the formula, I get a leftspeed of 800 and right speed of 0.
If anyone has taken the time to check using the formulas in the code above, are my calculations right? If so, how do I fix it as my motor driver library only takes an int value from -400 to 400.
joystickmap.pdf (57.4 KB)
