Hallo

Mein aktuelles Projekt bringt mich wieder zurück zur einfachen Kamera:
Bild hier  
http://www.youtube.com/watch?v=XTYzLqgKMLM

Das sieht zwar schon recht schick aus, aber die Ergebnisse mit den Phototransistoren sind einfach unbefriedigend wenn man die Leistung der Kamera kennt ;)

Im Moment mache ich noch Tests mit dem RP6 (8MHz Mega32) als Steuerung, geplant ist das aber eigentlich für einen tiny13 mit 9,6MHz. Deshalb muss der Code deutlich schlanker werden, was zur Folge hat, dass alles auch etwas übersichtlicher ist. Zur allgemeinen Erheiterung zeige ich euch deshalb mal den aktuellen Stand meiner Vorversuche. Ziel ist dabei u.a. möglichst wenig Ram zu verbraten denn der tiny hat davon nicht wirklich viel:
Code:
// cd-racer mit cam (erste Tests mit RP6)                          25.9.2008 mic

#include "RP6RobotBaseLib.h"

uint8_t get_line(void)
{
	uint8_t i;

	cli();
	
	// auf Bildanfang warten
	do
	{
		i=0; while (ADCH > 30); while (ADCH < 50) i++;
	} while (i < 40);

	// die ersten 50 Zeilen überlesen
	i=50;
	while (i--)
	{
		while (ADCH > 30); while (ADCH < 50);
	}

 	// warten auf hell-dunkel-Übergang
	while (ADCH > 110) i++; // Zeile einlesen bis Wert deutlich Richtung dunkel
	sei();
	return(i);
}

int main(void)
{
	uint8_t linie;
	uint16_t i, servo=1550, dummy;

	initRobotBase();
	extIntOFF(); // schaltet den E_INT1-Port auf Eingang für den ADC
	//powerON();

// ADC interne Referenz 2,56V, Ergebniss linksbündig, Kanal ADC4 (E_INT1)
	ADMUX = (1<<REFS1) | (1<<REFS0)  | (1<<ADLAR) | 4;
// setze free running triggern
	SFIOR = (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
// kein Interupt, Wandler einschalten, prescaller /2
	ADCSRA = (0<<ADIE) | (1<<ADEN) | (0<<ADPS2) | (0<<ADPS1)  | (1<<ADPS0);
// Autotriggern bedeutet jetzt free running aktivieren, altes Flag löschen
	ADCSRA |= (1<<ADATE) | (1<<ADIF);
// Initialisierung starten
	ADCSRA |= (1<<ADSC);
// und noch die wohl eher unnötige Initiallesung
	while (!(ADCSRA & (1<<ADIF)));
	ADCSRA |= (1<<ADIF);
	
	// SCL (Pin10) auf Ausgang und Low zur Servoansteuerung
	DDRC |= 1;
	PORTC &= ~1;

	while (1)
	{
		linie=get_line(); // linke Kante der Linie suchen

   	if((linie > 0) && (linie < 70)) // Linie im "Bild"?
   	{
			if(linie > 36 && servo <2000) servo+=(linie-35)*2; // Servoposition
			if(linie < 34 && servo > 675) servo-=(35-linie)*2; // korrigieren

			i=servo; // Servo blockierend auf Position stellen
			cli();
			PORTC |= 1;
			while(i--) dummy ^= i;
			PORTC &= ~1;
			sei();
			i=15000;
			while(i--) dummy ^= i;
		}
	}
	return(0);
}
Wie gehabt hängt die Kamera wieder direkt an einem ADC-Pin. Der ADC rennt wieder im Dauerlauf mit kleinstem Prescaler und die Werte werden auch wieder ohne Rücksicht auf den ADC-Status linksbündig als 8bit-Wert eingelesen. Der Ablauf ist zu Beginn ebenfalls wie gehabt: Warten auf neues Bild und dann Zeilen zählen bis der Start der gewünschten Zeile erreicht ist. Dann kommt eine kleine Änderung: Ich zähle wie oft der eingelesene Wert einen (im Moment noch festen) Wert überschreitet (=heller als Linie) und interpretiere diesen Zählwert dann als linke Kante der Linie. So erhalte ich Werte zwischen 0="Linie links aus dem Bild" bis 69="Linie rechts aus dem Bild".

Mit diesem Wert steuere ich dann ein Servo (ohne großen Schnickschnack über eine Zählschleife mit gesperrten Interrupts) und halte so die Kamera bei einem Wert zwischen 34 und 36:
Bild hier  
http://www.youtube.com/watch?v=46ts6GH04NI

Weil das so wunderbar funktioniert werde ich wohl nochmals einen kleinen Versuch mit einem liniefolgenden RP6 unternehmen ;)

Gruß

mic