Commande de robot par FPGA

De troyesGEII
Aller à : navigation, rechercher

Projet pour l'année scolaire 2013/2014

Le projet de l'année 2013/2014 et ce rapport correspondant ont été réalisés par les étudiants :

  • GALLAND Quentin
  • HENRY Guillaume
  • KERDILES Guillaume

Présentation du robot arexx

Le Robot Arexx a été envisagé comme base robotique de ce projet. En voici une présentation vidéo :

Fichier:Robot arexx.mkv

Le robot Arexx a finalement été abandonné au profit du robot Digilent (suiveur de ligne).

Présentation du nouveau cahier des charges

Notre objectif est de partir d'un Robot commandé par une carte microcontrôleur 32 bits de type PIC32 et de le remplacer par une carte FPGA. La carte utilisée cette année sera une carte Basys2.

Information sur la Basys 2

Basys2
Basys2


La Basys2 est une carte FPGA conçue par Digilent. Elle permet la simulation de vrais circuits numériques. La programmation de circuits numériques se fait à l'aide du logiciel XilinX. Grâce à sa grande collection de périphériques d'entrées et de sorties, on peut simuler une grande gamme de circuits numériques.




Caractéristiques :

    -Xilinx Spartan 3-E FPGA 100k ou 250k portes;
    -72Kbits de RAM et fréquence de transfert de 500MHz;
    -2 ports USB 2.0 pour les transferts de configurations et de données;
    -Fréquence de l'oscillateur (25,50 et 100MHz) réglable par l'utilisateur; 
    -Trois régulateurs de tension intégrés (1,2V, 2,5V, 3,3V) permettent l'utilisation 
     des sources d'alimentations externes 3.5V-5.5V;
    -8 LED, 4 Afficheurs sept segments, 4 boutons poussoirs,
     8 interrupteurs à glissière, 1 ports PS/2 et 1 port VGA-8bits;
    

Lien : User Guide Basys2

Carte capteur à photo-transistors

Le CNY70 est un capteur à réflexion optique c'est à dire qu'il est composé d'un photo-transistor filtrant la lumière visible et d'une diode infrarouge. Il permet de détecter un contraste noir-blanc à faible distance (inférieur à 5mm).

capteur à photo-transistor












On envisage l'implantation de 4 capteurs CNY70 au lieu de 2 vu précédemment dans le projet inter-semestre de 1ere année.

Montage et programmation du robot

Présentation de notre robot

Le robot est composé d'une plate-forme métallique sur laquelle est posée la carte Basys2, de 2roues de 3pouces, de 2moteurs contrôlés chacun par une carte PmodHB5, d'un support de 4piles et d'une bille porteuse permettant de maintenir le robot à plat.

Notre Robot



Tout d'abord, nous étions censés programmer un robot suiveur de ligne grâce à des capteurs photo-transistors. Cependant, les capteurs n'étant pas fiable, le robot était dans l'incapacité de suivre une ligne noire. Donc, nous avons décidés de remplacer les capteurs par une manette Nunchuk permettant de gérer la direction du robot.

Dans les prochaines parties, nous allons expliquer la programmation des différentes parties du robot.











Programmation des moteurs PmodHB5

Schéma fonctionnel des moteurs

Création du composant HB5RefComp qui s'introduit dans l'architecture de l'io.

component HB5RefComp
 port(	  ck : in  STD_LOGIC;          -- system clock (50MHz)
            
           bitDirIn : in  STD_LOGIC;			  -- User direction request
           vecDfIn : in  STD_LOGIC_VECTOR(7 downto 0); -- Duty factor value 
           bitEnOut : out  STD_LOGIC;
           			  -- Enable pin for Pmod HB5
           bitDirOut : out  STD_LOGIC); -- Dir pin for Pmod HB5
			  
end component ;

Les lignes de code sont placées dans le process de l'iowr. Le port B gère le rapport cyclique du moteur gauche. Le port C gère le bit directionnel des 2 moteurs. Enfin le port D gère le rapport cyclique du moteur droit.

