contrôleur PS2 dualshock - Utilisation comme télécommande pas chère

Salut à tous

je voulais rajouter une manette sans fil ergonomique de contrôle à un petit projet et ne voulais pas m'embêter à créer une manette...

J'avais dans mes tiroirs une manette (copie chinoise) d'une "Sony" PS2 dualshock (sans moteur de vibration)

1.manette.png

Ell a l'avantage d'être livrée avec un module sans fil fonctionnant à 2.4GHz

2.module2.4GHz.png

La manette fonctionne sur alimentation avec 2 piles batons AAA 1.5V standard que vous accédez par une trappe sous la manette, donc c'est vraiment simple et pratique pour tous les utilisateurs, petits et grands et côté arduino on alimentera (3.3V) le module sans fil.

3.piles.png

Il y a plusieurs intérêts à explorer cette manette pour des petits projets:

1/ d'une part vous pouvez en trouver pour vraiment pas cher an Asie, par exemple sur eBay à environ 7 euros livraison comprise (sans les piles) (chercher “B58C 64F1 Black 2.4GHz Wireless Dual Vibration Button Game Controller For PS2 PC“)

2/ Bill Porter a déjà étendue une librairie (en reprenant et affinant le travail de @Shutter) qui gère les détails de la communication entre la manette et un Arduino en exposant une API d'assez haut niveau.

3/ il y a de l'information sur internet (par exemple ce très bon post en anglais qui explique un peu le protocole (en gros SPI) et d'autres informations intéressantes)


Bon OK - vous êtes convaincu et voulez jouer avec pour commander votre gadget :slight_smile:

Les Branchements:

Mon unité de contrôle à distance n'a pas toutes les pins documentées sur internet mais il a les pins qu'il faut pour jouer et les pins correspondent bien au blog mentionné ci dessus

Le module sans fil a la bonne idée d'exposer des pins avec un accès simple (sans même à avoir à démonter le boîtier) pour des fils Dupont femelle standards.

Prenez une nappe de fils male <--> femelle et prenez les couleurs qui vous permettent par exemple d'avoir le fil rouge de 3.3V au bon endroit (et branchez le marron sur GND)


(bien sûr vous pouvez utiliser les fils que vous voulez)

de l'autre côté connectez votre Arduino UNO ou MEGA de la façon suivante:

Data -> pin D12 (mon fil blanc)
Command --> pin D11 (mon fil noir)
GND --> GND (mon fil marron)
3.3V ---> 3.3V (mon fil rouge)
Attention --> pin D10 (mon fil orange)
Clock --> pin D13 (mon fil jaune)

Mettez des piles dans la télécommande et allumez là avant de brancher l'arduino (qui alimente le module distant)

Installer la librairie:

Vous pouvez trouver la librairie PS2X de Bill Porter sur Github. Elle s'installe "à la main"

  • Téléchargement de la librairie en clickant sur "Clone or Download" --> “Download Zip”
  • Vous obtenez un fichier Arduino-PS2X-master.zip que vous décompressez.
  • Dans le répertoire obtenu Arduino-PS2X-master vous trouverez un dossier PS2X_lib qu'il ne vous reste plus qu'à déplacer dans le dossier standard de vos librairies Arduino.

Le code:

voilà vous êtes prêts à jouer. la librairie propose une classe PS2X, on commence par instancier un objet pour représenter la manette et dans le setup() on appelle config_gamepad() en donnant les pins utilisées

ensuite c'est simple à utiliser. Quand vous voulez lire l'état de la manette, vous appelez read_gamepad() et votre instance a ensuite des fonctions qui permettent de savoir quels sont les états de chaque bouton qui sont dénommés par un petit nom dans un #define que vous pouvez lire dans le .h de la librairie

Voici comment ils sont associés aux boutons

SUITE

Les fonctions intéressantes:
NewButtonState() sera vrai si quelque chose a changé
NewButtonState(refBouton) sera vrai si refBouton vient JUSTE d'être pressé ou relâché
Analog(refBouton donne la valeur de pression sur le bouton, pour les axes du joystick c'est la valeur entre 0 et 255 (127 ou 128 au repos) pour les boutons c'est 0 si pas pressé et 255 si appuyé, mais certaines manettes gèrent aussi la pression variable sur les boutons (mais pas cette manette pas chère).
ButtonPressed(refBouton) est vrai si le bouton VIENT d'être appuyé (depuis la dernière lecture de config)
Button(refBouton) est vrai si le bouton est tenu enfoncé
ButtonReleased(refBouton) est vrai si le bouton VIENT d'être relâché (depuis la dernière lecture de config)

Voilà un exemple de code qui écoute la télécommande toutes les 20ms et imprime dans la console série (réglée à 115200 bauds) ce qu'il se passe pour chacun des boutons ou joystick.

#include <PS2X_lib.h> /* PS2 Controller Library http://www.billporter.info/2010/06/05/playstation-2-controller-arduino-library-v1-0/ */
PS2X ps2x; /* on crée l'instance du controleur */

// information http://www.rhydolabz.com/wiki/?p=12663

// Connecter de gauche à droite en regardant le connecteur
// ----------------------
// Data --> pin 12
// Command --> pin 11
// NC
// ----------------------
// GND --> GND
// Power --> 3.3V
// Attention --> Pin 10
// ----------------------
// Clock --> pin 13
// NC
// NC
// ----------------------

const byte dataPin = 12;
const byte commandPin = 11;
const byte attentionPin = 10;
const byte clockPin = 13;

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

  /* config_gamepad(clock, command, attention, data, Pressures?, Rumble?) */
  ps2x.config_gamepad(clockPin, commandPin, attentionPin, dataPin, true, true); // gardez true, true à la fin même si pas de moteurs

  if (ps2x.readType() == 1) Serial.println(F("DualShock"));
  else {
    Serial.print(F("Manette Absente - code "));
    Serial.println(ps2x.readType());
    while (true); // on meurt ici, éventuellement enlever si vous avez un autre code manette
  }

  ps2x.read_gamepad(); // initialisation des valeurs
  delay(50);
  ps2x.read_gamepad();  /* initialise les états */
}


