Académique Documents
Professionnel Documents
Culture Documents
Robot Vierzon
Tl-transmission Zigbee
Comment rcuprer les informations du robot lorsqu'il suit la ligne
Alexandre Martins
Rsum du projet
Le but de ce projet est de pouvoir rcuprer en temps rel (c'est dire alors que le robot est en activit) le maximum d'informations du robot de Vierzon lorsque celui-ci suit la ligne en comptition. Pour cela nous avons raliser une carte sous protel qui sert relayer les informations rcupres sur le bus CAN du robot et les envoi via une carte Xbee (utilisant le protocole Zigbee) sur un PC quip d'un rcepteur o un programme rcuprera et stockera les informations reues du robot. Cela nous permettra ainsi de pouvoir reprer d'ventuels problmes ou simplement de retracer le trajet et comportement du robot durant son parcours.
Abstract
The goal of this project is to retrieve in realtime (bu realtime we mean while the robot is folowing the line) the maximum of informations about the ligne folower robot of the Vierzon competition. In order to achieve this we have to create hardware and software pieces. The hardware part is used to retrieve data from the CAN network and transmit it to the Xbee module (which uses the Zigbee protocol). The software part in the hardware with a MCU and another part is used in the computer to receive and store the data received. This project will allow us to debug potential anomalies or just reproduce the robot's ride.
Mots-cls
Introduction
Le robot Vierzon est constitu d'une multitude de cartes indpendantes relies pour la plupart par le bus CAN dont la fonction est de permettre au robot de suivre une ligne blanche et raliser diverses actions (tourner sur luimme, laisser une priorit...) de faon autonome et le plus efficace possible. Cependant des erreurs peuvent sur venir durant le parcours et le robot tant autonome (c'est dire que son centre dcisionnel est embarqu et qu'il ne communique pas avec l'extrieur durant son parcours) il est difficile de savoir d'o peut provenir cette erreur. Deux manires de rcolter des informations s'offrent alors nous, la transmission distance en temps rel (c'est dire lorsque le robot est encore en activit sur la piste) ou le stockage sur un support interne au robot (mmoire flash, carte SD...). Nous avons ici choisi la transmission distance. La vise du projet de tl-transmission est d'apporter au robot suiveur de ligne du concour Vierzon un moyen d'envoyer vers un terminal extrieur les informations qui transitent dans celui-ci et influent dans le comportement du robot sur la piste. Ceci est fait lorsqu'il est prsent sur la piste et nous permet en suivant en mme temps le ro bot et le terminal o on reoit les informations (un PC distant) de pouvoir trouver immdiatement d'o peut pro venir l'erreur de jugement du robot et pouvoir ainsi ensuite la corriger. Pour la ralisation de cette fonctionnalit nous allons dcouper le projet en trois parties: une partie hardware (la carte qui permettra la liaison) et deux parties software (une sur la carte cre et l'autre sur le terminal de rception). Cependant avant de se plonger dans le sujet nous allons tout d'abord introduire les protocoles utiliss dans ce projet.
Lors de ce projet nous utilisons une carte Xbee, celle-ci permet d'mettre les donnes qu'elle reoit sous format UART en utilisant le protocole Xbee. Pour de plus amples informations merci de vous rfrer la partie 2.1 de ce document.
pour permettre la communication entre les diffrentes cartes composant le robot. La mise en place de ce bus est dsormais peu couteuse du fait de sa large diffusion de plus il s'agit d'un moyen de transporter les donnes robuste, rapide et efficace tout en utilisant un systme de priorit dans les informations y circulant. La dfinition du bus CAN ne comporte pas de support physique prcis, ici nous avons choisi d'utiliser une ligne diffrentielle. Cette ligne est constitue de deux fils termins par une rsistance de 120 ohms qui les relient. Chaque carte du robot reprsente un noeud (node en anglais) sur le bus, chaque noeud tant indpendant et pouvant tre dconnect du rseau sans influencer son fonctionnement.
souvent sur sa provenance) ainsi que sur sa priorit. Le bus possdant un niveau dominant (0) et un niveau rces sif (1), le plus petit ID aura donc priorit sur un ID numriquement suprieur (du fait du nombre debits rcessifs dont son ID est compos). Voici a titre indicatif la forme d'une trame circulant sur le bus CAN:
2. Constitution d'une trame circulant sur le bus CAN:
2. La gestion des protocoles utiliss est prise en charge par deux composants
Bien que nous utilisons le protocole Zigbee et CAN, leur utilisation est plus ou moins transparente dans le projet tant donn qu'ils sont pris en charge par des composants ddis, nous allons ici vous faire un descriptif des composants utiliss dans ces deux liaisons (Zigbee et bus CAN).
2.1. Le module Xbee permet de transporter une donne reue en UART via Zigbee
Afin de permettre l'envoi via Zigbee des informations receuillies sur le bus CAN nous utilisons le module Xbee dvelopp par Digi.
VCC (1) pour alimenter la carte GND (10) pour alimenter la carte DIN (3), cela nous permettra d'envoyer au module les informations transmettre RSSI (6), afin d'extrapoler le niveau du signal Xbee entre le rcepteur et notre carte (il s'agit d'une PWM) Associate (15), led d'association Xbee elle nous permettra de savoir si le module est associ un autre ou non. Optionnel DOUT (2), afin de recevoir des informations via Zigbee sur notre carte (en vue d'une utilisation dtourne du projet).
L'envoi des donnes vers la carte Xbee ici se fera via une liaison UART, les informations envoyer par liaison Zigbee sont relayes depuis le microcontrolleur jusqu' la pin DIN (3).
donne, pas de bit de parit et un bit stop (niveau haut) comme indiqu sur ce schma: J'ai choisi de ne pas utiliser CTS (Clear To Send) et RTS (Request To Send) afin de simplifier le routage au ni veau du microcontrolleur et de prendre en considration la taille des buffer d'envoi et de rception du module Xbee dans le programme implment sur le microcontrolleur.
Une erreur remarque que bien trop tard lors de la conception de la carte est l'emplacement des condensateurs de dcouplage du microcontrolleur. En effet un plan dtaill est fourni par le constructeur concernant la disposition et le nombre de condensateurs de dcouplage recommands pour le 9S12C128. Notons que nous devons utiliser un transceiver de ligne afin d'utiliser le bus CAN (celui-ci se charge de la mise niveau des signaux issus du microcontrolleur pour les adapter au niveau de la ligne). Le composant utilis pour cela est le MCP2551
Photographie de l-transmission
de Niveau
3.2. Une carte deux niveaux de tension implique deux niveaux de signaux
Une carte avec deux tensions d'alimentation pose aussi le problme de niveau des signaux qui transitent entre les composants aliments deux niveaux de tensions diffrents. C'est le cas ici entre le microcontrolleur et le module Xbee, le niveau haut en sortie du microcontrolleur (+5V) n'tant pas support par le module Xbee (dont la tension maximale supporte en entre est de 3.4V d'aprs le datasheet) et le niveau haut en sortie du module Xbee tant dans la zone indtermine du microcontrolleur nous allons devoir adapter les niveaux de tension entre les deux composants. Pour cela plusieurs pistes ont t suivies (montage avec AOP, transistor, pont diviseur de tension...), deux montages ont t retenu. Pour les donnes dans le sens microcontrolleur Xbee nous avons choisi d'utiliser un montage simple avec une diode zener 3.3V afin d'abaisser le niveau de tension du signal (voir figure 14 droite). Aprs mesure des niveaux, cette diode t remplace par une diode zener de 3.9V, la diode de 3.3V n'autorisant un niveau haut en sortie de 2.1V alors que la nouvelle nous permet d'obtenir les 3.3V dsirs.
3 LED de niveau de signal 1 LED indiquant l'envoi de donnes du bus CAN vers le module Xbee 1 LED indiquant la rception de donne depuis le module Xbee 1 LED indiquant le fonctionnement du microcontrolleur 1 LED indiquant le statut d'association du module Xbee
Toutes les LED de la carte sont cbles de la mme faon et au microcontrolleur, sauf la LED d'association qui est alimente en 3.3V et directement rattache au module Xbee. Les rsistances sont associes une rsistance de pull-up et branches l'entre d'un port du microcontrolleur programm en sortie (voir figure 15), ainsi lorsque le port est au niveau bas, la LED associe s'allume, dans le cas contraire (niveau haut), la diffrence de tension est nulle entre VCC et le port, aucun courant ne circule la LED reste donc en tat bloqu et ne s'allume pas.
4. Programmation du microcontrolleur
Avoir une carte fonctionnelle ne reprsente que la moiti du projet. En effet sans programmation du microcontrolleur la carte de tl-transmission ne serait qu'une carte alimentant le module Xbee avec la LED d'association qui clignoterai mais aucune donne ne serait transmise via Zigbee. On peut dcouper ce programme en deux paties principales, une partie servant envoyer via une liaison srie les donnes vers le module Xbee et une autre qui se chargera de surveiller et rcuprer les trames d'intrt sur le bus CAN.
La valeur de SCIBDL est fix grce la formule prsente dans le datasheet du microcontrolleur:
Dbit =
Nous avons un quartz de 10Mhz adapt sur la carte, le rsultat du calcul est donc SCIBDL=2.71, J'ai donc arrondis 3.
/* FUNCTION NAME: RS232_init * DESCRIPTION * * RETURN * PARAMETER */ void RS232_init (void) { SCIBDH = 0x00; SCIBDL = 0x03; SCICR1 = 0x04; SCICR2 = 0x08; SCISR2 = 0x02; } // Baudrate de 115200: 0x03 (valeur exacte:2.71) // // Module d'emission seulement activ // Broche TXD en mode sortie : Initialise la liaison serie a 115200b/s, 8 bits, parite paire, interruptions activees en emission : void 1 : void
void initialisation_port(void) { asm{__cli;} DDRT = 0xFF; // Port T en sortie TIOS &= ~0x07; //Input capture pour T0 T1 T2 TSCR1 |= 0x80; //Active le bloc de timer TCTL4 |= 0x3F; //Activation chaque fronts montants et fronts descendants TIE |= 0x07; //Activation des interruptions sur les channels 0,1 et 2
4.1.2. Programme d'envoi des informations en UART avec utilisation des interruptions Les fonctions d'envoi de donnes sont au nombre de deux. La fonction RS232_snd_msg est appele dans le programme main ou une sous-fonction. Le message a envoyer est indiqu en paramtre. Dans cette fonction copie le message envoyer dans un tableau (buffer) et active les interruptions sur le microcontrolleur.
/* FUNCTION NAME: RS232_snd_msg * DESCRIPTION * RETURN * PARAMETER */ : Ralise l'mission d'un message termin par le caractre '\0'. : void 1 : INT8U* chaine de caractre a envoyer
char cpt=0; while (chaine[cpt]!='\0') { buffer[cpt]=chaine[cpt]; cpt++; } buffer [cpt+1] = '\0'; SCICR2 |= 0xC0; //TCIE et TIE =1 (activation des interruptions)
Une fois les interruptions actives, la fonction RS232_sc est appele chaque fin d'envoi d'un caractre de la chaine jusqu' ce qu'on atteigne la fin de la chaine (reprsente par le caractre '\0') o les interruptions sont de nouveau dsactives.
interrupt SCI0_ISR void envoi_de_caractere(void) { RS232_sc (); }
/* FUNCTION NAME: RS232_sc * DESCRIPTION * RETURN * PARAMETER */ void RS232_sc (void) { static char i=0, tmp=0; if ((SCISR1 & MASK_TDRE) == MASK_TDRE) { if (buffer[i]!='\0') { if (i==0) PTT &= ~MASK_LED_OUT; : Ralise l'envoie d'un caractre ASCII sur la liason srie : void : void
SCIDRL=buffer[i]; i++; } else { i=0; PTT |= MASK_LED_OUT; SCICR2 &= ~0xC0; } // Dsactivation des interruptions
} }
/*--------------------------------------------------------------------------*/
int comport = 7, baudRate = 115200, parity = NON, dataBits = 8, stopBits = 1, xonXoff = NON, timeout = 10,
// No du port COM // Baudrate // Bits de parits (0 = aucun) // Bits de donne // Nombre de bits stop // Spcifie si le mode Xon Xoff est utilis // Temp de latence (en secondes)
readCount = 499, // Nombre de bits a prendre en compte dans le message (avant de quitter la fonction de lecture) readTerm = 13, riage return CR = 13; ou linefeed LF = 10) portOpen = 0, bytesRead = 0, comStatus = 0, rs232Error, inputQueue = 500, outputQueue = 500; // Dtermine le caractre de fin de trame (car// Port COM ouvert (1) ou non (0) // Nombre de bits lus // Status du port COM // Variable en cas d'erreur // Taille du buffer de reception // Taille du buffer d'mission
// Pointeur vers le fichier txt // Pointeur vers le fichier csv (spars par vir// Variable de type time_t qui contiendra l'heure
et la date
Dans la fonction main la liaison avec le port srie est initialise et le programme boucle pour surveiller les changements sur le port COM. Pour viter de probables conflits les anciens fichiers de log prsents dans le dossier sont supprims (par scurit)
void main (void) { printf ("Demarrage du programme RS232... \n"); printf ("Ouverture du port COM %i avec un Baudrate de %i, parite: %i, bits de donnee : %i, bits stop: %i. \n", comport, baudRate, parity, dataBits, stopBits); PortConfig (); RemoveFileIfExists ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.txt"); RemoveFileIfExists ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.csv"); if (portOpen) { printf ("Port COM %i ouvert avec succes \n", comport); printf ("En attente de message... \n"); while (1) ReceiveData (); } else MessagePopup ("Erreur", "Erreur dans l'initialisation du port COM, fermeture du programme"); }
Dans ReceiveData la fonction ComRdTerm est utilise, celle-ci surveille le port et copie les donnes reues dans readData jusqu' ce que le nombre maximum de caractres soit atteind ou qu'un caractre en particulier soit observ.
void ReceiveData (void) { int i; readData[0] = '\0'; bytesRead = ComRdTerm (comport, readData, readCount, readTerm); // ComRdTerm lis les bits sur le port jusqu'au byte de terminaison dfini (retourne le nombre de bits la trame)
de
if (bytesRead != 0) { if (bytesRead == readCount) printf ("\n\n !!!! Attention le message ci-dessous est probable ment incomplet !!!!"); printf ("\n Message recu de %i caracteres: \n \t %s", bytesRead, readDa ta); // MessagePopup ("Message recu", readData); FillFile (); for (i=0; i<bytesRead; i++) readData[i] = '\0'; bytesRead = 0;
} }
Finalement la fonction FillFile va inscrire les donnes reues dans la fonction prcdente da s un fichier. Pour cela elle vrifie que les fichiers log soient accssibles en criture, puis les ouvre pour les manipuler. S'en suit un appelle la fonction retrieveCurrentTime afin de dterminer la date et l'heure puis utilise fprintf pour crire les donnes dans les fichiers avant de les fermer nouveau (et viter qu'ils ne soient pas accssibles en criture pour un prochain appel).
void FillFile (void) { int write_txt=0, write_csv=0, cpt=0; GetFileWritability ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.txt", &write_txt); dans le fichier GetFileWritability ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.csv", &write_csv); dans le fichier // Test si on peut c rire
if (write_txt && write_csv) { fichier_txt = fopen ("E:/Etudes/GEII semestre 4/Projet Zigbee/Prog_PC/RS232_perso/rs232_data.txt", "a"); fichier_csv = fopen ("E:/Etudes/GEII semestre 4/Projet Zigbee/Prog_PC/RS232_perso/rs232_data.csv", "a"); if (fichier_txt == NULL || fichier_csv == NULL) MessagePopup ("Erreur","Erreur d'ouverture de fichier"); // Ouvre le fichier // Ouvre le fichier
RetrieveCurrentTime (); fprintf (fichier_txt, "%s \t %s \n", date, readData); // Ecris les donnes recues dans le fichier txt fprintf (fichier_csv, "%s,%s \n", date, readData); // Ecris les donnes recues dans le fichier csv
fclose(fichier_txt); fclose(fichier_csv); } else MessagePopup ("Erreur", "Impossible de complter le fichier log, fichier prot g en criture"); } void RetrieveCurrentTime (void) { heure = time(NULL); strftime(date, sizeof(date), "%H:%M:%S", localtime(&heure)); }
(tel que la mise en place d'une interface graphique ou l'ajout d'une tche spcialise dans le RTOS dvelopp par Nathan Clerbout) aux vues du retard pris sur la conception de la carte de tl-transmission.
Annexe
Contenu de l'annexe:
Diagramme de Gantt du projet (ancien et actuel) Schma lectrique de la carte de tl-transmission PCB de la carte de tl-transmission Programme de rception sur PC (perso.c) Programme du microcontrolleur 9S12C128 de la carte de tl-transmission (version du 05/04/10) Extraits du datasheet du module Xbee Extrait du datasheet du LM2937-3.3 Extrait du datasheet du 74LS07
/********************************************************************************** * Perso.c * * Auteur: Alexandre Martins * * Date de rvision: 01/02/2010 * * Version: 0.1 * * Utilit : Ce fichier contient les fonctions permettant la * * rception et le stockage des donnes recues via le RS232 * * du PC * * * **********************************************************************************/ /*--------------------------------------------------------------------------*/ /* Includes */ /*--------------------------------------------------------------------------*/ #include "toolbox.h" #include <ansi_c.h> #include <cvirte.h> #include <userint.h> #include <rs232.h> #include <utility.h> #include <formatio.h> #include <string.h> #include <time.h> /*--------------------------------------------------------------------------*/ /* Defines */ /*--------------------------------------------------------------------------*/ #define OUI 1 #define NON 0 /*--------------------------------------------------------------------------*/ /* Dfinition des fonctions */ /*--------------------------------------------------------------------------*/ void DisplayComStatus (void); void ReceiveData (void); void FillFile (void); void PortConfig (void); void RetrieveCurrentTime (void); /*--------------------------------------------------------------------------*/ /* Variables globales */ /*--------------------------------------------------------------------------*/ int comport = 7, baudRate = 115200, parity = NON, dataBits = 8, stopBits = 1, xonXoff = NON, timeout = 10, readCount = 499, de lecture) readTerm = 13, 10) portOpen = 0, bytesRead = 0, comStatus = 0, rs232Error, inputQueue = 500, outputQueue = 500; char readData[500], com_msg[500], deviceName[10]= "COM7", date[10]; FILE *fichier_txt; FILE *fichier_csv; time_t heure; // // // // // // // // No du port COM Baudrate Bits de parits (0 = aucun) Bits de donne Nombre de bits stop Spcifie si le mode Xon Xoff est utilis Temp de latence (en secondes) Nombre de bits prendre en compte dans le message (avant de quitter la fonction
// Dtermine le caractre de fin de trame (carriage return CR = 13; ou linefeed LF = // // // // // // Port COM ouvert (1) ou non (0) Nombre de bits lus Status du port COM Variable en cas d'erreur Taille du buffer de reception Taille du buffer d'mission
// Tableau avec le message recu // Nom du port COM // Pointeur vers le fichier txt // Pointeur vers le fichier csv (spars par virgules) // Variable de type time_t qui contiendra l'heure et la date
/*--------------------------------------------------------------------------*/ /* Fonctions */ /*--------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------*/ /* Main */ /* Arguments : Aucun */ /* Sorties : Aucune */ /* Utilit : Fonction main du programme (appel fonctions) */ /*---------------------------------------------------------------------------------------------*/ void main (void) { printf ("Demarrage du programme RS232... \n"); printf ("Ouverture du port COM %i avec un Baudrate de %i, parite: %i, bits de donnee : %i, bits stop: %i. \n", comport, baudRate, parity, dataBits, stopBits); PortConfig (); RemoveFileIfExists ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.txt"); RemoveFileIfExists ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.csv"); if (portOpen) { printf ("Port COM %i ouvert avec succes \n", comport); printf ("En attente de message... \n"); while (1) ReceiveData (); } else MessagePopup ("Erreur", "Erreur dans l'initialisation du port COM, fermeture du programme"); } /*----------------------------------------------------------------------------------------------*/ /* PortConfig */ /* Arguments : Aucun */ /* Sorties : Pop-up */ /* Utilit : Permet l'ouverture et l'init du port COM */ /*----------------------------------------------------------------------------------------------*/ void PortConfig (void) { portOpen = 0; /* initialize flag to 0 - unopened */ rs232Error = OpenComConfig (comport, deviceName, baudRate, parity, dataBits, stopBits, inputQueue, outputQueue); comStatus = GetComStat (comport); DisplayComStatus (); if (rs232Error == 0 && comStatus == 0) { portOpen = 1; SetXMode (comport, xonXoff); // Active ou non le mode Xon-Xoff SetComTime (comport, timeout); // Dfini le timeout } else MessagePopup ("Erreur", "Erreur lors de l'initialisation"); } /*----------------------------------------------------------------------------------------------*/ /* DisplayComStatus */ /* Arguments : Aucun */ /* Sorties : Pop-up */ /* Utilit : Affiche par pop-up l'tat du port COM */ /*----------------------------------------------------------------------------------------------*/ void DisplayComStatus (void) { com_msg[0] = '\0'; if (comStatus & 0x0001) strcat (com_msg, "Input lost: Input queue" " filled and characters were lost.\n"); if (comStatus & 0x0002) strcat (com_msg, "Asynch error: Problem " "determining number of characters in input queue.\n"); if (comStatus & 0x0010) strcat (com_msg, "Parity error.\n"); if (comStatus & 0x0020) strcat (com_msg, "Overrun error: Received" " characters were lost.\n"); if (comStatus & 0x0040) strcat (com_msg, "Framing error: Stop bits were not received" " as expected.\n"); if (comStatus & 0x0080) strcat (com_msg, "Break: A break signal was detected.\n"); if (comStatus & 0x1000) strcat (com_msg, "Remote XOFF: An XOFF character was received." "\nIf XON/XOFF was enabled, no characters are removed"
" from the output queue and sent to another device " "until that device sends an XON character.\n"); if (comStatus & 0x2000) strcat (com_msg, "Remote XON: An XON character was received." "\nTransmisson can resume.\n"); if (comStatus & 0x4000) strcat (com_msg, "Local XOFF: An XOFF character was sent to\n" " the other device. If XON/XOFF was enabled, XOFF is\n" " transmitted when the input queue is 50%, 75%, and 90%\n" " full.\n"); if (comStatus & 0x8000) strcat (com_msg, "Local XON: An XON character was sent to\n" " the other device. If XON/XOFF was enabled, XON is\n" " transmitted when the input queue empties after XOFF\n" " was sent. XON tells the other device that it can \n" " resume sending data.\n"); if (strlen (com_msg) == 0) strcat (com_msg, "No status bits are set."); MessagePopup ("RS232 Message", com_msg); } /*----------------------------------------------------------------------------------------------*/ /* ReceiveData */ /* Arguments : Aucun */ /* Sorties : Pop-up ou texte et fichier */ /* Utilit : Lis, affiche et stocke les donnes recues */ /*----------------------------------------------------------------------------------------------*/ void ReceiveData (void) { int i; readData[0] = '\0'; // bytesRead = ComRd (comport, readData, readCount); // ComRd lis les bits sur le port jusqu'a ce que le compte soit atteint (retourne le nombre de bits de la trame) bytesRead = ComRdTerm (comport, readData, readCount, readTerm); // ComRdTerm lis les bits sur le port jusqu'au byte de terminaison dfini (retourne le nombre de bits de la trame) if (bytesRead != 0) { if (bytesRead == readCount) printf ("\n\n !!!! Attention le message ci-dessous est probablement incomplet !!!!"); printf ("\n Message recu de %i caracteres: \n \t %s", bytesRead, readData); MessagePopup ("Message recu", readData); FillFile (); for (i=0; i<bytesRead; i++) readData[i] = '\0'; bytesRead = 0; } } /*----------------------------------------------------------------------------------------------*/ /* FillFile */ /* Arguments : Aucun */ /* Sorties : Fichier text */ /* Utilit : Rempli le fichier de sortie (doit tre init) */ /*----------------------------------------------------------------------------------------------*/ void FillFile (void) { int write_txt=0, write_csv=0, cpt=0; GetFileWritability ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.txt", &write_txt); // Test si on peut crire dans le fichier GetFileWritability ("E:\\Etudes\\GEII semestre 4\\Projet Zigbee\\Prog_PC\\RS232_perso\\rs232_data.csv", &write_csv); // Test si on peut crire dans le fichier if (write_txt && write_csv) { fichier_txt = fopen ("E:/Etudes/GEII semestre 4/Projet Zigbee/Prog_PC/RS232_perso/rs232_data.txt", "a"); // Ouvre le fichier fichier_csv = fopen ("E:/Etudes/GEII semestre 4/Projet Zigbee/Prog_PC/RS232_perso/rs232_data.csv", "a"); // Ouvre le fichier if (fichier_txt == NULL || fichier_csv == NULL) MessagePopup ("Erreur","Erreur d'ouverture de fichier"); RetrieveCurrentTime (); fprintf (fichier_txt, "%s \t %s \n", date, readData); // Ecris les donnes recues dans le fichier txt fprintf (fichier_csv, "%s,%s \n", date, readData); // Ecris les donnes recues dans le fichier csv fclose(fichier_txt); fclose(fichier_csv); }
//
else MessagePopup ("Erreur", "Impossible de complter le fichier log, fichier protg en criture"); } /*----------------------------------------------------------------------------------------------*/ /* RetrieveCurrentTime */ /* Arguments : Aucun */ /* Sorties : Date sous forme de chaine de caractre */ /* Utilit : Cre une chine de caractre contenant l'heure */ /*----------------------------------------------------------------------------------------------*/ void RetrieveCurrentTime (void) { heure = time(NULL); strftime(date, sizeof(date), "%H:%M:%S", localtime(&heure)); }
/********************************************************************************** * Main.c * * Auteur: Alexandre Martins * * Date de rvision: 05/04/2010 * * Version: 2.1 * * Utilit : Programme main de la carte pour module Xbee * * * **********************************************************************************/ #include <hidef.h> /* common defines and macros */ #include <MC9S12C128.h> /* derivative information */ #include "STAR12.H" #include "IDENTIFIER.H" void initialisation_port(void); long i=0; INT8U can_rx_ready=0,can_tx_ready=0; T_MSCAN_frame rx_message; void main(void) { unsigned short cpt=0; unsigned char tableau[100] = "Telemetrie Zigbee -"; initialisation_port(); // Initialisation des registres EnableInterrupts; // Activation des interruptions TIMER_init(kPRE1); // Initialisation des Timers MSCAN0_init(); // Initialisation du bus CAN RS232_init(); // Initialisation de la liaison srie RS232_snd_msg (tableau); for(i=0;i<200000;i++); CANRIER_RXFIE = 1; // enable RX interrupt while(1) { RS232_snd_trame (rx_message.data); CANRIER_RXFIE = 1; // enable RX interrupt } } void initialisation_port(void) { DDRT = 0xFF; // Port T en sortie for(i=0;i<200000;i++); PTT = 0x00; // Allumage des LED for(i=0;i<200000;i++); PTT = 0xFF; // Extinction des LED TIOS &= ~0x07; //Input capture pour T0 T1 T2 TSCR1 |= 0x80; //Active le bloc de timer TCTL4 |= 0x3F; //Activation chaque fronts montants et fronts descendants TIE |= 0x07; //Activation des interruptions sur les channels 0,1 et 2 TSCR2 |= 0x06; // Rglagle du prescaler 2^6=64 } interrupt 11 void TIMER_int(void) { TFLG1 |= 0x08; // Remise zro du Flag } interrupt SCI0_ISR void envoi_de_caractere(void) { RS232_sc (); } interrupt CAN0RX_ISR void CAN_Rx_isr(void) { MSCAN0_Rx (&rx_message); CANRIER_RXFIE = 0; // disable RX interrupt }
/********************************************************************************** * rs232.c * * Auteur: Alexandre Martins * * Date de rvision: 05/04/2010 * * Version: 2.1 * * Utilit : Fonctions RS232 pour module Xbee * * * **********************************************************************************/ #include <hidef.h> /* common defines and macros */ #include <MC9S12C128.h> /* derivative information */ #include "STAR12.H" #include "IDENTIFIER.H" /******************************************************************************/ /* VARIABLES: */ /******************************************************************************/ void RS232_snd_trame (INT8U* chaine); U8 BUFFERFULL, BUFFEREMPTY, CARAC; char buffer [512]; /******************************************************************************/ /* FUNCTIONS: */ /******************************************************************************/ /* * FUNCTION NAME: RS232_init * DESCRIPTION : Initialise la liaison srie 19200b/s, 8 bits, parit paire, * interruptions actives en rception * RETURN : void * PARAMETER 1 : void */ void RS232_init (void) { SCIBDH = 0x00; SCIBDL = 0x03; // Baudrate de 115200: 0x03 (valeur exacte:2.71) SCICR1 = 0x04; SCICR2 = 0x08; // Module d'emission seulement activ SCISR2 = 0x02; // Broche TXD en mode sortie } /* * FUNCTION NAME: RS232_sc * DESCRIPTION : Ralise l'envoie d'un caractre ASCII sur la liason srie * RETURN : void * PARAMETER 1 : INT8U caractre envoyer */ void RS232_sc (void) { static char i=0, tmp=0; if ((SCISR1 & MASK_TDRE) == MASK_TDRE) { if (buffer[i]!='\0') { if (i==0) PTT &= ~MASK_LED_OUT; SCIDRL=buffer[i]; i++; } else { i=0; PTT |= MASK_LED_OUT; SCICR2 &= ~0xC0; // Dsactivation des interruptions } } } /* * FUNCTION NAME: RS232_snd_msg * DESCRIPTION : Ralise l'mission d'un message termin par le caractre '\0'. * l'envoie des caractre utilise le smaphore BUFFEREMPTY * RETURN : void * PARAMETER 1 : INT8U* chaine de caractre envoyer */ void RS232_snd_msg (INT8U* chaine) { char cpt=0;
while (chaine[cpt]!='\0') { buffer[cpt]=chaine[cpt]; cpt++; } buffer [cpt+1] = '\0'; SCICR2 |= 0xC0; //TCIE et TIE =1 (activation des interruptions) } void RS232_snd_trame (INT8U* chaine) { char cpt; for (cpt=0;cpt<8;cpt++) { buffer[cpt]=chaine[cpt]; } buffer [cpt+1] = '\0'; SCICR2 |= 0xC0; //TCIE et TIE =1 (activation des interruptions) }
/********************************************************************************** * can.c * * Auteur: Alexandre Martins * * Date de rvision: 05/04/2010 * * Version: 2.1 * * Utilit : Fonctions bus CAN pour module Xbee * * * **********************************************************************************/ #include "ERROR.H" #include "STAR12.H" #include "pwm.h" #define NULL (void*)0 void MSCAN0_init(void){ INT8U baud_rate_prescaler; INT8U sjw; INT8U extra_sampling; INT8U time_segment_1; INT8U time_segment_2; INT8U EIGTH_11BIT_ACCEPTANCE_FILTERS = 0x10; baud_rate_prescaler= 1; sjw=2; extra_sampling = FALSE; //quartz 10 Mhz time_segment_1 = 7; // Notes: baud_rate_prescaler*(time_segment_1+time_segment_2+1)=2*sys_clock_per_sec time_segment_2 = 2;
if(CANCTL1_CANE!=1) CANCTL1_CANE=1; while (CANCTL1_CANE!=1); if (CANCTL1_INITAK==0){ // If not in init mode CANCTL0=CANCTL0_INITRQ_MASK ; // then request for init mode while (CANCTL1_INITAK==0); // and wait init mode ack } CANCTL1_LISTEN=0; CANCTL1_CANE=1; //enable CAN module CANCTL1_CLKSRC=0; CANCTL1_LOOPB=0; CANCTL1_LISTEN=0; CANBTR0 = ((3&(sjw-1))<<6) | ((baud_rate_prescaler-1) & 0x3f); CANBTR1 = ((1&extra_sampling)<<7)|((7&(time_segment_2-1))<<4)|(0x0F&(time_segment_1-1)); CANIDAC = EIGTH_11BIT_ACCEPTANCE_FILTERS; CANIDMR0 = 0xFF; // Hit for all ID CANIDAR0 = 0x00; CANIDMR1 = 0xFF; // Hit for all ID CANIDAR1 = 0x00; CANIDMR2 = 0xFF; // Hit for all ID CANIDAR2 = 0x00; CANIDMR3 = 0xFF; // Hit for all ID CANIDAR3 = 0x00; CANIDMR4 = 0xFF; // Hit for all ID CANIDAR4 = 0x00; CANCTL0 &= ~0x01; // initreq=0: exit from init mode while (CANCTL1_INITAK!=0); // wait for ack // Attente de synchronisation du MSCAN while(!(CANCTL0&CANCTL0_SYNCH_MASK)) ; // CANRIER = CANRIER_RXFIE_MASK; // enable RX interrupt // CANTIER = CANTIER_TXEIE_MASK; // enable TX interrupt } INT8U MSCAN0_Tx (T_MSCAN_frame * p_message){ int i; INT8U can_tx_buffer_num; INT8U * CANTXDSR = &CANTXDSR0; ErrorIf(CANCTL0_SYNCH!=1,"CAN: no sychro"); CANTBSEL = CANTFLG; // select the lowest free tx buffer
can_tx_buffer_num = CANTBSEL; //ErrorIf (can_tx_buffer_num==0,"CAN:No free buffer"); if (!can_tx_buffer_num) return TRUE; CANTXIDR0 = (p_message->id&0xFC)>>3; CANTXIDR1 = p_message->id<<5; if(p_message->remote_transmitt_request) { CANTXIDR1 |= 0x10; } for (i=0;i<p_message->length;i++){ CANTXDSR[i] = p_message->data[i]; } CANTXDLR = p_message->length; CANTXTBPR = p_message->priority; CANTFLG = can_tx_buffer_num; return FALSE; } INT8U MSCAN0_Rx (T_MSCAN_frame * p_message){ INT8U * CANRXDSR = &CANRXDSR0; INT8U i; if (CANRFLG_RXF==0) return FALSE; // if (CANRXIDR1&0x08) return FALSE; p_message->id = ((CANRXIDR0<<3)&0x0700) | (INT8U)(CANRXIDR0<<3) | (INT8U)(CANRXIDR1>>5); p_message->remote_transmitt_request = (CANRXIDR1_SRR==1); p_message->length = CANRXDLR; for(i = 0; i < p_message->length; i++) { p_message->data[i] = CANRXDSR[i]; } CANRFLG &= ~0x01; return TRUE; } INT8U MSCAN0_CheckRcvdMsg(void) { return (CANRFLG_RXF==1); } INT8U MSCAN0_CheckTxBufReady(void) { return (CANTFLG_TXE!=0); } // Envoi un message sur le bus CAN void CAN_EnvoiMess(short int ID,unsigned char length, unsigned char* mess) { INT8U C_R=0; unsigned char i; T_MSCAN_frame canmess; // NB : Vrifier que c'est bien while(! et non while( while(!MSCAN0_CheckTxBufReady()); canmess.id=ID; canmess.length=length; for(i=0;i<length;i++) { canmess.data[i]=mess[i]; } canmess.remote_transmitt_request=0; do { C_R=MSCAN0_Tx(&canmess);} while (!C_R); } // Envoi un "drapeau"(message ne contenant pas de donne) sur le bus CAN void CAN_EnvoiDrapeau(short int ID){ // NB : Vrifier que c'est bien while(! et non while( while(!MSCAN0_CheckTxBufReady()); CAN_EnvoiMess(ID,0,NULL); }
// Envoi une requte sur le bus CAN. void CAN_EnvoiReq(short int ID) { T_MSCAN_frame canmess; // NB : Vrifier que c'est bien while(! et non while( while(!MSCAN0_CheckTxBufReady()); canmess.id=ID; canmess.remote_transmitt_request=1; MSCAN0_Tx(&canmess); }
Universit Paris-Sud IUT de Cachan Dpartement Geii-1 Parcours [ROBO-OS] Anne 2010
Asservissement du suivi de ligne par capteur CCD sur carte FPGA DE0
Klfa SANE
Klfa San
Rapport de projet S4
Page 2
Rsum
Pour le concours de robotique runissant les IUT Geii de France chaque anne Vierzon, un groupe dtudiant de lIUT de Cachan doivent concevoir un robot capable de suivre une ligne, le travaille que je devais faire au sein de ce groupe est lasservissement du suivi de ligne par capteur CCD sur une carte FPGA.
Abstract
For the contest of robotics joining together the IUT Geii of France each year at Vierzon , a group of student of the IUT of Cachan must design a robot able to follow a line, the work that I have to do in the group is the control of the follow of line by sensor CCD on a FPGA card.
Mots-cls
- Asservissement - TSL3301LF - capteur CCD -VHDL -carte FPGA DE0
Introduction
Comme chaque anne durant le semestre 4, les tudiants du parcours ROBOS de lIUT de Cachan participe au concours de robotique inter IUT Geii Vierzon, cette anne 8 tudiants vont devoir concevoir un robot capable de suivre une ligne le plus rapidement possible, le projet t rparti entre ces 8 tudiants. Mon objectif a t de raliser lasservissement du suivi de ligne, pour cela jai du tudier le capteur CCD sur lequel jallai travailler, son principe de fonctionnement, comment le mettre en uvre ensuite je devais raliser la carte dacquisition supportant le capteur et programmer sa mise en uvre en VHDL afin de recueillir les informations ncessaire me permettant de dlivrer les commandes moteurs pour que le robot puisse suivre la ligne.
Klfa San
Rapport de projet S4
Page 3
Figure 1 Boitier du TSL3301LF 1. Brochage du TSL3301LF Broche SCLK Vdd SDIN SDOUT GND NC Numro 1 2 3 4 6,7 5,8 Entre/Sortie Entre Entre Sortie Description Horloge systme du capteur Tension dalimentation positive (3V 5,5V) Entre de donnes (les donnes sont synchronises sur front montant de SCLK) Sortie de donnes (les donnes sont synchronises sur front descendant de SCLK) Masse Non Connect
Le TSL3301LF est implant dans un boitier de type DIP 8 (cf. Figure 1), il a deux entres une horloge synchronisation SCLK et une de commande SDIN. Il dispose dune seule sortie de donnes SDOUT.
Klfa San
Rapport de projet S4
Page 4
Certaines commandes comme celle de lecture vont provoquer une rponse du capteur, qui se fera au bout dun certain temps pour REGRead, il faut attendre un dlai de 4 priodes dhorloge avant le dbut de la rponse qui sera envoye sur SDOUT toujours avec le mme protocole (cf. Figure 4) la commande est dfinie par loctet <011a4_a3a2a1a0> (cf. Tableau 2), les bit a0 a4 reprsentent les 5 bit de poids faible de ladresse du registre dont on veut lire la valeur. Un dlai plus long de 44 priodes dhorloge est requis pour READPixel qui va nous envoyer les valeurs des 102 photodiodes sur cod sur 8 bits en continu les unes aprs les autres spares par des bits Stop et Start.
Klfa San
Rapport de projet S4
Page 5
Les 102 photodiodes du TSL3301LF sont rpartis en 3 groupes de 34 pour chaque groupe on peut programmer une valeur de gain et doffset sparment des autres, les valeurs doffset et gain sont dfinir dans des registres que lon identifie grce leur adresse (cf. Tableau 3), on rgle une valeur doffset sur 8 bits les valeurs allant de 0x00 0x7F reprsente un offset positif et de 0x80 0xFF un offset ngatif, le gain quant lui est sur 5 bits et la valeur maximale que lon peut rgler est de 31 en dcimal. Pour mettre une valeur dans un registre on utilise la commande REGWrite, elle est dfinie en envoyant loctet <010a4_a3a2a1a0> (cf. Tableau 2), les bits a0 a4 reprsentent les 5 bit de poids faible de ladresse du registre suivi de loctet <d7d6d5d4_d3d2d1d0> qui reprsente la valeur que lon veut mettre dans le registre.
3. Registres du TSL3301LF Adresse du registre 0x00 0x01 0x02 0x03 0x04 0x05 0x1F Description du registre Offset photodiodes (0 33) Gain photodiodes (0 33) Offset photodiodes (34 67) Gain photodiodes (34 67) Offset photodiodes (66 101) Gain photodiodes (66 101) Mode de fonctionnement du capteur Taille du registre en bit 8 5 8 5 8 5 8
Le TSL3301LF peut tre mis en SLEEP MODE c'est--dire teindre tous les circuits analogique du capteur, pour le mettre en SLEEP MODE il faut crire la valeur 1 sur le bit 4 SLP (cf. Figure 5) du registre ou 0 pour le mode normal de fonctionnement, les autres bits du registre ne nous sont daucune utilit et doivent tre mis 0, donc les uniques valeurs que lon peut mettre dans le registre sont 0x00 et 0x40, il est ncessaire dattendre une 1 milliseconde avant dutiliser une commande pour permettre au capteur de sortir du SLEEP MODE.
Klfa San
Rapport de projet S4
Page 6
Klfa San
Rapport de projet S4
Page 7
Figure 9 Symbole logique du SN65LVDS9637 4. Table de vrit du SN65LVDS9637 Entre diffrentielle A, B A-B >= 100mV -100mV < A-B < 100mV A-B <= -100mV Sortie Y H ? L
Figure 10 Symbole logique du DS90LV017A 5. Table de vrit du DS90LV017A Entre DI H Sortie DO+ H Sortie DOL
Voici un exemple des signaux diffrentiels du signal SDIN mis par la carte FPGA DE0 :
Klfa San
Rapport de projet S4
Page 8
Figure 12 Schma de cblage de la norme LVDS en sortie du Cyclone III Extrait de la datasheet du Cyclone III
Pour le seul signal SDOUT allant de la carte CCD la DE0 il nest pas ncessaire de cbler les 3 rsistances car les signaux en diffrentiels en sortie du DS90LV017A sont bien dans la gamme de tension de la norme LVDS, mais il faut toujours placer une rsistance de 100 sur les 2 entres diffrentielles de la DE0 (cf. Figure 13).
Figure 13 Schma de cblage de la norme LVDS en entre du Cyclone III Extrait de la datasheet du Cyclone III
Suite a jai dcid de raliser le schma de cblage complet sur une carte Labdec (cf. Figure 14), en plaant les 3 rsistances Rs 120 et Rp 160 pour les signaux SCLK et SDIN et la rsistance de 100 sur les 2 entres diffrentielles de la DE0 pour SDOUT. Cette carte me permettra de faire mes tests sur la chaine dacquisition complte, mais elle sera intgrer dans la carte dinterface ralise par mon collgue Nathan Clerbout qui relie tous les lments du robot camra, carte moteur, carte CCD
Klfa San
Rapport de projet S4
Page 9
Klfa San
Rapport de projet S4
Page 10
Le Schematic termin je suis pass au routage de la carte (cf. Figure 16) en dessinant les pistes reliant les composants, pour raliser au mieux cette tche jai rflchi sur le placement des composants, le capteur CCD devait tre plac au centre et sur le ct bottom pour tre face la piste, en fonction de cela jessayais de plac le reste des composants de faon avoir des pistes le plus droit possible et faire le moins de strap ce fut un travail long et fastidieux, mais cela en valait la peine car la carte parfaitement bien fonctionn du premier coup, je nai donc pas eu la modifier.
Jai du raliser une deuxime carte me permettant de commencer mes tests en attendant larriver des composants LVDS qui ont d tre commands (cf. Figure 17).
Klfa San
Rapport de projet S4
Page 11
Klfa San
Rapport de projet S4
Page 12
Klfa San
Rapport de projet S4
Page 13
4. Implantation en VHDL
La majeure partie de mon projet aura t de faire de la programmation en VHDL sur la carte FPGA DE0, il a fallu que je ralise lautomate dinitialisation et de contrle du capteur CCD et un autre automate en parallle dont le but tait de rcuprer les valeurs des 102 photodiodes et de raliser un traitement dessus pour recueillir les informations ncessaires pour raliser lasservissement du suivi de ligne.
Figure 20
On doit ensuite modifier le I/O Standard en remplaant 3.3-V LVTTL par LVDS_E_3R si le signal est en sorite, si il est en entre on remplace par LVDS (cf. Figure 21).
Figure 21
On remarque par ailleurs que sur la colonne Differential Pair lapparition des signaux diffrentiels inverss SCLK(n), SDIN(n) et SDOUT(n) (cf. Figure 22).
Figure 22
Les signaux diffrentiels inverss sont aussi dfinis la fin du tableau (cf. Figure 23).
Figure 23
Klfa San
Rapport de projet S4
Page 14
Il faut ensuite les assigns sur les broches dun des 2 connecteurs 40 broches de la DE0 qui sont dfinit dans les I/O Bank 3 et 4, dont les noms commencent par GPIO0_D[*] et GPIO1_D[*] avec un numro entre crochet. Je vais assigner SCLK sur la broche GPIO0_D[1] qui dfinit en Location par PIN_AA16, un message derreur apparait, il nous dit que le broche est dj assign (cf. Figure 24).
Figure 24
On doit donc trouver dans le tableau la broche GPIO0_D[1] est la supprimer ainsi que la broche dont la Location est PIN_AB16 (GPIO0_D[0]) (cf. Figure 25).
Figure 25
Une fois les 2 broches supprimes on peut assigner le signal SCLK sur lancienne broche GPIO0_D[1] (cf.Figure 25).
Figure 26
Klfa San
Rapport de projet S4
Page 15
Le signal diffrentiel invers SCLK(n) est quant lui directement assign en mme temps sur lancienne broche GPIO0_D[0] dons le Location tait PIN_AB16 (cf.Figure 27).
Figure 27
Pour les autres signaux il suffit de refaire les mmes manipulations en assignant les signaux diffrentiels non invers SDIN et SDOUT sur des broches dont la Location commence par PIN_AA suivi dun numro les signaux invers SDIN(n) et SDOUT(n) seront directement assign sur les broches dont la Location commence par PIN_AB suivi du mme numro.
Wait 5 MODE WRITE Wait 1ms Reset cpt Reg Add G Reg Write G Reg Add O Red Write O START Init Wait 22 Sample Init READ Pixel Wait 44 Wait End Read
Klfa San
Rapport de projet S4
Page 16
Klfa San
Rapport de projet S4
Page 17
Pour le rglage du gain et de loffset lautomate va faire 3 fois le tour de la premire boucle pour entrer les valeurs de gain et doffset des 3 groupes de 34 photodiodes, jai choisi de mettre un gain de 1 et un offset nulle car la carte LED claire suffisamment bien la piste. Aprs avoir initialis le capteur lautomate va rester enferm dans la deuxime boucle ou il va envoyer des commandes intgrations des photodiodes et de lecture.
: Entrer de la commande STARTInit : Attente des 22 priodes dhorloges pour lintgration : Entrer de la commande SAMPLEInit : Attente de 5 priodes dhorloge entre chaque commande : Entrer de la commande READPixel Voir en annexes pour le code source VHDL
5. Description des tats de lautomate de stockage et de traitement Etat INIT 2 Reset cpt pix Config Acquisition Stocker val pix Wait Description Initialisation du capteur Remise 1 du compteur cpt pix Configuration du capteur (criture des valeurs de gain et doffset dans les registres) Entrer des commandes STARTInit, SAMPLEInit et READPixel et attente des 44 priodes dhorloge Stockage des valeurs de 102 photodiodes dans un tableau Traitement des valeurs
Klfa San
Rapport de projet S4
Page 18
Pour effectuer la binarisation jai fais une boucle for dans laquelle je test la valeur des photodiodes enregistrer dans le tableau tab_val_pix si la valeur est suprieur au seuil que jai choisi laide des boutons de la carte DE0 je mets 1 dans un dans un nouveau tableau tab_pix_bnarise si par contre la valeur est infrieur je mets 0.
Klfa San
Rapport de projet S4
Page 19
for i in 1 to 100 loop if (tab_pix_binarise(i-1)='0' and tab_pix_binarise(i)='1' and tab_pix_binarise(i+1)='0') then tab_indice_pixel_noir(cpt_indice_pixel_modif)<=i; cpt_indice_pixel_modif<=cpt_indice_pixel_modif+1; elsif (tab_pix_binarise(i-1)='1' and tab_pix_binarise(i)='0' and tab_pix_binarise(i+1)='1') then tab_indice_pixel_blanc(cpt_indice_pixel_modif)<=i; cpt_indice_pixel_modif<=cpt_indice_pixel_modif+1; end if; end loop; cpt_indice_pixel_modif<=0; for i in 1 to 100 loop if (tab_indice_pixel_noir(i)/=0) then tab_pix_binarise(tab_indice_pixel_noir(i))<='0'; elsif (tab_indice_pixel_blanc(i)/=0) then tab_pix_binarise(tab_indice_pixel_blanc(i))<='1'; end if; end loop; y:=100; for i in 1 to 100 loop tab_pix_binarise_100(i)<=tab_pix_binarise(y); y:=y-1; end loop; Pour faire lrosion qui permet de supprimer les pixels isol je fais une opration majoritaire trois bits, qui vrifie si les 2 bits des extrmits sont gaux et que celui du milieu est diffrent, si cest le cas jenregistre lindice du tableau dont il faut changer la valeur dans un nouveau tableau. Je fais ensuite un test sur ce nouveau tableau si les valeurs du tableau sont diffrentes de zro alors je change la valeur du tableau. Je dois ensuite placer les nouvelles valeurs dans nouveau tableau sauf la premire et la dernire.
5. Conclusion
Par manque de temps et du retard que jai pris en restant bloqu sur certaines tches je nais pas pu terminer mon projet de S4, cependant le travaille que je ralis permet dobtenir une dtection de ligne net et prcise comme on lesprait (cf.Figure 31). Jai aussi pu mtre en pratique toutes les notions que jai apprise lIUT comme la programmation en VHDL et en dcouvrir dautre la conception de carte sur protel. Jai aussi dcouvert le travaille en autonomie au sein dun groupe et je pense que cette exprience sera une bonne prparation mon stage.
Klfa San
Rapport de projet S4
Page 20
6. Bibliographie et sitographie
[1]Documentation technique du capteur CCD TSL3301LF: http://www.alldatasheet.com/datasheet-pdf/pdf/203056/TAOS/TSL3301-LF.html [2]Documentation technique du SN65LVDS9637: http://www.datasheetcatalog.org/datasheet2/e/0ltco5la8l7r3jw47est6103i2ky.pdf [3]Documentation technique du DS90LV017A : http://www.national.com/ds/DS/DS90LV017A.pdf [4]Documentation technique du Cyclone III: http://www.altera.com/literature/hb/cyc3/cyc3_ciii5v1.pdf [5] Syntaxe VHDL: http://amouf.chez.com/syntaxe.htm
Klfa San
Rapport de projet S4
Page 21
Klfa San
Rapport de projet S4
Page 22
Klfa San
Rapport de projet S4
Page 23
cpt<=cpt+1; end if; when others => cpt<=cpt+1; end case; end process; process -- calcul de l'tat futur begin wait until falling_edge (SCLK_OUT); case etat is when init => if cpt=10 then etat<=ireset; else etat<=init; end if; when ireset => if cpt=25 then etat<=wait30; else etat<=ireset; end if; when wait30 => if cpt=55 then etat<=mode_reg; else etat<=wait30; end if; when mode_reg => if cpt=65 then etat<=wait5_1; else etat<=mode_reg; end if; when wait5_1 => if cpt=70 then etat<=mode_write; else etat<=wait5_1; end if; when mode_write => if cpt=80 then etat<=wait_1ms; else etat<=mode_write; end if; when wait_1ms => if cpt=8415 then etat<=reset_cpt_1; else etat<=wait_1ms; end if; when reset_cpt_1 => etat<=reg_address_G; when reg_address_G => if cpt=10 or cpt=70 or cpt=130 then etat<=wait5_2; else etat<=reg_address_G; end if; when wait5_2 => if cpt=15 or cpt=75 or cpt=135 then etat<=reg_write_G; else etat<=wait5_2; end if; when reg_write_G => if cpt=25 or cpt=85 or cpt=145 then etat<=wait5_3; else etat<=reg_write_G; end if; when wait5_3 => if cpt=30 or cpt=90 or cpt=150 then etat<=reg_address_O; else etat<=wait5_3; end if; when reg_address_O => if cpt=40 or cpt=100 or cpt=160 then etat<=wait5_4; else etat<=reg_address_O; end if; when wait5_4 => if cpt=45 or cpt=105 or cpt=165 then etat<=reg_write_O;
Klfa San
Rapport de projet S4
Page 24
else etat<=wait5_4; end if; when reg_write_O => if cpt=55 or cpt=115 or cpt=175 then etat<=wait5_5; else etat<=reg_write_O; end if; when wait5_5 => if cpt=60 or cpt=120 then etat<=reg_address_G; elsif cpt=180 then etat<=reset_cpt_2; else etat<=wait5_5; end if; when reset_cpt_2 => etat<=start_int; when start_int => if cpt=10 then etat<=wait22; else etat<=start_int; end if; when wait22 => if cpt=32 then etat<=sample_int; else etat<=wait22; end if; when sample_int => if cpt=42 then etat<=wait5_6; else etat<=sample_int; end if; when wait5_6 => if cpt=47 then etat<=read_pix; else etat<=wait5_6; end if; when read_pix => if cpt=57 then etat<=wait44; else etat<=read_pix; end if; when wait44 => if cpt=101 then etat<=wait919; else etat<=wait44; end if; when wait919 => if cpt=1121 then etat<=reset_cpt_2; else etat<=wait919; end if; end case; end process; process (etat,cpt) -- sorties en fontction de l'tat begin case etat is when mode_reg => if cpt=56 then SDIN<=start; elsif cpt=57 then SDIN<=mode_address(0); elsif cpt=58 then SDIN<=mode_address(1); elsif cpt=59 then SDIN<=mode_address(2); elsif cpt=60 then SDIN<=mode_address(3); elsif cpt=61 then SDIN<=mode_address(4); elsif cpt=62 then SDIN<=mode_address(5); elsif cpt=63 then SDIN<=mode_address(6);
Klfa San
Rapport de projet S4
Page 25
elsif cpt=64 then SDIN<=mode_address(7); elsif cpt=65 then SDIN<=stop; end if; when mode_write => if cpt=71 then SDIN<=start; elsif cpt=72 then SDIN<=mode_valeur(0); elsif cpt=73 then SDIN<=mode_valeur(1); elsif cpt=74 then SDIN<=mode_valeur(2); elsif cpt=75 then SDIN<=mode_valeur(3); elsif cpt=76 then SDIN<=mode_valeur(4); elsif cpt=77 then SDIN<=mode_valeur(5); elsif cpt=78 then SDIN<=mode_valeur(6); elsif cpt=79 then SDIN<=mode_valeur(7); elsif cpt=80 then SDIN<=stop; end if; when reg_address_G => if cpt=1 then SDIN<=start; elsif cpt=2 then SDIN<=reg_address_left_gain(0); elsif cpt=3 then SDIN<=reg_address_left_gain(1); elsif cpt=4 then SDIN<=reg_address_left_gain(2); elsif cpt=5 then SDIN<=reg_address_left_gain(3); elsif cpt=6 then SDIN<=reg_address_left_gain(4); elsif cpt=7 then SDIN<=reg_address_left_gain(5); elsif cpt=8 then SDIN<=reg_address_left_gain(6); elsif cpt=9 then SDIN<=reg_address_left_gain(7); elsif cpt=10 then SDIN<=stop; elsif cpt=61 then SDIN<=start; elsif cpt=62 then SDIN<=reg_address_center_gain(0); elsif cpt=63 then SDIN<=reg_address_center_gain(1); elsif cpt=64 then SDIN<=reg_address_center_gain(2); elsif cpt=65 then SDIN<=reg_address_center_gain(3); elsif cpt=66 then SDIN<=reg_address_center_gain(4); elsif cpt=67 then SDIN<=reg_address_center_gain(5); elsif cpt=68 then SDIN<=reg_address_center_gain(6); elsif cpt=69 then SDIN<=reg_address_center_gain(7); elsif cpt=70 then SDIN<=stop; elsif cpt=121 then SDIN<=start; elsif cpt=122 then SDIN<=reg_address_right_gain(0); elsif cpt=123 then SDIN<=reg_address_right_gain(1); elsif cpt=124 then SDIN<=reg_address_right_gain(2); elsif cpt=125
Klfa San
Rapport de projet S4
Page 26
then SDIN<=reg_address_right_gain(3); elsif cpt=126 then SDIN<=reg_address_right_gain(4); elsif cpt=127 then SDIN<=reg_address_right_gain(5); elsif cpt=128 then SDIN<=reg_address_right_gain(6); elsif cpt=129 then SDIN<=reg_address_right_gain(7); elsif cpt=130 then SDIN<=stop; end if; when reg_write_G => if cpt=16 then SDIN<=start; elsif cpt=17 then SDIN<=reg_write_left_gain(0); elsif cpt=18 then SDIN<=reg_write_left_gain(1); elsif cpt=19 then SDIN<=reg_write_left_gain(2); elsif cpt=20 then SDIN<=reg_write_left_gain(3); elsif cpt=21 then SDIN<=reg_write_left_gain(4); elsif cpt=22 then SDIN<=reg_write_left_gain(5); elsif cpt=23 then SDIN<=reg_write_left_gain(6); elsif cpt=24 then SDIN<=reg_write_left_gain(7); elsif cpt=25 then SDIN<=stop; elsif cpt=76 then SDIN<=start; elsif cpt=77 then SDIN<=reg_write_center_gain(0); elsif cpt=78 then SDIN<=reg_write_center_gain(1); elsif cpt=79 then SDIN<=reg_write_center_gain(2); elsif cpt=80 then SDIN<=reg_write_center_gain(3); elsif cpt=81 then SDIN<=reg_write_center_gain(4); elsif cpt=82 then SDIN<=reg_write_center_gain(5); elsif cpt=83 then SDIN<=reg_write_center_gain(6); elsif cpt=84 then SDIN<=reg_write_center_gain(7); elsif cpt=85 then SDIN<=stop; elsif cpt=136 then SDIN<=start; elsif cpt=137 then SDIN<=reg_write_right_gain(0); elsif cpt=138 then SDIN<=reg_write_right_gain(1); elsif cpt=139 then SDIN<=reg_write_right_gain(2); elsif cpt=140 then SDIN<=reg_write_right_gain(3); elsif cpt=141 then SDIN<=reg_write_right_gain(4); elsif cpt=142 then SDIN<=reg_write_right_gain(5); elsif cpt=143 then SDIN<=reg_write_right_gain(6); elsif cpt=144 then SDIN<=reg_write_right_gain(7); elsif cpt=145 then SDIN<=stop; end if; when reg_address_O => if cpt=31 then SDIN<=start;
Klfa San
Rapport de projet S4
Page 27
elsif cpt=32 then SDIN<=reg_address_left_offset(0); elsif cpt=33 then SDIN<=reg_address_left_offset(1); elsif cpt=34 then SDIN<=reg_address_left_offset(2); elsif cpt=35 then SDIN<=reg_address_left_offset(3); elsif cpt=36 then SDIN<=reg_address_left_offset(4); elsif cpt=37 then SDIN<=reg_address_left_offset(5); elsif cpt=38 then SDIN<=reg_address_left_offset(6); elsif cpt=39 then SDIN<=reg_address_left_offset(7); elsif cpt=40 then SDIN<=stop; elsif cpt=91 then SDIN<=start; elsif cpt=92 then SDIN<=reg_address_center_offset(0); elsif cpt=93 then SDIN<=reg_address_center_offset(1); elsif cpt=94 then SDIN<=reg_address_center_offset(2); elsif cpt=95 then SDIN<=reg_address_center_offset(3); elsif cpt=96 then SDIN<=reg_address_center_offset(4); elsif cpt=97 then SDIN<=reg_address_center_offset(5); elsif cpt=98 then SDIN<=reg_address_center_offset(6); elsif cpt=99 then SDIN<=reg_address_center_offset(7); elsif cpt=100 then SDIN<=stop; elsif cpt=151 then SDIN<=start; elsif cpt=152 then SDIN<=reg_address_right_offset(0); elsif cpt=153 then SDIN<=reg_address_right_offset(1); elsif cpt=154 then SDIN<=reg_address_right_offset(2); elsif cpt=155 then SDIN<=reg_address_right_offset(3); elsif cpt=156 then SDIN<=reg_address_right_offset(4); elsif cpt=157 then SDIN<=reg_address_right_offset(5); elsif cpt=158 then SDIN<=reg_address_right_offset(6); elsif cpt=159 then SDIN<=reg_address_right_offset(7); elsif cpt=160 then SDIN<=stop; end if; when reg_write_O => if cpt=46 then SDIN<=start; elsif cpt=47 then SDIN<=reg_write_left_offset(0); elsif cpt=48 then SDIN<=reg_write_left_offset(1); elsif cpt=49 then SDIN<=reg_write_left_offset(2); elsif cpt=50 then SDIN<=reg_write_left_offset(3); elsif cpt=51 then SDIN<=reg_write_left_offset(4); elsif cpt=52 then SDIN<=reg_write_left_offset(5); elsif cpt=53 then SDIN<=reg_write_left_offset(6); elsif cpt=54
Klfa San
Rapport de projet S4
Page 28
then SDIN<=reg_write_left_offset(7); elsif cpt=55 then SDIN<=stop; elsif cpt=106 then SDIN<=start; elsif cpt=107 then SDIN<=reg_write_center_offset(0); elsif cpt=108 then SDIN<=reg_write_center_offset(1); elsif cpt=109 then SDIN<=reg_write_center_offset(2); elsif cpt=110 then SDIN<=reg_write_center_offset(3); elsif cpt=111 then SDIN<=reg_write_center_offset(4); elsif cpt=112 then SDIN<=reg_write_center_offset(5); elsif cpt=113 then SDIN<=reg_write_center_offset(6); elsif cpt=114 then SDIN<=reg_write_center_offset(7); elsif cpt=115 then SDIN<=stop; elsif cpt=166 then SDIN<=start; elsif cpt=167 then SDIN<=reg_write_right_offset(0); elsif cpt=168 then SDIN<=reg_write_right_offset(1); elsif cpt=169 then SDIN<=reg_write_right_offset(2); elsif cpt=170 then SDIN<=reg_write_right_offset(3); elsif cpt=171 then SDIN<=reg_write_right_offset(4); elsif cpt=172 then SDIN<=reg_write_right_offset(5); elsif cpt=173 then SDIN<=reg_write_right_offset(6); elsif cpt=174 then SDIN<=reg_write_right_offset(7); elsif cpt=175 then SDIN<=stop; end if; when start_int => if cpt=1 then SDIN<=start; elsif cpt=2 then SDIN<=StartInt(0); elsif cpt=3 then SDIN<=StartInt(1); elsif cpt=4 then SDIN<=StartInt(2); elsif cpt=5 then SDIN<=StartInt(3); elsif cpt=6 then SDIN<=StartInt(4); elsif cpt=7 then SDIN<=StartInt(5); elsif cpt=8 then SDIN<=StartInt(6); elsif cpt=9 then SDIN<=StartInt(7); elsif cpt=10 then SDIN<=stop; end if; when sample_int =>if cpt=33 then SDIN<=start; elsif cpt=34 then SDIN<=SampleInt(0); elsif cpt=35 then SDIN<=SampleInt(1); elsif cpt=36 then SDIN<=SampleInt(2); elsif cpt=37 then SDIN<=SampleInt(3);
Klfa San
Rapport de projet S4
Page 29
elsif cpt=38 then SDIN<=SampleInt(4); elsif cpt=39 then SDIN<=SampleInt(5); elsif cpt=40 then SDIN<=SampleInt(6); elsif cpt=41 then SDIN<=SampleInt(7); elsif cpt=42 then SDIN<=stop; end if; when read_pix => if cpt=48 then SDIN<=start; elsif cpt=49 then SDIN<=ReadPixel(0); elsif cpt=50 then SDIN<=ReadPixel(1); elsif cpt=51 then SDIN<=ReadPixel(2); elsif cpt=52 then SDIN<=ReadPixel(3); elsif cpt=53 then SDIN<=ReadPixel(4); elsif cpt=54 then SDIN<=ReadPixel(5); elsif cpt=55 then SDIN<=ReadPixel(6); elsif cpt=56 then SDIN<=ReadPixel(7); elsif cpt=57 then SDIN<=stop; end if; when wait919 => SDIN<='1'; stock<='1'; when others => SDIN<='1'; stock<='0';
end case; end process; process -- CPT COMPTEUR avec remise zero suivant les tats begin wait until falling_edge (SCLK_OUT); case etat is when wait919 => if(cpt_stock=1020) then cpt_stock<=1; else cpt_stock<=cpt_stock+1; end if; when others => end case; end process; end architecture ; cpt_stock<=1;
Klfa San
Rapport de projet S4
Page 30
cpt_val_pix: integer range 0 to 9000:=0; cpt_indice_ligne_tab_val_pix: integer range 0 to 101:=0; cpt_indice_colonne_tab_val_pix: integer range 0 to 9:=0; cpt_indice_pixel_modif: integer range 0 to 101:=0;
signal SDOUT_unsigned: unsigned(0 downto 0); signal seuil: integer range 0 to 255; signal start : std_logic; signal stop : std_logic; begin SDOUT_sonde<=SDOUT; seuil<=to_integer(SWITCH_SEUIL); start<='0'; stop<='1'; with SDOUT select SDOUT_unsigned<="0" when '0', "1" when others; tab_pix_binarise_100(0)<='0'; tab_pix_binarise_100(101)<='0'; process(etat_val_pix) begin case etat_val_pix is when init_2 => for i in 0 to 101 loop tab_indice_pixel_init(i)<=0; end loop;
Klfa San
Rapport de projet S4
Page 31
process(etat_val_pix)--process qui chercher les valeur min et max des pix variable tab_max_val_pix:unsigned(7 downto 0); variable tab_min_val_pix:unsigned(7 downto 0); begin case etat_val_pix is when wait_2 => tab_max_val_pix:="00000000"; for i in 0 to 101 loop if(to_integer(tab_val_pix(i)) > to_integer(tab_max_val_pix)) then tab_max_val_pix:=tab_val_pix(i); else tab_max_val_pix:=tab_max_val_pix; end if; end loop; tab_max_pix<=tab_max_val_pix; tab_min_val_pix:="11111111"; for i in 0 to 101 loop if(to_integer(tab_min_val_pix)>to_integer(tab_val_pix(i))) then tab_min_val_pix:=tab_val_pix(i); else tab_min_val_pix:=tab_min_val_pix; end if; end loop; tab_min_pix<=tab_min_val_pix; when others => NULL; end case; end process; process (cpt_indice_ligne_tab_val_pix,cpt_indice_colonne_tab_val_pix,etat_val_pix) -- process qui affiche la ligne begin case etat_val_pix is when stocker_val_pix => if (cpt_indice_ligne_tab_val_pix=0 and cpt_indice_colonne_tab_val_pix=0) then ligne<=tab_pix_binarise_100(0); elsif (cpt_indice_ligne_tab_val_pix/=0 and cpt_indice_colonne_tab_val_pix=0) then ligne<=tab_pix_binarise_100(cpt_indice_ligne_tab_val_pix); end if; when reset_cpt_pix_3 => ligne<='1'; when others => ligne<='0'; end case; end process; process(etat_val_pix) --- process de traitement des pixels suppression des pixels isols VARIABLE j : INTEGER RANGE 0 TO 101; VARIABLE k : INTEGER RANGE 0 TO 101; VARIABLE y : INTEGER RANGE 0 TO 101; begin case etat_val_pix is when wait_2 => tab_indice_pixel_noir<=tab_indice_pixel_init; tab_indice_pixel_blanc<=tab_indice_pixel_init; for i in 0 to 101 loop if (to_integer(tab_val_pix(i))>seuil) then tab_pix_binarise(i)<='1'; else tab_pix_binarise(i)<='0'; end if; end loop; for i in 1 to 100 loop
Klfa San
Rapport de projet S4
Page 32
if (tab_pix_binarise(i-1)='0' and tab_pix_binarise(i)='1' and tab_pix_binarise(i+1)='0') then tab_indice_pixel_noir(cpt_indice_pixel_modif)<=i; cpt_indice_pixel_modif<=cpt_indice_pixel_modif+1; elsif (tab_pix_binarise(i-1)='1' and tab_pix_binarise(i)='0' and tab_pix_binarise(i+1)='1') then tab_indice_pixel_blanc(cpt_indice_pixel_modif)<=i; cpt_indice_pixel_modif<=cpt_indice_pixel_modif+1; end if; end loop; cpt_indice_pixel_modif<=0; for i in 1 to 100 loop if (tab_indice_pixel_noir(i)/=0) then tab_pix_binarise(tab_indice_pixel_noir(i))<='0'; elsif (tab_indice_pixel_blanc(i)/=0) then tab_pix_binarise(tab_indice_pixel_blanc(i))<='1'; end if; end loop; y:=100; for i in 1 to 100 loop tab_pix_binarise_100(i)<=tab_pix_binarise(y); y:=y-1; end loop; j := 0; loop exit when tab_pix_binarise_100(j)='1' or j=101; j := j + 1; end loop; prem_pixel_blanc<=j; k := 101; loop exit when tab_pix_binarise_100(k)='1' or k=0; k := k - 1; end loop; der_pixel_blanc<=k; if(prem_pixel_blanc=101 and der_pixel_blanc=0) then sui_ligne<='0'; else sui_ligne<='1'; pwm_mot_droit<=to_unsigned(100-prem_pixel_blanc,8); pwm_mot_gauche<=to_unsigned(prem_pixel_blanc,8); end if;
when others => null; end case; end process; process -- process qui stock les valeurs des pixels dans un tableau begin wait until rising_edge (SCLK_OUT); case etat_val_pix is when stocker_val_pix => if (cpt_indice_colonne_tab_val_pix/=0 and cpt_indice_colonne_tab_val_pix/=9) then tab_val_pix(cpt_indice_ligne_tab_val_pix)(cpt_indice_colonne_tab_val_pix1)<=SDOUT_unsigned(0); end if;
Klfa San
Rapport de projet S4
Page 33
process --cpt_indice_ligne_tab_val_pix avec remise zero suivant les tats begin wait until falling_edge (SCLK_OUT); case etat_val_pix is when stocker_val_pix => if (cpt_indice_colonne_tab_val_pix=9 and cpt_indice_ligne_tab_val_pix=101) then cpt_indice_ligne_tab_val_pix<=0; elsif cpt_indice_colonne_tab_val_pix=9 then cpt_indice_ligne_tab_val_pix<=cpt_indice_ligne_tab_val_pix+1; else cpt_indice_ligne_tab_val_pix<=cpt_indice_ligne_tab_val_pix; end if; when others => cpt_indice_ligne_tab_val_pix<=0; end case; end process; process --cpt_indice_colonne_tab_val_pix avec remise zero suivant les tats begin wait until falling_edge (SCLK_OUT); case etat_val_pix is when stocker_val_pix => if (cpt_indice_colonne_tab_val_pix=9) then cpt_indice_colonne_tab_val_pix<=0; else cpt_indice_colonne_tab_val_pix<=cpt_indice_colonne_tab_val_pix+1; end if; when others => cpt_indice_colonne_tab_val_pix<=0; end case; end process; process -- calcul de l'tat futur pour automate qui stocker les valeurs de pixels begin wait until falling_edge (SCLK_OUT); case etat_val_pix is when init_2 => if cpt_val_pix=8415 then etat_val_pix<=reset_cpt_pix_1; else etat_val_pix<=init_2; end if; when reset_cpt_pix_1 => etat_val_pix<=config; when config => if cpt_val_pix=180 then etat_val_pix<=reset_cpt_pix_2; else etat_val_pix<=config; end if; when reset_cpt_pix_2 => etat_val_pix<=acquisition; when acquisition => if cpt_val_pix=100 then etat_val_pix<=reset_cpt_pix_3; else etat_val_pix<=acquisition; end if; when reset_cpt_pix_3 => etat_val_pix<=stocker_val_pix; when stocker_val_pix => if cpt_val_pix=1019 then etat_val_pix<=wait_2; else etat_val_pix<=stocker_val_pix; end if; when wait_2 => if cpt_val_pix=1120 then etat_val_pix<=reset_cpt_pix_3; else etat_val_pix<=wait_2; end if; end case; end process;
Klfa San
Rapport de projet S4
Page 34
process -- CPT COMPTEUR avec remise zero suivant les tats etat_val_pix begin wait until falling_edge (SCLK_OUT); case etat_val_pix is when reset_cpt_pix_1 => when reset_cpt_pix_2 => when reset_cpt_pix_3 => cpt_val_pix <= 1; cpt_val_pix <= 1; cpt_val_pix <= 0;
when others => cpt_val_pix<=cpt_val_pix+1; end case; end process; end architecture;
Klfa San
Rapport de projet S4
Page 35