Go Down

Topic: controlar motor dc usando mando ps2 wireless (Read 122 times) previous topic - next topic

julenlen

Hola, estoy intentando construir un pequeño rover con motores dc y controlarlo con un mando de ps2 genérico.

Tengo el tema de hardware resuelto con un integrado L293D y conseguí establecer los sentidos de giro sin problemas.

Mi dificultad está relacionada con la programación del mando. Busqué en el foro soluciones similares a mi problema pero no encontré nada similar a lo que necesito, disculpas si pasé algo por alto.

Estoy utilizando la librería PS2X_lib.h descargada de aquí

Tras bastante lucha para conectar el mando conseguí hacerlo funcionar alimentando el receptor con 3,3v desde una placa Arduino UNO clónica, con una resistencia de 1K en pull-up en DATA y cambiando  #define CTRL_CLK  4 por #define CTRL_CLK 20

Estoy usando el programa  PS2X_Example que adjunto a continuación. Funciona  bien y recibo por el puerto serie lo esperado al pulsar los distintos botones.

Code: [Select]
#include <PS2X_lib.h>  //for v1.6


#define PS2_DAT        13      
#define PS2_CMD        11  
#define PS2_SEL        10  
#define PS2_CLK        12

#define pressures   false
#define rumble      false

PS2X ps2x; // create PS2 Controller Class


int error = 0;
byte type = 0;
byte vibrate = 0;

void setup(){
 
  Serial.begin(57600);
  
  delay(300);  //added delay to give wireless ps2 module some time to startup, before configuring it
  
    
   error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble);
  
  if(error == 0){
    Serial.print("Found Controller, configured successful ");
    Serial.print("pressures = ");
 if (pressures)
  Serial.println("true ");
 else
  Serial.println("false");
 Serial.print("rumble = ");
 if (rumble)
  Serial.println("true)");
 else
  Serial.println("false");
    Serial.println("Try out all the buttons...");
    Serial.println("holding L1 or R1 will print out the analog stick values.");
    Serial.println("Note: Go to www.billporter.info ....");
  }  
  else if(error == 1)
    Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips");
  
  else if(error == 2)
    Serial.println("Controller found but not accepting commands.");

  else if(error == 3)
    Serial.println("Controller refusing to enter Pressures mode, may not support it. ");
  
//  Serial.print(ps2x.Analog(1), HEX);
  
  type = ps2x.readType();
  switch(type) {
    case 0:
      Serial.print("Unknown Controller type found ");
      break;
    case 1:
      Serial.print("DualShock Controller found ");
      break;
    case 2:
      Serial.print("GuitarHero Controller found ");
      break;
 case 3:
      Serial.print("Wireless Sony DualShock Controller found ");
      break;
   }
}