void loop() {
  static uint32_t chrono = 0;
  const uint32_t periode = 20ul; // la manette est assez sensible, il ne faut pas lui demander les infos trop souvent. 15ms ou 20ms ça fonctionne pour moi

  if (millis() - chrono >= periode) {
    int RX = 0, RY = 0, LX = 0, LY = 0;
    static int PRX = 127, PRY = 128, PLX = 127, PLY = 128;

    chrono += periode;

    ps2x.read_gamepad();   /* on lit l'état de la manette */

    LX = ps2x.Analog(PSS_LX);          /* joystick de gauche X*/
    LY = ps2x.Analog(PSS_LY);          /* joystick de gauche Y */
    RX = ps2x.Analog(PSS_RX);          /* joystick de droite X */
    RY = ps2x.Analog(PSS_RY);          /* joystick de droite Y */

    // si une des coordonnées des joystick a changé alors on imprime les nouvelles coordonnées
    if ((LX != PLX) || (LY != PLY) || (RX != PRX) || (RY != PRY)) {
      PLX = LX;
      PLY = LY;
      PRX = RX;
      PRY = RY;
      Serial.print(LX);    Serial.print(F(" ,"));
      Serial.print(LY);    Serial.print(F(" ,"));
      Serial.print(RX);    Serial.print(F(" ,"));
      Serial.println(RY);
    }

    // if (ps2x.NewButtonState()) {}  /* vrai s'il y a un changement d'état, si on ne veut pas lire l'état à la main  */

    // ButtonPressed(unsigned int) vrai si le bouton VIENT d'être appuyé (depuis la dernière lecture de config)
    if (ps2x.ButtonPressed(PSB_START))     Serial.println(F("START APPUI"));
    if (ps2x.ButtonPressed(PSB_SELECT))    Serial.println(F("SELECT APPUI"));
    if (ps2x.ButtonPressed(PSB_PAD_UP))    Serial.println(F("HAUT APPUI"));
    if (ps2x.ButtonPressed(PSB_PAD_RIGHT)) Serial.println(F("DROIT APPUI"));
    if (ps2x.ButtonPressed(PSB_PAD_LEFT))  Serial.println(F("GAUCHE APPUI"));
    if (ps2x.ButtonPressed(PSB_PAD_DOWN))  Serial.println(F("BAS APPUI"));
    if (ps2x.ButtonPressed(PSB_L1))        Serial.println(F("GAUCHE 1 APPUI"));
    if (ps2x.ButtonPressed(PSB_R1))        Serial.println(F("DROITE 1 APPUI"));
    if (ps2x.ButtonPressed(PSB_L2))        Serial.println(F("GAUCHE 2 APPUI"));
    if (ps2x.ButtonPressed(PSB_R2))        Serial.println(F("DROITE 2 APPUI"));
    if (ps2x.ButtonPressed(PSB_GREEN))     Serial.println(F("Triangle APPUI"));
    if (ps2x.ButtonPressed(PSB_BLUE))      Serial.println(F("X APPUI"));
    if (ps2x.ButtonPressed(PSB_RED))       Serial.println(F("Cercle APPUI"));
    if (ps2x.ButtonPressed(PSB_PINK))      Serial.println(F("Carre APPUI"));

    // Button(uint16_t); vrai si le bouton est tenu enfoncé
    if (ps2x.Button(PSB_START))     Serial.println(F("START"));
    if (ps2x.Button(PSB_SELECT))    Serial.println(F("SELECT"));
    if (ps2x.Button(PSB_PAD_UP))    Serial.println(F("HAUT"));
    if (ps2x.Button(PSB_PAD_RIGHT)) Serial.println(F("DROITE"));
    if (ps2x.Button(PSB_PAD_LEFT))  Serial.println(F("GAUCHE"));
    if (ps2x.Button(PSB_PAD_DOWN))  Serial.println(F("BAS"));
    if (ps2x.Button(PSB_L1)) Serial.println(F("GAUCHE 1"));
    if (ps2x.Button(PSB_R1))Serial.println(F("DROITE 1"));
    if (ps2x.Button(PSB_L2))Serial.println(F("GAUCHE 2"));
    if (ps2x.Button(PSB_R2))Serial.println(F("DROITE 2"));
    if (ps2x.Button(PSB_GREEN))     Serial.println(F("Triangle"));
    if (ps2x.Button(PSB_BLUE))      Serial.println(F("X"));
    if (ps2x.Button(PSB_RED))       Serial.println(F("Cercle"));
    if (ps2x.Button(PSB_PINK))      Serial.println(F("Carre"));

    // ButtonReleased(unsigned int) vrai si le bouton VIENT d'être relâché (depuis la dernière lecture de config)
    if (ps2x.ButtonReleased(PSB_START))     Serial.println(F("START RELACHE"));
    if (ps2x.ButtonReleased(PSB_SELECT))    Serial.println(F("SELECT RELACHE"));
    if (ps2x.ButtonReleased(PSB_PAD_UP))    Serial.println(F("HAUT RELACHE"));
    if (ps2x.ButtonReleased(PSB_PAD_RIGHT)) Serial.println(F("DROITE RELACHE"));
    if (ps2x.ButtonReleased(PSB_PAD_LEFT))  Serial.println(F("GAUCHE RELACHE"));
    if (ps2x.ButtonReleased(PSB_PAD_DOWN))  Serial.println(F("BAS RELACHE"));
    if (ps2x.ButtonReleased(PSB_L1))        Serial.println(F("GAUCHE 1 RELACHE"));
    if (ps2x.ButtonReleased(PSB_R1))        Serial.println(F("DROITE 1 RELACHE"));
    if (ps2x.ButtonReleased(PSB_L2))        Serial.println(F("GAUCHE 2 RELACHE"));
    if (ps2x.ButtonReleased(PSB_R2))        Serial.println(F("DROITE 2 RELACHE"));
    if (ps2x.ButtonReleased(PSB_GREEN))     Serial.println(F("Triangle RELACHE"));
    if (ps2x.ButtonReleased(PSB_BLUE))      Serial.println(F("X RELACHE"));
    if (ps2x.ButtonReleased(PSB_RED))       Serial.println(F("Cercle RELACHE"));
    if (ps2x.ButtonReleased(PSB_PINK))      Serial.println(F("Carre RELACHE"));
  }
}

