Ps2 controller exploitation des données joysticks

oui vous allez faire sans doute en premier jet une structure comme cela

struct message_t {
  byte LX;
  byte LY;
  byte RX;
  byte RY;
  bool V_PSB_L1;
  bool V_PSB_L2;
  bool V_PSB_R1;
  bool V_PSB_R2;
  bool V_PSB_SQUARE;
} message;

et vous mettrez dans message.LX la valeur lue par l'appel à ps2x.Analog(PSS_LX) (idem pour les autres) et pour les boutons true s'il est appuyé et false sinon (ce que retourne ps2x.Button(PSB_L1) par exemple pour message.PSB_L1 )

tenez, ça pourrait ressembler à cela (tapé ici, absolument pas testé)

#include <PS2X_lib.h> //for v1.6
// PS2 pins
const byte PS2_SEL          = 16;
const byte PS2_DAT          = 14;
const byte PS2_CMD          = 15;
const byte PS2_CLK          = 17;
PS2X ps2x;

struct __attribute__ ((packed)) t_donneesManette {
  byte LX;
  byte LY;
  byte RX;
  byte RY;
  bool V_PSB_L1;
  bool V_PSB_L2;
  bool V_PSB_R1;
  bool V_PSB_R2;
  bool V_PSB_SQUARE;
  bool V_PSB_CROSS;
};

t_donneesManette valeursPrecedentes = {127, 128, 127, 128, false, false, false, false, false, false};
t_donneesManette valeursMaintenant;

void setup() {
  Serial.begin(115200);
  delay(300); //added delay to give wireless ps2 module some time to startup, before configuring it

  int error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, true, true);
  switch (error) {
    case 0:   Serial.println(F("Found Controller, configured successful ")); break;
    case 1:   Serial.println(F("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips")); break;
    case 2:   Serial.println(F("Controller found but not accepting commands. see readme.txt to enable debug. Visit www.billporter.info for troubleshooting tips")); break;
    case 3:   Serial.println(F("Controller refusing to enter Pressures mode, may not support it.")); break;
    default:  Serial.println(F("Unknown Error")); break;
  }

  byte type = ps2x.readType();
  switch (type) {
    case 0:   Serial.print(F("Unknown Controller type found ")); break;
    case 1:   Serial.print(F("DualShock Controller found ")); break;
    case 2:   Serial.print(F("GuitarHero Controller found ")); break;
    case 3:   Serial.print(F("Wireless Sony DualShock Controller found ")); break;
    default:  Serial.println(F("Unknown Type")); break;
  }
}

void loop() {
  ps2x.read_gamepad();          //read controller
  valeursMaintenant.LY = ps2x.Analog(PSS_LY);
  valeursMaintenant.LX = ps2x.Analog(PSS_LX);
  valeursMaintenant.RY = ps2x.Analog(PSS_RY);
  valeursMaintenant.RX = ps2x.Analog(PSS_RX);
  valeursMaintenant.V_PSB_L1      = ps2x.Button(PSB_L1);
  valeursMaintenant.V_PSB_L2      = ps2x.Button(PSB_L2);
  valeursMaintenant.V_PSB_R1      = ps2x.Button(PSB_R1);
  valeursMaintenant.V_PSB_R2      = ps2x.Button(PSB_R2);
  valeursMaintenant.V_PSB_SQUARE  = ps2x.Button(PSB_SQUARE);
  valeursMaintenant.V_PSB_CROSS   = ps2x.ButtonPressed(PSB_CROSS);

  if (memcmp(&valeursMaintenant, &valeursPrecedentes, sizeof(t_donneesManette)) == 0) { // https://www.cplusplus.com/reference/cstring/memcmp/ (on a compacté la structure et ce ne sont que des octets donc ça doit être OK)
    // pas de changement
    // éventuellement envoi d'un "battement de coeur" pour dire que tout va bien mais rien de nouveau
  } else {
    // quelque chose a changé, envoyer la structure par radio

    // on mémorise la nouvelle configuration
    valeursPrecedentes = valeursMaintenant;
  }
  delay(50) ;
}

ce code lit l'état des joysticks et des boutons pertinents, les stocke dans la structure et compare avec l'état précédent. S'il y a une changement c'est là qu'il faudra émettre, s'il n'y a pas de changement alors on n'émet rien.

Par raison de sécurité on peut décider d'émettre quand même un message particulier s'il n'y a pas de changements de façon à ce que le module distant sache qu'il est toujours sous contrôle. On utilise cela comme un "battement de coeur" ➜ si le module distant ne reçoit aucun message pendant x secondes alors c'est que la connexion avec la base est rompue et le robot se met en position de sécurité (arrêt moteurs etc par exemple).