when X"38"  => -- PORTB
              s_vecDfIND <= I_DIN;
              --L_LEDS <= not L_LEDS;
when X"35" => -- PORTC
              s_bitDirING <= I_DIN(0);
       	      s_bitDirIND <= I_DIN(1);
when X"32" => -- PORTD
	      s_vecDfING <= I_DIN;

Les signaux servent à transmettre les informations du composant HB5RefComp à l'io.

--moteur

signal s_vecDfIND        : std_logic_vector( 7 downto 0);
signal s_vecDfING        : std_logic_vector( 7 downto 0);
signal s_bitDirIND       : std_logic;
signal s_bitDirING       : std_logic;

Ceci est le port map du moteur droit du robot. Les bits (bitDirIn,bitDirOut,bitEnOut et vecDfIn) sont envoyés dans l'architecture de l'io grâce à des signaux (s_bitDirIND, DirOutD, EnOutD, s_vecDfIND) que l'on a créé qui font office de fil.

commandeD : HB5RefComp
          port map(    ck         => I_CLK,
		       bitDirIn   => s_bitDirIND,
		       bitDirOut  => DirOutD,
		       bitEnOut   => EnOutD,
	               vecDfIn    => s_vecDfIND);

Programmation de la manette Nunchuk

schéma fonctionnel Nunchuk

Création du composant nunchukTop qui s'introduit dans l'architecture de l'io.

component nunchukTop
	port(     sys_clk : IN std_logic;
		  Init : IN std_logic;
		  readFIFO,i_continue : in std_logic;
		  O_data_nunchuk : out std_logic_vector(7 downto 0);
	          data_present, full, half_full : out std_logic;
		  sda : INOUT  std_logic;
		  scl : INOUT  std_logic);
end component;

commande Nunchuk du composant NunchukTop créé.

commandeNunchuk : nunchukTop
	port map(	O_data_nunchuk => s_odata,
			data_present => s_datap,
			full => s_full, 
			i_continue => s_icontinue,
			readFIFO => s_readFIFO,
			half_full => s_hf,
			sys_clk => I_CLK,
			Init => I_CLR,
			sda => sda,
			scl => scl);

Voici les lignes de commande qui permettent de commander la manette Nunchuk.

iord: process(I_ADR_IO, I_SWITCH,
                  U_RX_DATA, U_RX_READY, L_RX_INT_ENABLED,
                  U_TX_BUSY, L_TX_INT_ENABLED)
when X"23" => 
        Q_DOUT <= s_odata(7 downto 0);
when X"56" => 
        Q_DOUT <= "00000" & s_datap & s_hf & s_full;

iowr: process(I_CLK)
when X"56" =>
	s_icontinue <= I_DIN(0);

Programme C

Ce programme est composé d'une boucle qui gère les différentes directions du robot. Nous avons fait quelques calculs pour déterminer à quelle position il fallait commencer à tourner droite ou à gauche ou encore avancer ou reculer. Il y a 4 sous-programmes qui gèrent le mode marche en avant, en arrière, à droite ou à gauche et un sous-programme qui lit les données envoyées par la manette Nunchuk.


  • Calibrage Joystick analogique :
     -gauche à fond : 0x20
     -droite à fond : 0xE1
     -repos : 0x7F
     -avant à fond : 0xE0
     -arrière à fond : 0x25
     -repos : 0x80


//#include "stdint.h"
#include "avr/io.h"
//#include "avr/pgmspace.h"
#undef F_CPU
#define F_CPU 25000000UL
#include "util/delay.h"
#define DATAPRESENT 2
#define PORTA _SFR_IO8(0x1B)


void readFIFOandAskForNextData(unsigned char nunchukDATA[]);
void enAvant(unsigned char droite, unsigned char gauche);
void enArriere(unsigned char droite, unsigned char gauche); 
void tourneDroite(unsigned char gauche);
void tourneGauche(unsigned char gauche);

