Go Down

Topic: 2 motors controlled by one joystick (Read 43003 times)previous topic - next topic

HazardsMind

#30
Sep 15, 2013, 08:19 pmLast Edit: Sep 15, 2013, 08:30 pm by HazardsMind Reason: 1
Its actually very simple. A pot has a range from 0 - 1023, and being that you want to control a motor or servo, you will most likely want full forward, full reverse and stop.
Well forward is equal to anything above 512(mid point of pot), and reverse is anything below 512. Now you also want to stop the motor, and that done when your at 512.
So you will need an IF statement.

psudo:

Code: [Select]
`int XSpeed = analogRead( XpotPin );if ( XSpeed > (512 + deadzone) ) //go forward...else if ( XSpeed < (512 - deadzone) ) //go reverse ...else //XSpeed = 512 +- deadzone, stop`
deadzone is needed because your pot will almost never perfectly be centered at 512, so some slack is needed

zoomkat

#31
Sep 16, 2013, 07:16 pm
Quote
Its actually very simple.

Can you post the combined working code? The problem is solvable to a certain extent, but I haven't seen single code (that I understand) that provides forward/reverse and  left/right from a joystick, especially if the stick is pushed in a diagonal direction. I currently do any actual testing with pots and servos as my hardware is currently disconnected and in various places.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

HazardsMind

#32
Sep 16, 2013, 07:26 pm
I'll post the full working code later when I get home.

HazardsMind

#33
Sep 17, 2013, 01:09 amLast Edit: Sep 17, 2013, 01:13 am by HazardsMind Reason: 1
Ok, I have here the simplest form of single joystick control. It by default assumes that the motor pins have pull down resistors, but if you don't have pull down resistors, then just uncomment the other lines.

Code: [Select]
`/*Simple motor control with square limit joystick      Y(1023)    |---------|    |---------|X(0)|---512---|X(1023)    |---------|    |---------|       Y(0)        Left Motor Forward/Reverse = LMF/LMR Right Motor Forward/Reverse = RMF/RMR*/const byte LMF = 3;const byte LMR = 5;const byte RMF = 6;const byte RMR = 9;const byte Xpot = A0;const byte Ypot = A1; volatile unsigned int X = 512, Y = 512; // pot values default 512 for centerunsigned int Xspeed = 0, Yspeed = 0; //motor speed default 0 for full stopconst int Xdeadzone = 5, Ydeadzone = 5; //amount of slack needed for pot valuesvoid setup(){  pinMode(LMF, OUTPUT);  pinMode(LMR, OUTPUT);  pinMode(RMF, OUTPUT);  pinMode(RMR, OUTPUT);  Serial.begin(9600);}void loop(){  X = analogRead(Xpot);  Y = analogRead(Ypot);  if (X >= (512 + Xdeadzone))//Forward  {     Xspeed = (X - 512) / 2; // 0 - 255    if(Y > (512 + Ydeadzone)) //Left    {      Yspeed = (Y - 512) / 2;      analogWrite(LMF, Xspeed - Yspeed); analogWrite(RMF, Xspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }    else if (Y < (512 - Ydeadzone)) //Right    {      Yspeed = (512 - Y) / 2;      analogWrite(LMF, Xspeed); analogWrite(RMF, Xspeed - Yspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }    else    {      analogWrite(LMF, Xspeed); analogWrite(RMF, Xspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }  }  else if (X <= (512 - Xdeadzone))//Reverse  {     Xspeed = (512 - X) / 2;    if(Y > (512 + Ydeadzone)) //Left    {      Yspeed = (Y - 512) / 2;      //digitalWrite(LMF, LOW); digitalWrite(RMF, LOW);      analogWrite(LMR, Xspeed - Yspeed); analogWrite(RMR, Xspeed);    }    else if (Y < (512 - Ydeadzone)) //Right    {      Yspeed = (512 - Y) / 2;      //digitalWrite(LMF, LOW); digitalWrite(RMF, LOW);      analogWrite(LMR, Xspeed); analogWrite(RMR, Xspeed - Yspeed);    }    else    {      //digitalWrite(LMF, LOW); digitalWrite(RMF, LOW);      analogWrite(LMR, Xspeed); analogWrite(RMR, Xspeed);    }  }  else // X is between 512 +- deadzone  {    if(Y > (512 + Ydeadzone)) // zero point turn Left    {      digitalWrite(LMF, LOW); analogWrite(RMF, Yspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }    else if(Y < (512 - Ydeadzone))// zero point turn Right    {      analogWrite(LMF, Yspeed); digitalWrite(RMF, LOW);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);     }    else    { // Full stop      digitalWrite(LMF,LOW);      digitalWrite(RMF,LOW);      digitalWrite(LMR,LOW);      digitalWrite(RMR,LOW);    }  }}`

