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
Lesezeichen