une fois qu'on a compris le principe, il suffit de faire une machine à état qui gère les événements sur la manette pour contrôler son objet (cf mon tuto éventuellement)

Notes:

  • parfois la télécommande est capricieuse, il faut l'éteindre et la rallumer, vous assurer que le voyant vert sur l'unité de réception ne clignote plus et rebooter l'arduino. la librairie ne sait pas se reconnecter si elle perd la manette (donc ne commandez pas un avion avec ça... juste des petits truc qui roulent pas loin et pas vite ou des petits servos pour un robot etc).

  • la librairie fonctionne aussi avec d'autres manettes Sony PS2 donc vous pouvez exploiter en fonction de votre propre manette.

A mon avis cela risque d'avoir un certain succès ... :grin:

hbachetti:
A mon avis cela risque d'avoir un certain succès ... :grin:

je me suis dit que ça pourrait aider :slight_smile:

hbachetti:
A mon avis cela risque d'avoir un certain succès ... :grin:

:grin:

Je pense aussi

Génial!! Merci pour ce post!

Il semble que celle que j'ai acheter sur Aliexpress ne fonctionne pas.
Les deux LED sur la télécommande clignote en permanence. Du coup j'ai le message suivant sur le port série.
00:11:02.846 -> No controllNo controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips
00:11:02.879 -> Unknown Controller type

C’est un peu capricieux - de mémoire j’avais joué avec le bouton analog ou le petit bouton derrière et ensuite le module avait été reconnu par la télécommande

Je ne sais pas sous d'autres système mais avec mon firefox sous Debian le titre que je vois est :

Capture_2020_09_16_15_51.png
Une petite modif du titre du premier message ?

Au passage la méthode pour mettre des images à changé avec la nouvelle version du forum

Capture_2020_09_16_15_51.png

LOL

J’ai changé le titre - faut acheter un écran à plus haute résolution :))

J'ai le même affichage sur smartphone. Mais ça a eu l'avantage d'attirer mon regard et du coup j'ai lu la discussion...

l'affichage est formaté par le forum : quels que soient les machines, OS, navigateurs, résolutions ou niveaux de zoom, on voyait bien "con..." ... et je trouvais ça marrant

Ok je ne vois pas ça sur mon mac ou iPad (Safari)
Peut-être je ne regarde pas au même endroit

c'est sûr : depuis que le titre est modifié, on ne le voit plus ... ça me semble normal

Je veux dire que je ne vois pas de titres avec des « .... » quel que soit le titre que j’utilise

C’est dans quelle page ?

5_cylindres:
l'affichage est formaté par le forum : quels que soient les machines, OS, navigateurs, résolutions ou niveaux de zoom, on voyait bien "con..." ... et je trouvais ça marrant

Oui mais il y a un gros soucis moi j'aurai tendance à mettre au pluriel parce que pour ce qui est des espèces en voie de disparition <censuré>