Tuto pas à pas : utliser un joystick avec une Gamebuino Meta

On va voir étape par étape comment utiliser un joystick sur notre Gamebuino Meta.

Le tuto est destiné à être réalisé avec le matériel fourni dans le pack d’accessoires Gamebuino

Pour ce tutoriel, il vous faut :

  • une console Gamebuino META
  • un joystick compatible Arduino
  • un ordinateur avec l’environnement de développement l’IDE Aduino installé

Si ce n’est pas encore fait, reportez vous à la fiche
Premiers pas (C++ 1/5) : Installation rapide du logiciel - Gamebuino pour installer l’IDE Arduino.


Si vous avez déjà les bases en programmation (ou juste la flemme de suivre ce tuto) le code complet réalisé dans ce sujet est disponible sur le Mini-code : joystick


Etape 1 : bien commencer

Cette étape est identique sur la plupart des tutos car elle constitue la base indispensable de n’ilmporte quel programme pour Gamebuino.

Pour commencer, ouvrez l’éditeur Arduino préconfiguré pour la Gamebuino

-Vous devriez avoir ceci sur votre écran :

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}

Pour l’instant, le code est un peu vide, mais on va le compléter.

  • En premier lieu on a besoin d’ajouter au tout début du fichier la ligne suivante :
#include <Gamebuino-Meta.h>

C’est ce qu’on appelle une “librairie”, elle va nous permettre d’utiliser tout un tas de fonctions sans avoir à les programmer à la main. Cette librairie contient toutes les fonctions de la Gamebuino et est très utile pour la suite.
On va ajouter deux fonctions pour que notre programme puisse fonctionner :

  • Dans la fonction setup() on ajoute un appel à la fonction gb.begin() comme suit :
void setup() {
  // put your setup code here, to run once:
  gb.begin();
}

La fonction gb.begin() permet d’initialiser la console : sans cela rien ne fonctionnera !

  • Ensuite, on ajoute la fonction while(!gb.update()) dans la fonction loop :
void loop() {
  // put your main code here, to run repeatedly:
  while (!gb.update());
}

La fonction while(!gb.update()) permet de rafraichir le contenu de l’écran (c’est à dire dessiner dessus), gère la lecture des sons, les appuis sur les touches, bref tout ce qui donne vie à votre Gamebuino.

On a à présent une structure de programme fonctionnelle, même si elle ne fait encore rien de concret.


Etape 2 : lire les données du joystick

Dans cette étape on va voir comment récupérer les informations envoyées par le joystick pour les intégrer à notre programme.

Pour cela on va utiliser deux fonctions :

  • la fonction analogRead() qui permet de lire une valeur depuis une entrée analogique
  • la fonction digitalRead() qui elle permet de lire une valeur depuis une entrée digitale
    -Les noms des fonctions sont assez explicites, tant mieux parce que ce n’est pas toujours le cas.

Avant la lecture proprement dite on va utiliser une fonctionnalité très pratique : le define. Un define permet d’intégrer dans le code des associations de “mot-clés”. Ici nous allons utiliser trois define pour rendre la distinction entre les trois entrées de notre joystick plus simples.

  • On procède la manière suivante :
#define JOY_X_AXIS A1
#define JOY_Y_AXIS A2
#define JOY_SWITCH 7

On s’y retrouve beaucoup plus facilement avec un define bien posé car on peut être très descriptif. Ici l’usage de define est quand même un peu superflu, nous n’avons que 3 éléments à différencier. Mais imaginez avec 10, 20, 50 éléments ou plus. Les define c’est bien, mangez-en.

Par convention on place les define au début du programme, je vous laisse bidouiller si vous voulez comprendre pourquoi ;p

Maintenant qu’on a nos broches d’entrée bien définies on peut lire les valeurs sans soucis.

  • Pour ça on utilise nos fonctions de lecture :
void loop(){
  // put your main code here, to run repeatedly:
  while (!gb.update());

 int32_t i32_stick_x_value = analogRead(JOY_X_AXIS);
 int32_t i32_stick_y_value = analogRead(JOY_Y_AXIS);
 int32_t i32_joy_switch_value = digitalRead(JOY_SWITCH);
}

On récupère donc les valeurs de notre joystick dans 3 variables directement dans notre fonction loop().
Cette méthode est un peu lourde mais notre programme est très léger, donc on peut se permettre ce manque d’optimisation.