int main(int argc, char * argv[])
{ 
  unsigned char nunchukDATA[6],vitesseDroite,vitesseGauche,avant;
  while(1){
    readFIFOandAskForNextData(nunchukDATA);
    if (!(nunchukDATA[5] & 1)) {// Z button
      if (nunchukDATA[1]>0xA0) {vitesseDroite=vitesseGauche=nunchukDATA[1]-0x80; avant=1;}
        else  if (nunchukDATA[1]<0x60) {vitesseDroite=vitesseGauche=0x80-nunchukDATA[1];avant=0; }
          else {vitesseGauche=vitesseDroite=0x00;}
      if (nunchukDATA[0]>0xA0) vitesseDroite = vitesseDroite -nunchukDATA[0]+0x80;
      else  if (nunchukDATA[0]<0x60) vitesseGauche = vitesseGauche + nunchukDATA[0]-0x80;
      if (avant) enAvant(vitesseGauche,vitesseDroite); else enArriere(vitesseGauche,vitesseDroite);
    } else if (!(nunchukDATA[5] & 2)) {// C button
      if (nunchukDATA[2]>0xB0) tourneDroite(0x55);
      else if (nunchukDATA[2]<0x55) tourneGauche(0x55);
           else if (nunchukDATA[3]>0x90) enAvant(0x55,0x55);
                else if (nunchukDATA[3]<0x80) enArriere(0x55,0x55);  
		   else enAvant(0x00,0x00);	
	}
	else enAvant(0x00,0x00);
    PORTA = vitesseGauche;
    _delay_ms(100);
    

}
  return 0;
}



void readFIFOandAskForNextData(unsigned char nunchukDATA[]){
  unsigned char i;
  while(!(TWCR & (1<<DATAPRESENT))); // attente données dans le FIFO 	
  for (i=0;i<6;i++) {//lecture du Nunchuk du FIFO dans tableau
     nunchukDATA[i]=TWDR;
     //PORTA=TWDR;
  }
  // on demande une nouvelle lecture par le pérphérique : toutes données seront pour la prochaine fois
  TWCR |= (1<<0); //depart
  TWCR &= ~(1<<0);// arret pour attendre la prochaine fois : voir machine d'états pour comprendre
}


void enAvant(unsigned char droite, unsigned char gauche) {
// par sécurité toute fonction commence par l'arrêt des moteurs
    PORTD = 0x00;
    PORTB = 0x00;
    _delay_ms(10);
// les deux moteurs en marche avant
// choix de la direction : en avant : voir code iotimer.vhd
    PORTC = 0x02;
    PORTD = droite;
    PORTB = gauche;
}


void enArriere(unsigned char droite, unsigned char gauche) {
// par sécurité toute fonction commence par l'arrêt des moteurs
    PORTD = 0x00;
    PORTB = 0x00;
    _delay_ms(10);
// les deux moteurs en marche arriere
// choix de la direction : en avant : voir code iotimer.vhd
   PORTC = 0x01;
    PORTD = droite;
    PORTB = gauche;
}


void tourneDroite(unsigned char gauche) {
// par sécurité toute fonction commence par l'arrêt des moteurs
    PORTD = 0x00;
    PORTB = 0x00;
    _delay_ms(10);
// les deux moteurs en marche avant
// choix de la direction : en avant : voir code iotimer.vhd
    PORTC = 0x02;
    PORTB = gauche;
}

void tourneGauche(unsigned char droite) {
// par sécurité toute fonction commence par l'arrêt des moteurs
    PORTD = 0x00;
    PORTB = 0x00;
    _delay_ms(10);
// les deux moteurs en marche avant
// choix de la direction : en avant : voir code iotimer.vhd
    PORTC = 0x02;
    PORTD = droite;
}

Voir aussi

Ce chapitre rédigé par les étudiants est complété dans un livre de la Wikiversité rédigé par l'enseignant tuteur :

Projet pour l'année scolaire 2014/2015