/* Name: chariot.c * Description: Controle d'un chariot suiveur de ligne noire sur un PIC. * Author: cLx * Date: Juin 2006 * Compiler: CCS - http://www.ccsinfo.com/ (pas gratuit, désolé!) * * Hardware: Un PIC 16F877, une caméra video noir et blanc couplé à un * circuit séparant les synchro trame et ligne et la video sous * forme d'un signal logique tout ou rien, une carte à mostfet pour * commander deux moteurs, et une carte de détection d'obstacle par * réflexions d'ultra-sons. En clair, vous pourrez jamais utiliser * ce code tel-quel... */ #include <16f877.h> #include <defines.h> #bit PC0 = PORTC.0 // moteur gauche #bit PC1 = PORTC.1 // moteur droit #bit TEST = PORTC.6 // synchro oscillo #bit TRAME = PORTB.0 #bit LIGNE = PORTB.1 #bit LOGIQUE = PORTB.2 #bit OBSTACLE = PORTD.0 #use delay (clock=20000000) /* Ajustement de certains paramètres */ #define MIN 1 // Valeur min } Rétourné par la fonction #define MAX 45 // Valeur max } de détection de la piste noire #define TOLERANCE 3 // Ecart max dans lequel le chariot roulera droit #define TAILLESLT 2 // Taille maximum d'une saleté, en cycles #define RETOUR 1 // Active le demi-tour à la fin de la ligne (option) #define LINETOANALYZE 130 // Numéro de la ligne que l'on veut analyser /* Autres macros */ #define CENTRE (MAX+MIN)/2 /* début des fonctions */ /* Initialise les I/O */ void init(void){ TRISB = 0b11111111; // tout le port B en entrée TRISC = 0b10111100; // RC6, RC1 et RC0 en sortie TRISD = 0b11111111; // tout le port D en entrée } /* Fonctions de commande des moteurs. Il sera plus * plus clair et plus simple d'appeler ces fonctions. * que de modifier les deux bits a chaque fois */ void marche(void){ PC0 = 1; PC1 = 1; } void arret(void) { PC0 = 0; PC1 = 0; } void gauche(void){ PC0 = 0; PC1 = 1; } void droite(void){ PC0 = 1; PC1 = 0; } /* Fonction de test des moteurs */ void motortest(void){ gauche(); // Mise en marche du moteur droit... delay_ms(3000); droite(); // ... puis du moteur gauche... delay_ms(3000); marche(); // ... puis des deux. delay_ms(3000); arret(); } /* Fonction d'analyse d'une image video à partir de la caméra */ int analyze(void){ int cptligne = 0; int cptlogic = 0; int start, stop, epaisseur; // On attend le prochain front montant sur TRAME ; le début d'une trame... while(TRAME); while(!TRAME); // Puis on attend la ligne que l'on veut analyser... while(cptligne++ < LINETOANALYZE){ while(LIGNE); // détection de while(!LIGNE); // front montant } // analyse de la ligne : c'est ici // que le timing est critique ! on // attend d'abord que "l'image commence" delay_us(8); // on génére une synchro pour l'oscillo, pour observer // le timing du comptage. Voir chronogrames, compte rendu module 2. TEST = 1; do { // On scrute le signal video logique, à chaque fois que l'on // effectue une boucle, on incrémente cptlogic. // On compte pendant que l'on est sur la bande noire... while(LOGIQUE){ cptlogic++; } // On mémorise la position du début de la détection de la bande noire start = cptlogic; // ... puis on compte pendant que l'on est sur la bande noire. while(!LOGIQUE){ cptlogic++; } // mémorisation de la fin de la détection de la bande noire stop = cptlogic; // mais si tout ça s'est passé en trop de temps, ça veut dire que // les fronts n'etaient pas ceux de la bande noire, mais la fin de // la ligne. On retourne alors "0" pour signaler a la fonction // appelante que en fait, on est paumés, pas de bande noire en vue. if (cptlogic > MAX) { TEST = 0; // synchro oscillo à 0 return 0; } // on verifie que la bande noire detectée n'est pas trop // fine, sinon cela voudrait dire que c'est une saleté noire sur le // sol blanc, et on continue le scrutage comme si de rien n'etait. epaisseur = stop-start; } while (epaisseur < TAILLESLT); TEST = 0; // synchro oscillo 1->0 // sinon, on retourne une valeur entre 0 et 45, on fait // la moyenne pour que cela soit le centre de la ligne noire return (start + stop) / 2; } /* ENTRY POINT */ void main(void){ int result = 0; init(); // initialisations des ports motortest(); // test des moteurs /* Boucle principale */ while(1){ /* On analyse une image de la camera, la valeur retournée depend de la position de la bande noire, elle peut aller de 1 à 45 (respectivement au maximum à gauche et le maximum à droite). Si la valeur retournée est 0, c'est que la ligne a disparue du champ de vision de la camera. */ result = analyze(); /* on s'arrête si le chariot détecte un obstacle */ if (OBSTACLE) { arret(); } /* Si la ligne disparait, selon la configuration */ else if (!result) { if (!RETOUR) { arret(); // ... Soit on arrete le chariot par sécurité ; } else { droite(); // ... Soit on essaie de faire demi-tour. } } /* Sinon, on suit tout simplement la ligne : si la bande est trop * à gauche par rapport au chariot, on dirige celui ci vers la * gauche, idem pour la droite, tandis que si la bande est dans la * marge de tolérance autour de CENTRE, on se dirige tout droit. */ else if (result < CENTRE-TOLERANCE) { gauche(); } else if (result > CENTRE+TOLERANCE) { droite(); } else { marche(); } } }