Hallo
Bild hier
Aus Zeitgründen habe ich es leider nicht geschafft eine vernünftige Software zu erstellen. Nach Druck auf den linken Bumper wird das hellste Teelicht im Blickbereich angesteuert und beschossen, ein Druck auf den rechten Bumper wiederholt den Schuss. Mein Konzept funktioniert nur im Halbdunkel, aber bei strahlender Sonne braucht man eh keine Teelichter;)
Sensor ist die Projekt-Cam, Ausbläser ist ein Luftballon auf einem PET-Flaschenrest der mit einer Wäscheklammer und zwei Servos gespannt und abgeschossen wird:
Bild hier Bild hier Bild hier
http://www.youtube.com/watch?v=qgmKWWT4lps
http://www.youtube.com/watch?v=l79jabBqgo0
Helferleinkatze ist natürlich auch mit dabei ;)
Code:
// Teelicht löschen mit RP6 12.4.2010 mic
#include "RP6RobotBaseLib.h"
#define auf 30
#define zu 12
#define aus 0
#define spannen 14
#define holen 38
uint8_t klammer=0, ziehen=0; // Servos aus
void init(void);
void setMotorPWM(uint8_t power_links, uint8_t power_rechts);
uint16_t richtung(void);
void schuss(void);
int main(void)
{
init();
while(1)
{
writeInteger(richtung(), 10);
writeString_P("\n");
setLEDs(63); // ready
do
{
schuss();
while(!(getBumperRight() || getBumperLeft())); // weiteren Schuss auslösen
}
while(!getBumperLeft()); // nächste Kerze
}
return(0);
}
ISR (TIMER1_OVF_vect)
{
static uint16_t servocount=1;
if(servocount > klammer) PORTC &= ~SCL; else PORTC |= SCL; // PC0 XBUS 10
if(servocount > ziehen) PORTC &= ~SDA; else PORTC |= SDA; // PC1 XBUS 12
if(servocount < 400) servocount++; else servocount=1;
}
void init(void)
{
initRobotBase();
DDRC |= (SCL | SDA); // Servopins auf Ausgang setzen
TIMSK |= (1 << TOIE1); // Die Timer1 Overflow-ISR zur Servoansteuerung
extIntOFF(); // schaltet den E_INT1-Port auf Eingang für den ADC
// ADC interne Referenz 2,56V, Ergebniss linksbündig, Kanal ADC4 (E_INT1)
ADMUX = (1<<REFS1) | (1<<REFS0) | (1<<ADLAR) | 4;
// setzte 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);
//powerON();
}
// 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;
}
uint16_t richtung(void)
{
uint8_t bildspeicher[100], *bildzeiger; // 100 Byte Bildspeicher sollten reichen
uint8_t zeile, sync, c; // und dürfen NICHT global sein!
uint16_t spalte_max, spaltenwerte[12];
writeString_P("-------------------------\n");
do
{
spalte_max=0;
for(c=0; c<12; c++)
{
setLEDs(c); // working
bildzeiger=&bildspeicher[0]; // Zeiger auf Start des Bildspeicherbereich
zeile=c*20+35; // aktuelle Zeile (35 Zeilen sind der Schrott beim Bildstart)
cli();
do // Warten auf langen Syncbereich = Bildstart
{
sync=0;
while (ADCH > 20); // warten solange Bilddaten erkannt werden
while (ADCH < 30) sync++; // Länge des Sync-Signal zählen
}while (sync < 40); // größer 40 bedeutet Bildstart
while(zeile--)
{
while (ADCH > 20); // Bilddaten
while (ADCH < 30); // Sync
}
do *bildzeiger=ADCH; while(*bildzeiger++ > 20); // schnelle Zeile einlesen
sei();
spaltenwerte[c]=0;
for(zeile=0; zeile<48; zeile++) // 64 Pixel zusammenzählen
{
spaltenwerte[c]+=bildspeicher[zeile];
setLEDs(zeile);
}
if(spaltenwerte[c] > spalte_max) spalte_max=spaltenwerte[c];
}
for(c=0; c<12; c++) // größten Spaltenwert suchen
{
if(spaltenwerte[c] == spalte_max) spalte_max=c;
}
writeString_P("hellste Spalte: ");
writeInteger(spalte_max, 10);
writeString_P(" Spaltenwert: ");
writeInteger(spaltenwerte[spalte_max], 10);
writeString_P("\n");
//if(spaltenwerte[spalte_max] > 3000)
{
if(spalte_max > 6) {setMotorDir(FWD,FWD); setMotorPWM(100,0);}
else if(spalte_max <6) {setMotorDir(BWD,FWD); setMotorPWM(100,0);}
//mSleep(200);
//setMotorPWM(0,0);
//mSleep(500);
else setMotorPWM(0,0);
}
}while(spalte_max !=6);
return(spaltenwerte[spalte_max]); // Summenhelligkeit der Spalte
}
void schuss(void)
{
klammer=auf;
mSleep(500);
ziehen=holen;
mSleep(500);
klammer=zu;
mSleep(300);
ziehen=spannen;
mSleep(500);
klammer=auf;
mSleep(200);
klammer=zu;
mSleep(200);
klammer=0;
}
Gruß
mic
[Edit]
Ich hab's zerlegt, weil der Ballon kaputt ging. Der kleine Knubbel war im Ballon als Greifpunkt für die Klammer. Das Sieb stammt aus einem Kaffeepad.
Lesezeichen