Etape 3 : Afficher les valeurs

Maintenant que nous avons récupéré les valeurs depuis notre joystick nous allons les afficher à l’écran. Cela permet de vérifier le bon fonctionnement du stick mais aussi de comprendre comment il marche, ce qui nous sera utile par la suite.

Pour afficher nos valeurs on va créer une fonction d’affichage dédiée à cette tâche.

  • on déclare notre fonction de la manière suivante :
void joystick_display( int32_t X_value, int32_t Y_value, int32_t SWITCH_value){

  gb.display.clear();
}

La fonction gb.display.clear() sert à effacer l’écran avant d’y afficher quelque chose pour éviter “d’empiler” les images.

Notez les indications de variables entre les parenthèses après le nom de notre fonction : ce sont des paramètres, des valeurs que nous allons pouvoir “donner” à notre fonction pour qu’elle s’en serve.

Justement nous allons nous en servir dès maintenant, rassurez-vous c’est très simple. On va utiliser la fonction gb.display.printf pour afficher nos valeurs sur l’écran ainsi qu’un peu de texte pour rendre tout ça plus compréhensible.

  • pour ça on ajoute simplement un appel à la fonction printf de la façon suivante :
void joystick_display( int32_t X_value, int32_t Y_value, int32_t SWITCH_value){

  gb.display.clear();

 gb.display.printf(" X_axis = %d\n Y_axis = %d\n switch = %d", X_value, Y_value, SWITCH_value);
}

Ca peut sembler un peu compliqué mais en fait c’est assez simple : Le texte entre guillemets constitue le message à afficher, les “%d” correspondent à des valeurs numériques qui sont spécifiées après le message dans l’ordre et séparées par des virgules et les “\n” sont des retours à la ligne pour séparer notre texte sur trois lignes.
Rien de bien compliqué donc. L’avantage c’est qu’on peut ainsi tout afficher avec une seule fonction au lieu d’utiliser 6 fois la fonction gb.display.print.

  • Et bien sûr on pense à ajouter l’appel à notre fonction value_display() dans notre fonction loop() en lui passant les variables lues précédemment en paramètres :
void loop(){
  // put your main code here, to run repeatedly:
  while (!gb.update());

 int32_t i32_stick_x_value = analogRead(JOY_X_AXIS);
 int32_t i32_stick_y_value = analogRead(JOY_Y_AXIS);
 int32_t i32_joy_switch_value = digitalRead(JOY_SWITCH);

 joystick_display(i32_stick_x_value, i32_stick_y_value, i32_joy_switch_value);
}

Lancez une petite vérification de votre code avant de le téléverser sur la Gamebuino pour vérifier que tout marche bien et vous devriez obtenir ceci :

00001

Bougez votre joystick et appuyez dessus pour voir les valeurs changer.
Normalement vous devriez remarquer un petit soucis avec le clic, il semble ne pas fonctionner correctement, la valeur change de manière aléatoire et non pas quand vous appuyez dessus.

Pour cela il faut effectuer un petit réglage. Le pin du switch de notre joystick n’est pas analogique mais digital, il faut donc configurer cette entrée d’une manière spécifique pour qu’elle fasse ce que nous voulons. Pas de panique, il existe une fonction dédiée à cela, pas besoin de coder nous-même pour cette fois.

  • Il faut utiliser la fonction pinMode comme ceci pour régler notre soucis :
void setup() {
  // put your setup code here, to run once:
  gb.begin();

  //set the input mode of the switch pin to INPUT_PULLUP
  //using only the INPUT mode will make the value flicker constantly
  pinMode(JOY_SWITCH, INPUT_PULLUP);
}

Le problème est normalement réglé.


Etape 4 : Ajouter un visuel

Jusque là on a pu récupérer les valeurs envoyées par le joystick et les afficher. C’est bien mais ce n’est pas très joli ni très parlant. On va donc faire en sorte d’ajouter une transcription visuelle de ce que fait notre joystick à l’écran.

Pour commencer, vous reprendrez bien un peu de define non ?

  • On va définir les dimensions d’un cercle que l’on utilisera ensuite dans notre visuel :
#define CIRCLE_X (gb.display.width()/2)
#define CIRCLE_Y (gb.display.height()/2 + 8)
#define CIRCLE_RAD (gb.display.height()/3)

Souvenez-vous, les define se mettent au début du programme