zoomkat

#34
Sep 17, 2013, 05:06 am
Quote
Simple motor control with square limit joystick

I assume this means no diagonal stick movement. Correct?
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

HazardsMind

#35
Sep 17, 2013, 05:19 amLast Edit: Sep 17, 2013, 10:42 pm by HazardsMind Reason: 1
This use every position, which includes diagonal.

I called it square limit because the older joysticks like the Atari joystick have a square range. But the current ones like those used on ps2 controller, xbox, or anything else that uses a joystick, has a round limit. These I think need to use sine and cosine to get there full range of movement. I'll do some tests to confirm if that's true or not, later.

Atari joystick:
http://en.wikipedia.org/wiki/File:Joyopis.svg

The one I posted earlier is the one I am currently using, and it works for diagonal positions too. The only difference is that the first one uses the map function, whereas this one is straight forward using IF ELSE to take the difference of X and Y positions to go a certain direction.

The first one I posted is neater but a little more confusing, compared to this "simpler" code that breaks it all down. Not as nice but not as confusing.

thegrid

#36
Feb 20, 2014, 12:52 pm
so this is the working combined code?

Code: [Select]
`/*Simple motor control with square limit joystick      Y(1023)    |---------|    |---------|X(0)|---512---|X(1023)    |---------|    |---------|       Y(0)        Left Motor Forward/Reverse = LMF/LMR Right Motor Forward/Reverse = RMF/RMR*/const byte LMF = 3;const byte LMR = 5;const byte RMF = 6;const byte RMR = 9;const byte Xpot = A0;const byte Ypot = A1; volatile unsigned int X = 512, Y = 512; // pot values default 512 for centerunsigned int Xspeed = 0, Yspeed = 0; //motor speed default 0 for full stopconst int Xdeadzone = 5, Ydeadzone = 5; //amount of slack needed for pot valuesvoid setup(){  pinMode(LMF, OUTPUT);  pinMode(LMR, OUTPUT);  pinMode(RMF, OUTPUT);  pinMode(RMR, OUTPUT);  Serial.begin(9600);}void loop(){  X = analogRead(Xpot);  Y = analogRead(Ypot);  if (X >= (512 + Xdeadzone))//Forward  {     Xspeed = (X - 512) / 2; // 0 - 255    if(Y > (512 + Ydeadzone)) //Left    {      Yspeed = (Y - 512) / 2;      analogWrite(LMF, Xspeed - Yspeed); analogWrite(RMF, Xspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }    else if (Y < (512 - Ydeadzone)) //Right    {      Yspeed = (512 - Y) / 2;      analogWrite(LMF, Xspeed); analogWrite(RMF, Xspeed - Yspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }    else    {      analogWrite(LMF, Xspeed); analogWrite(RMF, Xspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }  }  else if (X <= (512 - Xdeadzone))//Reverse  {     Xspeed = (512 - X) / 2;    if(Y > (512 + Ydeadzone)) //Left    {      Yspeed = (Y - 512) / 2;      //digitalWrite(LMF, LOW); digitalWrite(RMF, LOW);      analogWrite(LMR, Xspeed - Yspeed); analogWrite(RMR, Xspeed);    }    else if (Y < (512 - Ydeadzone)) //Right    {      Yspeed = (512 - Y) / 2;      //digitalWrite(LMF, LOW); digitalWrite(RMF, LOW);      analogWrite(LMR, Xspeed); analogWrite(RMR, Xspeed - Yspeed);    }    else    {      //digitalWrite(LMF, LOW); digitalWrite(RMF, LOW);      analogWrite(LMR, Xspeed); analogWrite(RMR, Xspeed);    }  }  else // X is between 512 +- deadzone  {    if(Y > (512 + Ydeadzone)) // zero point turn Left    {      digitalWrite(LMF, LOW); analogWrite(RMF, Yspeed);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);    }    else if(Y < (512 - Ydeadzone))// zero point turn Right    {      analogWrite(LMF, Yspeed); digitalWrite(RMF, LOW);      //digitalWrite(LMR, LOW); digitalWrite(RMR, LOW);     }    else    { // Full stop      digitalWrite(LMF,LOW);      digitalWrite(RMF,LOW);      digitalWrite(LMR,LOW);      digitalWrite(RMR,LOW);    }  }}`

drazha

#37
Mar 03, 2016, 06:52 pm
Hi all,

I have run the code that HazardsMind has posted manually, and as far as I can see it is not doing what it is supposed to do?!

Did anyone actually load this into the Arduino, with a Left DC Motor and Right DC motor, and got it to move forward when you push Y up, backwards when you push Y down, and turn left-right when X is pushed left-right?

jpl-pfungst

#38
Mar 03, 2016, 07:07 pm
I want to use servo and radio functions but the includs are incompatible.
Has some one resolve the problem.
Thanks

