Projets Matlab & Microcontrôleur #6: Manette de jeu infrarouge avec Arduino 2/2

Manette de jeu infrarouge avec Arduino 1

Objectifs

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) .

touches manette IR

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;            

void setup()  
{
  // Init RS232
  Serial.begin(9600);
  
  // Init Indicateurs manette   
  pinMode(UpLED, OUTPUT);
  pinMode(DownLED, OUTPUT);
  pinMode(LeftLED, OUTPUT);
  pinMode(RightLED, OUTPUT);
  
  // Init du récepteur 
  irrecv.enableIRIn();
  
  // Initialisation 
  digitalWrite(UpLED, LOW);   
  digitalWrite(DownLED, LOW);                                        
  digitalWrite(LeftLED, LOW); 
  digitalWrite(RightLED, LOW); 
}

void loop()  
{
  // Lecture de la télécommande 
  if (irrecv.decode(&results))
  {
    // Récupération du code   
    res_val = results.value;

    // Réception de la nouvelle valeur
    irrecv.resume();
  } 

  // Envoie la commande à Matlab  
  ManetteTocuhe(res_val); 

  // Init 
  res_val=0; 
}

void InitLEDs(void)
{
  digitalWrite(UpLED, LOW);   
  digitalWrite(DownLED, LOW);                                        
  digitalWrite(LeftLED, LOW); 
  digitalWrite(RightLED, LOW);
  Serial.println(99,DEC); // Waiting... 
  delay(200);  
}
void ManetteTocuhe(long Chan_code)
{
  switch(res_val)  
  {
    case 0xFF18E7: // Up
      digitalWrite(UpLED, HIGH);   
      digitalWrite(DownLED, LOW);                                        
      digitalWrite(LeftLED, LOW); 
      digitalWrite(RightLED, LOW);
      Serial.println(150,DEC); 
      delay(200);
      break;

    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);

test de l'interface série

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

Le programme principal (main.m)

%% Open Serial Port

SerialCOM = Open(); % Open new port

%% Programme principal

% Params Labyrinthe
sz=10;
tile_sz=100;
tangling_steps=300;
growing_steps=900;

% Génération LABY
[elements,t_set] = Maze_gen( sz,tangling_steps,growing_steps);
img_maze = Plot_maze( elements,t_set,tile_sz);

% Taille du joueur  NxN
N=20;

% Déplacement en pixel
Pas=round(N/2);

% 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(:));
    
    % Gestion du compteur: Incrémentation ou Pénalité
    if(mean_pixel < Seuil_outZone)
        % Affichage
        img_maze0(Start_y:Start_y+N-1,Start_x:Start_x+N-1,:)=128*ones(N,N,3);
        im_gray=im2uint8(imresize(img_maze0,[512 512]));
        imshow(im_gray); title('Maze size 10x10'); axis square;
        
        % Mise à jour
        Start_y_0=Start_y;
        Start_x_0=Start_x;
        Cmp_cible=Cmp_cible+1;
    else
        Cmp_cible=Cmp_cible+Out_zone_pinal;
    end
    
    % Affichage score
    disp('Votre compteur:');
    disp(Cmp_cible);
    
    % Délai & Init
    pause(0.5);
    Manette=ones(1,4);
    img_maze0=img_maze;
end

%% Port Delete (Previous port if exist)

Delete(SerialCOM);

Photos du projet

Projet Manette de jeu infrarouge avec Arduino (2)

Photos Projet Manette de jeu infrarouge avec Arduino (3)

Photos Projet Manette de jeu infrarouge avec Arduino (2)

Photos Projet Manette de jeu infrarouge avec Arduino (1)

Téléchargement

Tout les projets Matlab & µC

 

Articles

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Anti-Robot *