void loop() {
  /* You must Read Gamepad to get new values and set vibration values
     ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255)
     if you don't enable the rumble, use ps2x.read_gamepad(); with no values
     You should call this at least once a second
   */  
  if(error == 1) //skip loop if no controller found
    return;
  
  if(type == 2){ //Guitar Hero Controller
    ps2x.read_gamepad();          //read controller
  
    if(ps2x.ButtonPressed(GREEN_FRET))
      Serial.println("Green Fret Pressed");
    if(ps2x.ButtonPressed(RED_FRET))
      Serial.println("Red Fret Pressed");
    if(ps2x.ButtonPressed(YELLOW_FRET))
      Serial.println("Yellow Fret Pressed");
    if(ps2x.ButtonPressed(BLUE_FRET))
      Serial.println("Blue Fret Pressed");
    if(ps2x.ButtonPressed(ORANGE_FRET))
      Serial.println("Orange Fret Pressed");

    if(ps2x.ButtonPressed(STAR_POWER))
      Serial.println("Star Power Command");
    
    if(ps2x.Button(UP_STRUM))        
      Serial.println("Up Strum");
    if(ps2x.Button(DOWN_STRUM))
      Serial.println("DOWN Strum");
 
    if(ps2x.Button(PSB_START))        
      Serial.println("Start is being held");
    if(ps2x.Button(PSB_SELECT))
      Serial.println("Select is being held");
    
    if(ps2x.Button(ORANGE_FRET)) {    
      Serial.print("Wammy Bar Position:");
      Serial.println(ps2x.Analog(WHAMMY_BAR), DEC);
    }
  }
  else { //DualShock Controller
    ps2x.read_gamepad(false, vibrate); //read controller and set large motor to spin at 'vibrate' speed
    
    if(ps2x.Button(PSB_START))         //will be TRUE as long as button is pressed
      Serial.println("Start is being held");
    if(ps2x.Button(PSB_SELECT))
      Serial.println("Select is being held");      

    if(ps2x.Button(PSB_PAD_UP)) {      
      Serial.print("Up held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC);
    }
    if(ps2x.Button(PSB_PAD_RIGHT)){
      Serial.print("Right held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC);
    }
    if(ps2x.Button(PSB_PAD_LEFT)){
      Serial.print("LEFT held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC);
    }
    if(ps2x.Button(PSB_PAD_DOWN)){
      Serial.print("DOWN held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC);
    }  

    vibrate = ps2x.Analog(PSAB_CROSS);  //this will set the large motor vibrate speed based on how hard you press the blue (X) button
    if (ps2x.NewButtonState()) {        //will be TRUE if any button changes state (on to off, or off to on)
      if(ps2x.Button(PSB_L3))
        Serial.println("L3 pressed");
      if(ps2x.Button(PSB_R3))
        Serial.println("R3 pressed");
      if(ps2x.Button(PSB_L2))
        Serial.println("L2 pressed");
      if(ps2x.Button(PSB_R2))
        Serial.println("R2 pressed");
      if(ps2x.Button(PSB_TRIANGLE))
        Serial.println("Triangle pressed");        
    }

    if(ps2x.ButtonPressed(PSB_CIRCLE))               //will be TRUE if button was JUST pressed
      Serial.println("Circle just pressed");
    if(ps2x.NewButtonState(PSB_CROSS))               //will be TRUE if button was JUST pressed OR released
      Serial.println("X just changed");
    if(ps2x.ButtonReleased(PSB_SQUARE))              //will be TRUE if button was JUST released
      Serial.println("Square just released");    

    if(ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) { //print stick values if either is TRUE
      Serial.print("Stick Values:");
      Serial.print(ps2x.Analog(PSS_LY), DEC); //Left stick, Y axis. Other options: LX, RY, RX  
      Serial.print(",");
      Serial.print(ps2x.Analog(PSS_LX), DEC);
      Serial.print(",");
      Serial.print(ps2x.Analog(PSS_RY), DEC);
      Serial.print(",");
      Serial.println(ps2x.Analog(PSS_RX), DEC);
    }    
  }
  delay(50);  
}


Mi intención es asociar los valores máximos y mínimos de los ejes Y de los sticks para controlar por separado el sentido de giro de los motores izquierdo y derecho.

Al comprobar con el monitor serie el rango de valores este varía de 0 a 255 y en reposo arroja 128.

He colocado el siguiente código justo antes del bloque que permite ver los valores analógicos al pulsar L1 o R1.

Code: [Select]
if (ps2x.ButtonPressed(PSB_CIRCLE))              
      Serial.println("Circle just pressed");
    if (ps2x.NewButtonState(PSB_CROSS))            
      Serial.println("X just changed");
    if (ps2x.ButtonReleased(PSB_SQUARE))            
      Serial.println("Square just released");

    /////CONTROL LADO IZQUIERDO

    if ((ps2x.Analog(PSS_LY), DEC) < 1) {
      Serial.println ("Adelante");
      delay(500);
    }
    if ((ps2x.Analog(PSS_LY), DEC) > 254) {
      Serial.println ("ATRÁS");
      delay(500);
    }
    ////////

    if (ps2x.Button(PSB_L1)) { //print stick values if either is TRUE
      // if(ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) { //print stick values if either is TRUE
      Serial.print("Stick Values:");
      Serial.print(ps2x.Analog(PSS_LY), DEC); //Left stick, Y axis. Other options: LX, RY, RX
      Serial.print(",");
      Serial.print(ps2x.Analog(PSS_LX), DEC);
      Serial.print(",");
      Serial.print(ps2x.Analog(PSS_RY), DEC);
      Serial.print(",");
      Serial.println(ps2x.Analog(PSS_RX), DEC);
    }

  }

  delay(50);
}


Tras subirlo al arduino todo el comportamiento original se mantiene pero cuando muevo el joystick arriba o abajo no obtengo nada en monitor serie.

He probado con este otro código

Code: [Select]


    if ((ps2x.Analog(PSS_LY), DEC) < 128) {
      Serial.println ("Adelante");
      delay(500);
    }
    if ((ps2x.Analog(PSS_LY), DEC) > 128) {
      Serial.println ("ATRÁS");
      delay(500);
    }


y entonces por monitor serie aparece Adelante en intervalos de medio segundo y no funciona ninguno de los otros botones.

Agradecería cualquier sugerencia.
Muchas gracias.

surbyte

Es que poner dos pausas de 500 mseg suman 1000 mseg o 1 segundo, cuando esperas que se perciba si presionas botones o no?

Tu solución es ir a documentación, indice de temas tutoriales y reemplazar delay x millis()

julenlen

Lo primero, he visto que tuviste que mover el post porque estaba mal publicado, lo siento y en lo sucesivo seré más cuidadoso con ello.
En cuanto a la solución que propones, le daré una buena leída en la dirección que apuntas y comento los resultados obtenidos.
Gracias por tu sugerencia.

julenlen

Hola de nuevo, perdón por la demora en volver a responder.
He estado leyendo las diferencias entre delay() y millis() y creo haber entendido por qué es más adecuado el uso de este último. Si entendí bien la función milis() no pausa la ejecución del programa, por lo que en un escenario en el que estamos enviando valores analógicos que pueden cambiar de forma constante la respuesta será mejor.

He introducido los siguientes cambios en el programa de ejemplo. Primero con un botón que funciona como un while. El resultado es el esperado; al pulsar "botón arriba"en el mando de forma continuada recibo por el monitor serie el mensaje programado con un retardo mayor que en los botones que no lo incluyen.

A continuación he asociado el mismo código al joystick del mando, inicialmente no funcionó, pero he conseguido una respuesta razonable con el código que adjunto.

Code: [Select]
/////CONTROL LADO IZQUIERDO

    if (ps2x.Analog(PSS_LY) < 100) {
      /////AÑADIMOS EL CONDICIONAL DE MILIS
      tiempo2 = millis();
      if (tiempo2 > (tiempo1 + 100)) { //Si ha pasado 1 segundo ejecuta el IF
        tiempo1 = millis(); //Actualiza el tiempo actual
        //tiempoSegundos = tiempo1 / 1000;

        Serial.println ("Adelante");
      }
    }

    if (ps2x.Analog(PSS_LY) > 200) {
      Serial.println ("ATRÁS");

    }
    ////////


Funciona tanto con la pausa como sin ella, por lo que me inclino a pensar que el problema estaba en la determinación de los rangos que parecen no coincidir con los esperados conforme a lo que mostraba el monitor serie y en el formateo decimal, ya que el anterior código

Code: [Select]
/////CONTROL LADO IZQUIERDO

    if (ps2x.Analog(PSS_LY),DEC < 100) {
      /////AÑADIMOS EL CONDICIONAL DE MILIS
      tiempo2 = millis();
      if (tiempo2 > (tiempo1 + 100)) { //Si ha pasado 1 segundo ejecuta el IF
        tiempo1 = millis(); //Actualiza el tiempo actual
        //tiempoSegundos = tiempo1 / 1000;

        Serial.println ("Adelante");
      }
    }

    if (ps2x.Analog(PSS_LY),DEC > 200) {
      Serial.println ("ATRÁS");

    }


provoca un volcado continuo del mensaje "adelante" por el monitor serie incluso con el joystick en posición de reposo.

Quedo a la espera de cualquier corrección o sugerencia que crean oportuna para renombrar el hilo como solucionado.

Un saludo y gracias.

Go Up