Grâce à ces dimensions on peut afficher un cercle à l’écran. Pour ça on utilise la fonction gb.display.drawCircle() que l’on intègre dans notre fonction joystick_display() en lui donnant les dimensions posées par nos define.

  • Cela se fait de la manière suivante :
void joystick_display( int32_t X_value, int32_t Y_value, int32_t SWITCH_value){

  gb.display.clear();

 gb.display.printf(" X_axis = %d\n Y_axis = %d\n switch = %d", X_value, Y_value, SWITCH_value);

 gb.display.drawCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_RAD);
}

Cela affiche simplement un cercle blanc vide à l’écran aux coordonnées spécifiées avec un rayon donné.

00002

Pour représenter le mouvement de notre joystick on va ajouter un point rouge qui se déplacera à l’intérieur du cercle en fonction des valeurs renvoyées par le stick.
Pour ça on va devoir définir les coordonnées de ce point de manière dynamiques. Rien de bien compliqué, on sait déjà le faire avec la lecture des valeurs de notre joystick. On adapte simplement le code pour définir deux coordonnées plutôt que pour lire des variables.

  • On déclare juste deux variables que l’on assigne de manière dynamique avec une petite formule mathématique pour les rapporter à la valeur de nos axes X et Y et en restant à l’intérieur du cercle :
void joystick_display( int32_t X_value, int32_t Y_value, int32_t SWITCH_value){

  gb.display.clear();

 gb.display.printf(" X_axis = %d\n Y_axis = %d\n switch = %d", X_value, Y_value, SWITCH_value);

 gb.display.drawCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_RAD);

 int32_t i32_x_dot = ((X_value - 512) * CIRCLE_RAD) / 1023;
 int32_t i32_y_dot = ((Y_value - 512) * CIRCLE_RAD) / 1023;
}

Pour afficher le point on va utiliser la fonction gb.display.fillCircle() qui permet justement de dessiner un cercle plein à l’écran.

  • En pratique cela donne ceci :
void joystick_display( int32_t X_value, int32_t Y_value, int32_t SWITCH_value){

  gb.display.clear();

 gb.display.printf(" X_axis = %d\n Y_axis = %d\n switch = %d", X_value, Y_value, SWITCH_value);

 gb.display.drawCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_RAD);

 int32_t i32_x_dot = ((X_value - 512) * CIRCLE_RAD) / 1023;
 int32_t i32_y_dot = ((Y_value - 512) * CIRCLE_RAD) / 1023;
 gb.display.fillCircle(i32_x_dot + CIRCLE_X, i32_y_dot + CIRCLE_Y, 5);
}

00003

Bon… On rajoute un peu de couleur ?

Ca ne nous prendra qu’une seule tout petite ligne de code, grâce à la fonction gb.display.setColor() qui permet… de définir une couleur d’affichage.

  • On ajoute cette fonction juste avant l’affichage de notre point :
void joystick_display( int32_t X_value, int32_t Y_value, int32_t SWITCH_value){

  gb.display.clear();

 gb.display.printf(" X_axis = %d\n Y_axis = %d\n switch = %d", X_value, Y_value, SWITCH_value);

 gb.display.drawCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_RAD);

 int32_t i32_x_dot = ((X_value - 512) * CIRCLE_RAD) / 1023;
 int32_t i32_y_dot = ((Y_value - 512) * CIRCLE_RAD) / 1023;
 gb.display.setColor(RED);
 gb.display.fillCircle(i32_x_dot + CIRCLE_X, i32_y_dot + CIRCLE_Y, 5);
}

00004

Et voilà !

Vous avez maintenant un programme entièrement fonctionnel qui vous permet de tester votre beau joystick tout neuf et de vérifier qu’il fonctionne bien.
Les plus observateurs noteront d’ailleurs que le joystick ne bouge pas réellement dans un cercle mais plutôt dans un carré, c’est normal. Le mouvement circulaire auquel on est habitué est un effet mécanique qui n’existe pas pour la machine informatique. Si on voulait un mouvement vraiment circulaire il faudrait tricher dans notre code pour extrapoler les valeurs lues et les transposer sur un cercle, ce qui est au-delà de mes compétences pour le moment, aussi je ne vous soumettrai pas à cet exercice périlleux, du moins pas tout de suite.

joystick_animated

Vous avez survécu à ce tuto, bravo ! A très bientôt pour de nouvelles aventures.

1 Like