Go Down

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

HazardsMind

#30
Sep 15, 2013, 08:19 pm Last 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
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

zoomkat

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.
Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

HazardsMind

I'll post the full working code later when I get home.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

HazardsMind

#33
Sep 17, 2013, 01:09 am Last 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 center
unsigned int Xspeed = 0, Yspeed = 0; //motor speed default 0 for full stop
const int Xdeadzone = 5, Ydeadzone = 5; //amount of slack needed for pot values

void 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);
    }
  }
}

My GitHub:
https://github.com/AndrewMascolo?tab=repositories

zoomkat

Quote
Simple motor control with square limit joystick


I assume this means no diagonal stick movement. Correct?
Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

HazardsMind

#35
Sep 17, 2013, 05:19 am Last 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.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

thegrid

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 center
unsigned int Xspeed = 0, Yspeed = 0; //motor speed default 0 for full stop
const int Xdeadzone = 5, Ydeadzone = 5; //amount of slack needed for pot values

void 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

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

I want to use servo and radio functions but the includs are incompatible.
Has some one resolve the problem.
Thanks

jp31310

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.

Please help me if you can.

thank a lot,

jp

jp31310

My code for my robot projet is:
// Librairie Adafruit
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_MotorShield monShield = Adafruit_MotorShield(); //création de l'objet shield
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
lecX = analogRead(x);
lecY = analogRead(y);
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void loop() {

// Calibration du joystick en 0,0
calX = analogRead(x)-lecX;
calY = analogRead(y)-lecY;

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

Quote
My code for my robot projet is:
Please read #7 below and put your code in code tags:

http://forum.arduino.cc/index.php/topic,148850.0.html
Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

drazha

@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...

cr0sh

#43
Mar 08, 2016, 03:17 pm Last 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.

cr0sh

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
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy