Le présent article et la partie 2/2 du projet du jeu labyrinthe avec Arduino et Matlab (voir la partie 1/2). Nous avons abordé dans la première partie l’interface du jeu avec Matlab et comment générer un labyrinthe aléatoire en utilisant une librairie Matlab. Ici on va se focaliser particulièrement sur la liaison télécommande IR-Arduino et Arduino-Matlab. On fera également une mise à jour du programme matlab pour l’adapter à la manette infrarouge. Les objectifs du projet sont les suivants :
Savoir transférer les données entre Arduino et Matlab
Savoir utiliser une télécommande IR
Se familiariser à la programmation matlab
Etc.
Vidéo démonstration
Principe de fonctionnement
En résumé la carte arduino est analogue à une manette de jeu infrarouge sans fil constituée de 4 touches. Chaque touche sert à contrôler le déplacement du joueur dans l’interface Matlab (droite, fauche, haut et bas). La carte dispose également de quatre LED indiquant la touche active. La LED s’allume pendant 200 ms quand l’utilisateur appuie sur la télécommande IR. Ci-dessous la configuration des touches de la télécommande IR et le code correspondant (voir le projet commande IR d’un moteur à CC) .
Programme Arduino
Pinout des composants avec Arduino (voir le schéma au début de l’article)
Récepteur IR : 11
LED bleue: 2
LED rouge: 3
LED verte: 4
LED jaune: 5
Codage des touches et liaison avec Matlab
La carte Arduino scrute le récepteur en boucle. Lorsqu’une touche de la télécommande est active, la carte Arduino communique un code sur 1 octet au logiciel Matlab via la liaison série. En effet, chaque touche de la télécommande dispose d’un code sur 3 octets. Lorsque le récepteur détecte le code, il indique la présence d’une touche. Dans notre cas uniquement 4 touches seront utilisées. Ci-dessous le tableau récapitulatif des codes reçus par la télécommande et ceux envoyés à Matlab :
Touche de la télécommande
Fonction
Code envoyé par la télécommande (HEX)
Code envoyé à Matlab (Décimal)
« 2 »
Up
0xFF18E7
150
« 8 »
Down
0xFF4AB5
160
« 4 »
Left
0xFF10EF
170
« 6 »
Right
0xFF5AA5
180
Autres
Waiting
Others
99
Programme
#include "IRremote.h"
// Numéro du pin sortie du récepteur long int res_val; const int receiver = 11;
// Indicateurs manette const int UpLED = 2; const int DownLED = 3; const int LeftLED = 4; const int RightLED = 5;
// Déclaration d'un objet IRrecv IRrecv irrecv(receiver); decode_results results;
case 0xFF4AB5: // Down digitalWrite(UpLED, LOW); digitalWrite(DownLED, HIGH); digitalWrite(LeftLED, LOW); digitalWrite(RightLED, LOW); Serial.println(160,DEC); delay(200); break;
case 0xFF10EF: // Left digitalWrite(UpLED, LOW); digitalWrite(DownLED, LOW); digitalWrite(LeftLED, HIGH); digitalWrite(RightLED, LOW); Serial.println(170,DEC); delay(200); break;
case 0xFF5AA5: // Right digitalWrite(UpLED, LOW); digitalWrite(DownLED, LOW); digitalWrite(LeftLED, LOW); digitalWrite(RightLED, HIGH); Serial.println(180,DEC); delay(200); break;
default: InitLEDs(); } }
Programme Matlab
Test de l’interface série (voir la vidéo)
Le script Matlab TestManette.m sera utilisé pour valider le bon fonctionnement de l’interface série. Son objectif est la lecture et l’affichage en boucle du contenu de l’interface série au format entier. La carte Arduino envoie le code « 99 » lorsque aucune touche n’est actionnée et un ensemble de 4 valeurs (voir le tableau ci-dessus) au moment d’appui sur la touche. Le programme ci-dessous affiche la valeur acquise lorsqu’elle est différente du « 99 ».
%% Open Serial Port
SerialCOM = Open(); % Open new port
%% Read data from Serial port
while(1) % Read data DataArduino = fscanf(SerialCOM,'%d'); if(DataArduino~=99) DataArduino end end
%% Port Delete (Previous port if exist)
Delete(SerialCOM);
Mises à jour du programme précédent
Le programme est identique au celui de la partie 1/2. Nous avons effectué une légère mise à jour. Nous avons ajouté une boucle infinie au début de la boucle principale (while(1)). Elle bloque le programme en attendant un appui sur une touche de la télécommande (voir ci-dessous).
while(1) ... % Read data from serial port (attente) while(1) DataArduino = fscanf(SerialCOM,'%d'); if (DataArduino~=99) break; end; end; ... end
Nous avons aussi utilisé une nouvelle fonction ManetteVal() qui permet de convertir la valeur acquise en un vecteur de taille quatre. Chaque case du vecteur est liée à un déplacement du joueur dans le labyrinthe (voir partie ½ du projet). Lorsqu’un champ est égal à « 1 », il indique l’activation d’un déplacement. Les champs sont égaux à « 1 » ([1 1 1 1]) dans le cas contraire (voir le script ManetteVal.m).
function Manette = ManetteVal( DataArduino )
switch DataArduino case 150 % UP Manette=[1 0 0 0]; case 160 % DOWN Manette=[0 1 0 0]; case 170 % LEFT Manette=[0 0 0 1]; case 180 % RIGHT Manette=[0 0 1 0]; otherwise Manette=[1 1 1 1]; end end
% Coordonnées de la position initiale du joueur (x0, y0) img_maze0=img_maze; im_rgb=((im2uint8(img_maze0))); pix =[236 28 36]; x_y=GetPixel(im_rgb, pix); Start_y_0=x_y(1);Start_y=Start_y_0; Start_x_0=x_y(2); Start_x=Start_x_0;
% Manette Manette=ones(1,4); Seuil_outZone=0.3;
% Positionner le joueur sur (x0, y0) img_maze0(Start_y_0:Start_y_0+N-1,Start_x_0:Start_x_0+N-1,:)=128*ones(N,N,3); im_affich=imresize(img_maze0,[512 512]); imshow(im_affich); title('Maze size 10x10'); axis square;
% Compteur pas vers la cible Cmp_cible=0; Out_zone_pinal=2; figure(1);
while(1)
% Read data from serial port (attente) while(1) DataArduino = fscanf(SerialCOM,'%d'); if (DataArduino~=99) break; end; end;
% Obtenir le vecteur Manette Manette = ManetteVal( DataArduino );
% Extraction des valeurs Down =Manette(1); Up=Manette(2); Right =Manette(3); Left=Manette(4);
% Déplacement if Up~0 Start_y=Start_y_0+Pas; elseif Down~0 Start_y=Start_y_0-Pas; if Start_y <=0 Start_y=1; end; end; if Right~0 Start_x=Start_x_0+Pas; elseif Left~0 Start_x=Start_x_0-Pas; if Start_x <=0 Start_x=1; end; end;
% Calcul de la valeur moyenne de la position actuelle
% Extraction du bloc NxN im_0= img_maze0(Start_y:Start_y+N-1,Start_x:Start_x+N-1,:);
% Conversion RGB => Gray im_0=rgb2gray(im_0);
% Caclul de la valeur moyenne mean_pixel=mean(im_0(:));