Hello. Currently I'm working on joystick controlled Arduino robot and found a big problem when programming the direction controls for it, specifically with diagonal movement.
Basically, most programs of Arduino joystick robot control only do forwards and backwards with the y-axis and pivot steering with the x-axis, but I wanted do to diagonal turning- basically, when you direct the analog stick at say, 2 o'clock, using both the x and the y-axis, there will be force going for both motors, but the left motor will be stronger and the right motor will be weaker. This way it allows you to do turns without just stopping dead to do it.
I tried to come up with a solution to it- the Arduino only uses the x-axis for mapping, then I wrote it so the innermost motor to the curve (again with the 2 o'clock example, in that case it would be the right motor) works as a "mirror" of the outermost motor of the curve, that way the farthest to the x-axis you pull the joystick the faster the outermost motor gets and the slower the innermost motor gets.
However that has bunch of problems; it's quite wonky and unreliable. The main problem is when the x-axis reading is low, like when you want to make a slight diagonal turn, because of the mirrored nature of the map function of the innermost motor, it will go stronger than the outermost motor, making you curve to the wrong way.
I thought about it for a long while and haven't really come up with anything to substitute the function- the two ideas I have is:
-
make some kind of equation that grabs both y and x-axis reading and does some kind of math operation to them to come up with a number; that number is translated into a PWM command and sent to the motor shield for the outermost motor, and it is proportionally divided by another function to be sent to the innermost motor.
-
Make a matrix of some sort for all the joystick values and have each position in the matrix (like 1024x1024) have a speed assigned to it, either by a function or manually, which sounds like a nightmare.
However I don't really have a clue on how to implement either of these of if they will even work. Do any of you guys have an idea of something I could do or use or base myself on to accomplish what I'm trying to do? Because I'm really at at loss here and any help would be appreciated.
Here is my code:
int potPin1= A4;//Y axis
int potPin2 = A5; //X axis
//these are the motor shield inputs
int ena = 5;//right motor power input
int en1 = 7;//right motor direction input 1
int en2 = 8;//right motor direction input 2
int enb = 6;// left motor power input
int en3 = 4;//left motor direction input 1
int en4 = 9;//left motor direction input 2
int joyValue1= 0;
int joyValue2= 0;
int joyValueMax = 1023;
int joyValueMin = 0;
int joyValueMid = 512;
int joyValueMidUpper = 550; //these two values are the necessary tolerances so that the car won't go crazy on idle
int joyValueMidLower = 470; //they also double has fixed values in between which the straight forward, straight backward and pivot steer left and right functions operate
byte motorSpeed1 = 0;
byte motorSpeed2 = 0;
byte motorSpeedMin = 0;
byte motorMaxMin = 90; //not in use, but this is here because the motor only starts to move reliably at 90; anything bellow that and it's really finicky and might not move
byte motorMaxHigh = 255;//maximum motor speed
void setup() {
pinMode (ena, OUTPUT);
pinMode (en1, OUTPUT);
pinMode (en2, OUTPUT);
pinMode (en3, OUTPUT);
pinMode (en4, OUTPUT);
pinMode (enb, OUTPUT);
}
void loop() {
joyValue1 = analogRead(potPin1); //reads value of y axis potenciometer
joyValue2 = analogRead(potPin2);// reads value of x axis potentiometer
//straight forward
if (joyValue1 >= joyValueMidUpper && joyValue2 <= joyValueMidUpper && joyValue2 >= joyValueMidLower) {//this uses the "tolerance" values to set a course in which both motors will reliably operate with the same strengh without fluctiations
motorSpeed1 = map(joyValue1, joyValueMidUpper, joyValueMax, motorSpeedMin, motorMaxHigh); //map function that translates joystick readings to pwm input
MotorForward1 (motorSpeed1);
motorSpeed2 = map (joyValue1, joyValueMidUpper, joyValueMax, motorSpeedMin, motorMaxHigh);
MotorForward2 (motorSpeed2);
digitalWrite (en1, LOW);
digitalWrite (en2, HIGH);
digitalWrite (en3, LOW);
digitalWrite (en4, HIGH);
}
else if (joyValue1 <= joyValueMidLower && joyValue2 <= joyValueMidUpper && joyValue2 >= joyValueMidLower) {//staight backwards reverse
motorSpeed1 = map(joyValue1, joyValueMidLower, joyValueMin, motorSpeedMin, motorMaxHigh);
MotorForward1 (motorSpeed1);
motorSpeed2 = map (joyValue1, joyValueMidLower, joyValueMin, motorSpeedMin, motorMaxHigh);
MotorForward2 (motorSpeed2);
digitalWrite (en1, HIGH);
digitalWrite (en2, LOW);
digitalWrite (en3, HIGH);
digitalWrite (en4, LOW);
}
else if (joyValue1 <= joyValueMidUpper && joyValue1 >= joyValueMidLower && joyValue2 >= joyValueMidUpper ) {// pivot steer right
motorSpeed2 = map(joyValue2, joyValueMidUpper, joyValueMax, motorSpeedMin, motorMaxHigh);//while in the pivot steer range the opposite motor will be shut off
MotorSides2 (motorSpeed2);
digitalWrite (en1, HIGH);
digitalWrite (en2, HIGH);
digitalWrite (en3, LOW);
digitalWrite (en4, HIGH);
}
else if (joyValue1 <= joyValueMidUpper && joyValue1 >= joyValueMidLower && joyValue2 <= joyValueMidLower ) {//pivot steer left
motorSpeed1 = map(joyValue2, joyValueMidLower, joyValueMin, motorSpeedMin, motorMaxHigh);
MotorSides1 (motorSpeed1);
digitalWrite (en1, LOW);
digitalWrite (en2, HIGH);
digitalWrite (en3, HIGH);
digitalWrite (en4, HIGH);
}
else if (joyValue2 > joyValueMidUpper && joyValue1 > joyValueMidUpper ){
motorSpeed2 = map(joyValue2, joyValueMidUpper, joyValueMax, motorSpeedMin, motorMaxHigh);// has you can see the left and right motors have got their map function mirrored
MotorSides2 (motorSpeed2);//this way, the more to the right the controller stick is, the stronger the left motor is and the weaker the right motor is
motorSpeed1 = map(joyValue2, joyValueMax, joyValueMidUpper, motorSpeedMin, motorMaxHigh);
MotorSides1 (motorSpeed1);
digitalWrite (en1, LOW);
digitalWrite (en2, HIGH);
digitalWrite (en3, LOW);
digitalWrite (en4, HIGH);
}
else if (joyValue2 < joyValueMidLower && joyValue1 > joyValueMidUpper ){//diagonal northwest
motorSpeed2 = map(joyValue2, joyValueMin, joyValueMidLower, motorSpeedMin, motorMaxHigh);
MotorSides2 (motorSpeed2);
motorSpeed1 = map(joyValue2, joyValueMidLower, joyValueMin, motorSpeedMin, motorMaxHigh);
MotorSides1 (motorSpeed1);
digitalWrite (en1, LOW);
digitalWrite (en2, HIGH);
digitalWrite (en3, LOW);
digitalWrite (en4, HIGH);
}
else if (joyValue2 < joyValueMidLower && joyValue1 < joyValueMidLower) {// diagonal southwest
motorSpeed2 = map(joyValue2, joyValueMin, joyValueMidLower, motorSpeedMin, motorMaxHigh);
MotorSides2 (motorSpeed2);
motorSpeed1 = map(joyValue2, joyValueMidLower, joyValueMin, motorSpeedMin, motorMaxHigh);
MotorSides1 (motorSpeed1);
digitalWrite (en1, HIGH);
digitalWrite (en2, LOW);
digitalWrite (en3, HIGH);
digitalWrite (en4, LOW);
}
else if (joyValue2 > joyValueMidUpper && joyValue1 < joyValueMidLower) {// diagonal southeast
motorSpeed2 = map(joyValue2, joyValueMidUpper, joyValueMax, motorSpeedMin, motorMaxHigh);
MotorSides2 (motorSpeed2);
motorSpeed1 = map(joyValue2, joyValueMax, joyValueMidUpper, motorSpeedMin, motorMaxHigh);
MotorSides1 (motorSpeed1);
digitalWrite (en1, HIGH);
digitalWrite (en2, LOW);
digitalWrite (en3, HIGH);
digitalWrite (en4, LOW);
}
else { digitalWrite (en1, LOW); //idle mode
digitalWrite (en2, LOW);
digitalWrite (en3, LOW);
digitalWrite (en4, LOW);
}
}
void MotorForward1(byte Spd){
analogWrite(ena, Spd);}//this function is the one that actually inputs the pwm commands to the motors
void MotorForward2(byte Spd) {
analogWrite(enb, Spd);
}
void MotorSides1 (byte Spd){// these two "motorSides" functions do the exact same thing has the "motorForward" functions and are intechangeable with them
analogWrite(ena, Spd);}//but they help me distinguish what function does what more quickly so I keep them
void MotorSides2 (byte Spd){
analogWrite(enb, Spd);
}
I know I'm not too good at explaining myself but I really am trying. If there's any confusion ask me about it and I'll try to clarify it the best way I can.