(on pourrait utiliser des champs de bits pour les boutons pour rendre la structure plus compacte - mais à conserver les optimisations pour plus tard :slight_smile: )

bonjour JML,
j'ai décortiqué et étudié ce code et je dois avouer que ça fait beaucoup d'infos d'un coup pour ma petite tête. Du coup j'ai un peu décroché et me suis mis sur l'électronique pour tester le robot en mode filaire( jusque là des moteurs "test" posé sur le bureau), je rencontre quelques problèmes de parasites, mais passons.

je vais tenter d'inclure les informations nécessaire au fonctionnement du/des nrf24 puis je reviendrais vers vous. Je dois aussi assembler les nrf et les arduino car j'ai pu voir sur certain tuto que ces modules sont très sensibles aux parasites et les connections parfois un peu lâches d'une breadboard ne sont pas les plus adaptées.

pas de souci - faites déjà bien fonctionner ce que vous avez !

bonjour JML,

manette sans fils reçue et mise en service :smiley: (heureux comme un gosse qui à un nouveau jouet),
après de nombreux tests et fusibles grillés (ils sont là pour ça).
Des mises aux points mécaniques et électriques s'imposent,
je me vois contraint d'installer des fins de courses, sur les mouvements du bras, balancier et godet.

en définissant les pins des fdc en INPUT_PULLUP , avec l'un des pôles du micro interrupteur sur le 5v et l'autre sur le pin choisi pour fdcOuvre ou fdcFerme.

Que pensez-vous de quelque chose comme ceci ?

if (RX != PRX) {
    if (RX > 140) godetOuvre(map(RX, 0, 140, 0, 255));      else digitalWrite(godetIn4, LOW);   if (fdcGodetOuvre == LOW){ digitalWrite(godetIn4, LOW);}
    if (RX < 113) godetFerme(map(RX, 113, 0, 0, 255));      else digitalWrite(godetIn3, LOW);   if (fdcGodetFerme == LOW){ digitalWrite(godetIn3, LOW);}
    PRX = RX;                                                                                          
  }

je pensais aussi à un truc avec un OU logique || comme ça :

if (RX > 140) godetOuvre(map(RX, 0, 140, 0, 255)); else || (fdcGodetOuvre == LOW) digitalWrite(godetIn4, LOW);

mais cela ne me paraît pas être bien formulé

Bonsoir m122

Jolie la manette sans fils :wink:, tu peux même la faire vibrer pour signaler d'éventuels problèmes.

Avec le PULL_UP, le pôle du micro doit être au GND et l'autre sur le pin choisi.
Comme ta machine a de GROS moteurs qui génèrent des perturbations,, il est préférable de mettre des PULL_UP externes d'environ 4.7k., voire même utiliser du câble blindé entre le FDC et l'Arduino.

Cordialement
jpbbricole

bonsoir jpbbricole
autant pour moi c'est logique pull_up se traduit par tiré_haut.

déjà beaucoup de monde sur le méga c'est pour ça que je pensait aux résistances internes.
Cela dit je pense me procurer un shield "bornier à vis" pour le méga et souder les résistances directement dessous

ça c'est clair qu'ils ne peinent pas ! Si je pose le "godet" pour essayer de lever les chenilles c'est la tringle de mouvement du bras qui plie !! Ce proto est un bon début mais le prochain sera une vraie bête. (déjà des idées plein la tête à tel point que je n'arrive plus à me concentrer sur la commande via nrf24, mais je vais m'y remettre) un peu plus tard...

c'est vrai comment ça marche? si j'arrive à obtenir une vibration lorsque j'arrive sur un fin de course ça peut être sympa.

je me suis aperçu d'un petit loupé dans le code

les else ne s'adressent pas au pins "godet", ce qui n'empêche pas le fonctionnement mais le mouvement du godet ne s'arrête pas au laché du joystick il faut cherché le point 'neutre'

Bonjour m122

Regardes l'exemple PS2X_Example de la librairie PS2X_lib.h et recherches vibrate.

Bonne journée
Cordialement
jpbbricole

certaines "copie" asiatiques pas chères n'ont pas le petit moteur de vibration.

bonsoir à vous, les moteurs de vibrations sont bien présents(manette transparente) mais non fonctionnels via le code exemple car la manette n'accepte pas le mode " pressure", les boutons sont seulement on / off.
Mais les vibrations fonctionnent avec la console de jeu.

