/* 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(); }
	}
}
 [PROGRAMME COMPLET] AutoExit (a sa propre page)
 [C] [Win32] Mouseloop : Ou comment faire des trucs stupides avec le pointeur de la souris
 [PHP] [INCLUDE] Récupérer des chaines quel que soit l'état de magicquotes.
 [C] [Win32] APM : Faire passer les moniteurs en green mode/locker le PC rapidement.
 [QBASIC] Lire par RS-232 les données du multimetre VC 670 et les enregistrer dans un CSV
 [C] [Portable] [Connerie] Un encodeur/décodeur ROT13 et pas que 13, en mode console.
 [mIRC] Ce client IRC n'est pas très convivial avec le mode "away". Voila qui est mieux.
 [C] [Win32] Un programme pour récupérer le nom de la chanson actuellement jouée.
 [Cµ] [PIC] [CCS] Le programme d'un chariot suiveur de ligne noire par caméra video.
10  [PROJET SOURCEFORGE] [C] Un client/passerelle en mode console pour les minichats (rmcgirr83.org) sur forums PhpBB
11  [C] [Win32] [NHC] "Workaround" d'un probleme avec le son de mon laptop lors du changement de frequence cpu
12  [C] Make-ILDA : a C routine to create ILDA files, for lasershows.