jp31310

#39
Mar 04, 2016, 12:01 pm
I
I am french and I have a same problem with arduino and motorshield adafruit.

I try to control a robot with a joystick.

I can control 2 motors directly and I can get the location of the joystick with a switch cas. But I can't connect both to conduct my robot.

thank a lot,

jp

jp31310

#40
Mar 04, 2016, 12:09 pm
My code for my robot projet is:
#include <Wire.h>

Adafruit_DCMotor *moteurGauche = monShield.getMotor(1); //création de l'objet moteurGauche par pointeur et repérage du numéro
Adafruit_DCMotor *moteurDroite = monShield.getMotor(2); //création de l'objet moteurDroite par pointeur et repérage du numéro

// Branchement joystick et moteur
const int x = A0;
const int xMin = 0;
const int xMax = 1023;
const int y = A4;
const int yMin = 0;
const int yMax = 1023;
int neut = 20; // zone neutre
int neutn = -20; // zone neutre négative

int zone;
int zone_val;

// Définition des variables
int lecX, lecY, calX, calY, retX, retY, vit;

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
void setup () {
// Initialisation port serie
Serial.begin(9600);
AFMS.begin();
zone_val = 10;
zone = 10;
// Lecture des valeurs en x et y
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void loop() {

// Calibration du joystick en 0,0

Serial.print("+++++++> valeur_calX :") && Serial.println (calX);
Serial.print("+++++++> valeur_calY :") && Serial.println (calY);
delay (100);

/*
Serial.print("SENS INITIAL MOTEUR 1 RELEASE++++++> :")&&Serial.println (sensM1);
Serial.print("SENS INITIAL MOTEUR 2 RELEASE++++++> :")&&Serial.println (sensM2);
Serial.print("SENS TEST MOTEUR 3 FORWARD++++++> :")&&Serial.println (sensM3);

delay (1000);

//sensM1 = "FORWARD";
//sensM2 = "FORWARD";
//Serial.print("SENS MOTEUR 1 FORWARD++++++> :") && Serial.println ('sensM1');
//Serial.print("SENS MOTEUR 2 FORWARD++++++> :") && Serial.println ('sensM2');
delay(1000);
*/

// Réatalonnage x et y de 0,1023 à -255,255
//Ré-étalonne la valeur entre 0 et 1023 sur une fourchette entre 0 et 255
retX = map(calX, xMin, xMax, -255 , 255);
retX= constrain(calX, -255, 255);
retY = map(calY, yMin, yMax, -255, 255);
retY = constrain(calY, -255, 255);

Serial.print("=======> valeur_X :") && Serial.println (retX);
Serial.print("=======> valeur_Y :") && Serial.println (retY);
delay (100);

if ((abs(retX)) > (abs(retY)))
{
vit = (abs(retX));
}
else
{
vit = (abs(retY));
}
//++++++++++++++++++

calcul_zone(retX, retY);
Serial.println("POSITION JOYSTICK case valeur :");
Serial.print("======> valeur_X :") && Serial.println (retX);
Serial.print("=======> valeur_Y :") && Serial.println (retY);
delay(100);

Serial.print("ZONE VAL ======> :") && Serial.println(zone);
delay(100);

Serial.println("BONJOUR");
impression(zone);
delay(2000);
ACTION_MOTOR(zone);
//delay(500);
//arret();
//delay(2000);
//Serial.print("ZONE VAL ======> :") && Serial.println(zone_val);
Serial.println("AU REVOIR");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~é
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// CALCUL DE ZONE PAR RAPPORT A LA POSITION JOYSTICK (RetX, RetY);

void calcul_zone(int XX, int YY)
{
if (YY <= neutn)
{
if (XX >= neut){zone = 4;}
if (XX <= neutn){zone = 6;}
if ((XX < neut) && (XX > neutn)) {zone = 5;}
}
if (YY >= neut)
{
if (XX >= neut){zone = 2;}
if (XX <= neutn){zone = 8;}
if ((XX < neut) && (XX > neutn)) {zone = 1;}
}
if ((YY > neutn) && (YY < neut))
{
if (XX >= neut){zone = 3;}
if (XX <= neutn){zone = 7;}
if ((XX < neut) && (XX > neutn)) {zone = 0;}
}
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@à
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&++++++++++++++++++++++++++++++++++++++++++++++++++
void arret(){
//fonction d'arrêt des deux moteurs
moteurGauche->run(RELEASE);
moteurDroite->run(RELEASE);
}
void defVitesse(int v){
moteurGauche->setSpeed(v); //on redéfinit la vitesse
moteurDroite->setSpeed(v); //des deux moteurs
}
void avance(int v){
//fonction de marche avant
//defVitesse(v);
moteurGauche->setSpeed(v);
moteurDroite->setSpeed(v);
//appel de la fonction pour définir la vitesse
moteurGauche->run(FORWARD);
moteurDroite->run(FORWARD);
}
void recule(int v){
//fonction de marche arrière
defVitesse(v);
moteurGauche->run(BACKWARD);
moteurDroite->run(BACKWARD);
}
void tourneDroite(int v){
//fonction pour tourner à droite sur place
defVitesse(v);
moteurGauche->run(FORWARD);
moteurDroite->run(BACKWARD);
}
void tourneGauche(int v){
//fonction pour tourner à gauche sur place
defVitesse(v);
moteurGauche->run(BACKWARD);
moteurDroite->run(FORWARD);
}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&++++++++++++++++++++++++++++++++++++++++++++++++
//§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
void impression(int zone)
{
switch (zone)
{
case 0:
Serial.println("Robot STOP");
break;
case 1:
Serial.println("Robot AVANCE");
delay(10);
break;
case 2:
Serial.println("Robot AVANCE et TOURNE à GAUCHE");
break;
case 3:
Serial.println("Robot TOURNE à GAUCHE toute");
break;
case 4:
Serial.println("Robot RECULE et TOURNE à GAUCHE");
break;
case 5:
Serial.println("Robot RECULE");
break;
case 6:
Serial.println("Robot RECULE et TOURNE à DROITE");
break;
case 7:
Serial.println("Robot TOURNE à DROITE toute");
break;
case 8:
Serial.println("Robot AVANCE et TOURNE à DROITE");
break;
default:
break;
}
}
//§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
//:::::::::::::::::::::::::::::::::::::::::::::::::
void ACTION_MOTOR(int zone)
{
switch (zone)
{
case 0:
Serial.println("ACTION MOTOR Robot STOP");
arret();
break;
case 1:
Serial.println("ACTION MOTOR Robot AVANCE");
avance(100);
delay(500);
arret();
break;
case 2:
Serial.println("ACTION MOTOR Robot AVANCE et TOURNE à GAUCHE");
break;
case 3:
Serial.println("ACTION MOTOR Robot TOURNE à GAUCHE toute");
break;
case 4:
Serial.println("ACTION MOTOR Robot RECULE et TOURNE à GAUCHE");
break;
case 5:
Serial.println("ACTION MOTOR Robot RECULE");
break;
case 6:
Serial.println("ACTION MOTOR Robot RECULE et TOURNE à DROITE");
break;
case 7:
Serial.println("ACTION MOTOR Robot TOURNE à DROITE toute");
break;
case 8:
Serial.println("ACTION MOTOR Robot AVANCE et TOURNE à DROITE");
break;
default:
break;
}
}

//:::::::::::::::::::::::::::::::::::::::::::::::::::

zoomkat

#41
Mar 04, 2016, 07:48 pm
Quote
My code for my robot projet is:

http://forum.arduino.cc/index.php/topic,148850.0.html
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

drazha

#42
Mar 08, 2016, 11:07 am
@jp31310: I did not go into detail with your code, but I think we are in the same line of thought: I have defined "quadrants" and based on the "quadrant" different logic takes place.

You can find my code here: https://github.com/drazha/Son-Dad-Rover-Mk-I

It is a bit messy and requires refactoring, but the general idea is there...

keeper63

#43
Mar 08, 2016, 03:17 pmLast Edit: Mar 08, 2016, 03:18 pm by cr0sh
Can you post the combined working code? The problem is solvable to a certain extent, but I haven't seen single code (that I understand) that provides forward/reverse and  left/right from a joystick, especially if the stick is pushed in a diagonal direction. I currently do any actual testing with pots and servos as my hardware is currently disconnected and in various places.
Does my logic - see posts #4 and #5 at:

http://forum.arduino.cc/index.php?topic=172581.0

...not work? The OP seemed to think it worked.

I mean - if it doesn't work, I'd certainly like to know - but the logic seems sound.
I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

keeper63

#44
Mar 08, 2016, 03:31 pm
deadzone is needed because your pot will almost never perfectly be centered at 512, so some slack is needed
For many (most? all?) of the PS2 style thumbsticks - they have a "built-in" deadzone around the center of the stick (in some cases I have heard it is quite large - almost to the point of making the stick unusable). Just something to keep in mind; it should be possible to figure out what the size of the zone is with some test code.

Alternatively, if you have a display available (serial or maybe an LCD) - you could create a "calibration code" section for the thumbstick like the old PC games used that would instruct you to push the stick up to one corner, push it down to the opposite corner, perhaps move it around in a circle, then center it - at each step instructing you to "press a button" (and don't make this the "stick button" that many of these units have - as that could throw off the reading - though with the deadzone it may be ok - eh, play with it). It might even be possible to do the calibration with an LED and some "intelligent" code (and/or a buzzer or something?).
I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

Go Up