un problème plus important me perturbe depuis quelques jours maintenant:
le rotofil( moteur 12v 3.9A) après avoir brûlé de nombreux mosfet ( une dizaine, tous différents k06n06 , irf540n .... pourtant surdimensionnés montés sur dissipateur alu 60*60mm) j'obtiens un fonctionnement "bizarre" avec les 2n0609.
le moteur ne s'arrête pas à chaque fois et lorsqu'il à bien voulu s'arrêter, redémarre ( à vitesse aléatoire même dans des valeurs non définies par le code des vitesse 1,2 et 3) à l'utilisation de la commande tourelle (uniquement cette commande) et ne s'arrête plus de nouveau.
j'ai changé le pin de commande du rotofil car juste à coté du pin tourelle : même comportement !!
il me semble que des parasites sont la cause du problème, qu'en pensez vous?

voici la datasheet du mosfet (j'ai modifié le code des 3 vitesses pour rester dans les valeur de Vgs(th)).
2N0609-INCHANGE.pdf (244.4 KB)

je dois préciser que tous ces mosfet proviennent de vielles cartes, je les déssoude en prenant soin de faire chauffer les composant le moins possible (tissu humide ou dissipateur laissé dessus pour le démontage) et un doigt sur le corps du composant pour contrôle température.

Bonjour m122

Pourquoi ne pas utiliser des h-bridge, il y en a de toutes sortes.

Cordialement
jpbbricole

Bonjour, par manque de patience.
J'ai commandé des H-bridge en Asie, mais ils se font désirer ! Ils devraient arriver courant septembre.
Et l'utilisation des mosfet paraissait simple, mais la je ne comprends plus.

Mais ce n'est pas le fait que ça ne marche pas qui m'agace, c'est le fait de ne pas comprendre mon erreur. Donc je vais continuer de lire des tuto et autres prez pour réussir à faire fonctionner (au moins quelques minutes) jusque là espérance de vie des mosfet 30/40 secondes

il y a de nombreux tutos en ligne sur la construction de son H-brdige

une vidéo (un des premiers hits) avec 2 2P et 2N + 2 transistors 2N2222

son schéma

et bien sûr le tuto de @68tjs qui est à (re)lire

Voilà j'ai trouvé d'où vient ce pentin de parasite.
Le dissipateur des mosfet était fixé sur le châssis du robot, une fois isolé de la machine, fonctionnement impeccable pendant plusieurs minutes avec 2 mosfet 2n0609 en parallèle.
Je vais maintenant me concentrer sur la mise en place des fins de courses, j'ai trouvé du câble en 4*0,34 blindé, ça devrait être pas mal. Je vous tiendrai informé de l'avancement.
Encore merci à vous 2 pour l'aide et les conseils.

ce sont ce cour et ce tuto que j'ai suivi (et resuivi) avec attention, sans comprendre pourquoi ça ne fonctionnait pas pour moi. je ne pensais pas que la carcasse serait source de parasites.

un souci de GND ?

Bonjour

Je te mets un petit exemple avec le bouton Select

#include <PS2X_lib.h>  //for v1.6

PS2X ps2x; // create PS2 Controller Class

const byte PS2_DAT          = 14;
const byte PS2_CMD          = 15;
const byte PS2_SEL          = 16;
const byte PS2_CLK          = 17;

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

void setup(){
 Serial.begin(115200);

 //CHANGES for v1.6 HERE!!! **************PAY ATTENTION*************
  
 error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, true, true);   //setup pins and settings:  GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
 
	if(error == 0){
		Serial.println("Found Controller, configured successful");
		Serial.println("Try out all the buttons, X will vibrate the controller, faster as you press harder;");
		Serial.println("holding L1 or R1 will print out the analog stick values.");
		Serial.println("Go to www.billporter.info for updates and to report bugs.");
	}
   
	else
		Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips");
}

void loop(){
	ps2x.read_gamepad(false, vibrate);          //read controller
	
    if(ps2x.Button(PSB_SELECT))
    {
	    Serial.println("Select is being held");
	    vibrate = 200;
    }
	else
	{
		vibrate = 0;
	}
	
	delay(50);     
}

En fait il suffit de faire

ps2x.read_gamepad(false, vibrate)

vibrate (byte) de 0 à 255.

Cordialement
jpbbricole

Oui je pense, pourtant la carcasse est sensée être libre de potentiel.Tous les moteurs hors mi celui de la tourelle sont montés sur silent-blocs, mais c'est aussi le seul qui a un réducteur 100% métallique.
Sûrement un petit défaut d'isolement sur le moteur de la tourelle.
Je travaille au dessin d'un support à imprimer en 3d pour le dissipateur.
Je devrais 'forcer' un GND sur la carcasse ?

Merci, je test ça dès que j'ai un peu de temps.

je ne suis pas le mieux placé pour répondre - faudrait demander à pro du hard... (mais je suppose que ça ne peut pas faire de mal)