Hallo
Der RP6 ist einfach zu fett für den engen RN-Kurs:
Bild hier Bild hier Bild hier
http://www.youtube.com/watch?v=h7bdUD3mJfg
http://www.youtube.com/watch?v=sm3WrykPj4M
http://www.youtube.com/watch?v=3r_m2rGgXLk
Aber als Test für mein Projekt reicht mir das erstmal. Andere Anwendungen wären z.B. Objekt-, Muster- und Hindernisserkennung, Barcodelesen, Abstandsmessung (mit Laserpointer) und möglicherweise auch Licht-/IR-Kommunikation. Vielleicht fällt mir noch was nettes ein, vorerst bleibe ich mal beim Liniensuchen. Hier noch der Code:
Code:
// RP6 folgt einer Linie die mit der Kamera erkannt wird 26.9.2008 mic
#include "RP6RobotBaseLib.h"
#define mitte 1550
// Achtung! Die PWM-Werte werden hier OHNE Rampe verändert!
void setMotorPWM(uint8_t power_links, uint8_t power_rechts)
{
extern uint8_t mleft_ptmp, mright_ptmp;
if(power_links > 210) power_links = 210;
if(power_rechts > 210) power_rechts = 210;
mleft_power=mleft_ptmp=power_links;
mright_power=mright_ptmp=power_rechts;
OCR1BL = power_links;
OCR1AL = power_rechts;
if(power_links || power_rechts)
TCCR1A = (1 << WGM11) | (1 << COM1A1) | (1 << COM1B1);
else
TCCR1A = 0;
}
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
i=0; while (ADCH > 100) i++;
sei();
return(i);
}
int main(void)
{
uint8_t linie;
uint16_t i, servo=mitte, 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;
setMotorDir(BWD,BWD);
//setMotorPWM(100,100);
while (1)
{
linie=get_line(); // linke Kante der Linie suchen
if((linie > 0) && (linie < 70)) // Linie im "Bild"?
{
if(linie > 36 && servo <mitte+800) servo+=(linie-35)*2; // Servoposition
if(linie < 34 && servo >mitte-1000) 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;
if(servo < mitte) setMotorPWM(100, 100-(mitte-servo)/10);
if(servo > mitte) setMotorPWM(100-(servo-mitte)/10, 100);
if(servo < mitte-300)
{
setMotorDir(BWD,FWD);
setMotorPWM(100, (mitte-servo)/10);
}
else if(servo > mitte+300)
{
setMotorDir(FWD,BWD);
setMotorPWM((servo-mitte)/10, 100);
}
else setMotorDir(BWD,BWD);
} // else setMotorPWM(0,0);
}
return(0);
}
Übrigends ist die hier vorgestellte Anwendung bei weitem nicht so zeit- und rechenintensiv wie allgemein angenommen ;)
Gruß
mic
Lesezeichen