/* 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(); }
}
}