Archiv verlassen und diese Seite im Standarddesign anzeigen : TicTacToe/Reaktivlicht - Led als Sensor
Hallo libes Forum,
ich wollte euch hier jetzt mal mein neustes fertiges Projekt vorstellen. Es ist ein TicTacToe geworden, das man bedienen kann, in dem man auf die LEDs "zeigt". Das beruht auf dem Prinzip eines Reaktivlichtes, dass mit einer LED funktioniert. http://reaktivlicht.de/kochbuch.pdf
http://blog.makezine.com/order.jpg
(Quelle:http://blog.makezine.com/archive/2006/06/led_touch_sensor.html)
Ich brauche also keine Phototransistoren oder LDRs. Als Computer-Gegner hab ich mir den NegaMax-Akgorithmus ausgesucht, den hab ich allerdings abgetippt und auf meine Bedürfnisse angepasst. Der Algorithmus geht systematisch alle Eventualitäten durch und sucht die Beste aus, deswegen kann man gegen ihn nicht gewinnen, das Beste was man schaffen kann ist Unentschieden.
Nach dem Einschalten kann man wählen ob man gegen den Computer oder einen anderen Menschen spielen will. Am besten schaut ihr euch das Video an.
http://www.youtube.com/watch?v=UcPQEy6P6zc
Ich benutze übrigens einen Atmega32 und Duo-LEDs von Pollin. Der Atmega ist in C programmiert. Ich freue mich auf eure Kritik, Anregungen und Verbesserungsvorschläge.
Bei Intresse kann ich euch weitere Links zum Thema "Led als Sensor" geben.
KR-500
asurofreak.
20.12.2009, 18:53
hi KR-500!
das schaut ma cool aus!
das wirkt wie son touchscreen, echt klever
das signal der led muss man dann aber verstärken, oder?, denn ich hab mir mal so ne schaltung gebaut, wenn man eine led unter ner lichtquelle hielt, fing die andere an zu leuchten, ich brauchte dafür 2 transistoren.
MfG
Hallo!
LED's als Sensoren zu nutzen, habe ich auch schon öfters gemacht. Ich habe mal eine Uhr gebaut, bei der die Status-LED neben der Funktion als Statusanzeige die Helligkeit misst und dementsprechend die Displayhelligkeit anpasst.
Momentan arbeite ich an einem TicTacToe auf einem Grafik-LCD. allerdings noch ohne KI.
Aber auf die Idee, TicTacToe und Reaktivlicht zu kombinieren, bin ich noch nicht gekommen. Hut ab, es ist wirklich ein tolles Projekt von dir geworden...
Grüße
Thomas
hi KR-500!
das schaut ma cool aus!
das wirkt wie son touchscreen, echt klever
das signal der led muss man dann aber verstärken, oder?, denn ich hab mir mal so ne schaltung gebaut, wenn man eine led unter ner lichtquelle hielt, fing die andere an zu leuchten, ich brauchte dafür 2 transistoren.
Es ist nicht notwendig, da irgendwas zu verstärken. Es wird lediglich für einige ms die Led "geladen" (wie ein Kondensator) und dann geprüft, wie schnell sie sich wieder entlädt.
Grüße
Thomas
asurofreak.
20.12.2009, 19:34
was man mit LED´s alles so machen kann...das sowas geht wusste ich nun noch net, les mir gerade die pdf-datei durch
MfG
feine sache, ich hatte auch an ein tictactoe auf meinem roboter gedacht, hatte aber tasten im blickfeld. duoleds wollte ich auch nutzen, hab das projekt aber bis jetzt nur hardware mäßig geplant, weil ich mir noch zuviele gedanken über den code gemacht habe, ich habbe selber und an einem wochenende mal tictactoe entschlüsselt, kann jetzt nicht mehr gegen freunde verliehren, wenn ich anfange verliehren die immer, jetzt will keiner gegen mich spielen :-(
kannst du deinen code mal als hilfestellung zur übersetztung von meiner strategie in ein C-programm posten?
ist eigendlich perfekt, der RP6 hat ja auch den Atmega32
Hallo zusammen,
danke für die netten Kommentare. Die AI ist ja wie schon erwähnt ein NegaMax-Algorithmus. Da der Code ca. 1000 Zeilen umfasst kann ich ihn nicht ganz posten aber ich hab die wichtigsten Stellen gepostet. Wenn du oder jemand anderes Intresse am gesamten Code hat schicke ich ihm gerne eine PM. Es tut mir leid wenn der Code an einigen Stellen unleserlich ist, ich sollte ihn bei Gelegenheit noch mal überarbeiten, weil ich relativ unsauber programmiert habe. Der Algorithmus ist ja wie schon gesagt abgetippt. Der NegaMax-Algorithmus ist nur einer von vielen, den man verwenden kann, wikipedia liefert eine ganz gute Übersicht, du musst unten in den links gucken, d stehen halt noch die anderen:
http://de.wikipedia.org/wiki/Minimax-Algorithmus
Hier sind noch ein paar links die mir geholfen haben den Algorithmus zu verstehen:
http://www.aihorizon.com/essays/basiccs/trees/minimax.htm
http://en.literateprograms.org/Tic_Tac_Toe_%28C_Plus_Plus%29
http://www.experts-exchange.com/Programming/Game/AI_Physics/Q_21994259.html
http://www.gm.fh-koeln.de/~hk/lehre/ala/ws0506/Praktikum/Projekt/A_rot/060125_Proj_AlphaBetaPruning_Norvig_Russell_FINAL. pdf
http://www.osix.net/modules/article/?id=801
http://www.chessandpoker.com/tic_tac_toe_strategy.html
http://www.angelfire.com/wi/wickmann/cs002.html
Die sind zwar alle bis auf einen auf Englisch aber du wirst damit gut klargekommen. Allerdings beschäftigt sich nur der letzte Link explizit mit dem "NegaMax-Algorithmus", von dem hab ich auch abgetippt. Hier ist mein Code:
#include <avr/io.h>
#include "USART_Util.h"
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
unsigned char Board[3][3]={{2,2,2},
{2,2,2},
{2,2,2}};
int ply=0;
int toggle=1,win=0;
unsigned char a[9] = {0,0,0,0,0,0,0,0,0};
unsigned char led[9] = {0,0,0,0,0,0,0,0,0};
unsigned int c_flag,npc=2;
volatile unsigned char k=100;
unsigned char OtherPlayer(unsigned char inPlayer)
{
if(inPlayer==1)return 0;
return 1;
}
char doWin(unsigned char inBoard[3][3],unsigned char inPlayer)
{
if((inBoard[0][0]==inPlayer)&(inBoard[0][1]==inPlayer)&(inBoard[0][2]==inPlayer))
{
return 1;
}
if((inBoard[0][0]==inPlayer)&(inBoard[1][0]==inPlayer)&(inBoard[2][0]==inPlayer))
{
return 1;
}
if((inBoard[2][0]==inPlayer)&(inBoard[2][1]==inPlayer)&(inBoard[2][2]==inPlayer))
{
return 1;
}
if((inBoard[2][2]==inPlayer)&(inBoard[1][2]==inPlayer)&(inBoard[0][2]==inPlayer))
{
return 1;
}
if((inBoard[1][0]==inPlayer)&(inBoard[1][1]==inPlayer)&(inBoard[1][2]==inPlayer))
{
return 1;
}
if((inBoard[0][1]==inPlayer)&(inBoard[1][1]==inPlayer)&(inBoard[2][1]==inPlayer))
{
return 1;
}
if((inBoard[0][0]==inPlayer)&(inBoard[1][1]==inPlayer)&(inBoard[2][2]==inPlayer))
{
return 1;
}
if((inBoard[0][2]==inPlayer)&(inBoard[1][1]==inPlayer)&(inBoard[2][0]==inPlayer))
{
return 1;
}
return 0;
}
int NegaMax(unsigned char inBoard[3][3], unsigned char inPlayer)
{
if(doWin(inBoard,inPlayer)==1)
{
return 1;
}
if(doWin(inBoard,OtherPlayer(inPlayer))==1)
{
return -1;
}
int best=-2;
int i;
for(i=0;i<3;i++)
{
int j;
for(j=0;j<3;j++)
{
if(inBoard[i][j]==2)
{
inBoard[i][j]=inPlayer;
int value=-NegaMax(inBoard,OtherPlayer(inPlayer));
inBoard[i][j]=2;
if(value>best)
{
best=value;
}
}
}
}
if(best==-2)
{
return 0;
}
return best;
}
void moveComputer(unsigned char inBoard[3][3])
{
if(ply<4){
ply++;
int i;
int j;
int best=0;
unsigned char besti=0;
unsigned char bestj=0;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if(Board[i][j]==2)
{
Board[i][j]=1;
best=-NegaMax(inBoard,0);
Board[i][j]=2;
besti=i;
bestj=j;
}
}
}
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if(inBoard[i][j]==2)
{
inBoard[i][j]=1;
int score=-NegaMax(inBoard,0);
if(score>best)
{
besti=i;
bestj=j;
best=score;
}
inBoard[i][j]=2;
}
}
}
Board[besti][bestj]=1;
}
}
void pc (void){
int q,u;
c_flag=1;
for(unsigned int e=0;e<5;e++){
while(c_flag){
if(led[0]==0){
PORTA |= (1<<PA0);
PORTB &=~ (1<<PB0);
}
if(led[1]==0){
PORTA |= (1<<PA1);
PORTB &=~ (1<<PB1);
}
if(led[2]==0){
PORTA |= (1<<PA2);
PORTB &=~ (1<<PB2);
}
if(led[3]==0){
PORTA |= (1<<PA3);
PORTB &=~ (1<<PB3);
}
if(led[4]==0){
PORTA |= (1<<PA4);
PORTB &=~ (1<<PB4);
}
if(led[5]==0){
PORTA |= (1<<PA5);
PORTB &=~ (1<<PB5);
}
if(led[6]==0){
PORTA |= (1<<PA6);
PORTB &=~ (1<<PB6);
}
if(led[7]==0){
PORTA |= (1<<PA7);
PORTB &=~ (1<<PB7);
}
if(led[8]==0){
PORTC |= (1<<PC7);
PORTD &=~ (1<<PD5);
}
_delay_us(10);
if(led[0]==0){
DDRA &=~ (1<<PA0);
PORTA &=~ (1<<PA0);
}
if(led[1]==0){
DDRA &=~ (1<<PA1);
PORTA &=~ (1<<PA1);
}
if(led[2]==0){
DDRA &=~ (1<<PA2);
PORTA &=~ (1<<PA2);
}
if(led[3]==0){
DDRA &=~ (1<<PA3);
PORTA &=~ (1<<PA3);
}
if(led[4]==0){
DDRA &=~ (1<<PA4);
PORTA &=~ (1<<PA4);
}
if(led[5]==0){
DDRA &=~ (1<<PA5);
PORTA &=~ (1<<PA5);
}
if(led[6]==0){
DDRA &=~ (1<<PA6);
PORTA &=~ (1<<PA6);
}
if(led[7]==0){
DDRA &=~ (1<<PA7);
PORTA &=~ (1<<PA7);
}
if(led[8]==0){
DDRC &=~ (1<<PC7);
PORTC &=~ (1<<PC7);
}
_delay_ms(k-75);
a[2] = (PINA & (1<<PINA2));
a[3] = (PINA & (1<<PINA3));
a[5] = (PINA & (1<<PINA5));
_delay_ms(10);
a[4] = (PINA & (1<<PINA4));
_delay_ms(65);
a[0] = (PINA & (1<<PINA0));
a[1] = (PINA & (1<<PINA1));
a[6] = (PINA & (1<<PINA6));
a[7] = (PINA & (1<<PINA7));
a[8] = (PINC & (1<<PINC7));
DDRA = 0xFF;
DDRC = 0xFF;
if((a[0]!=0)&&(led[0]==0)){
PORTB |= (1<<PB0);
c_flag = 0;
c[0]=0;
Board[0][0]=0;
led[0]=1;
_delay_ms(120);
}
if(a[1]!=0){
PORTB |= (1<<PB1);
c_flag = 0;
c[1]=0;
Board[0][1]=0;
led[1]=1;
_delay_ms(120);
}
if(a[2]!=0){
PORTB |= (1<<PB2);
c_flag = 0;
c[2]=0;
Board[0][2]=0;
led[2]=1;
_delay_ms(120);
}
if(a[3]!=0){
PORTB |= (1<<PB3);
c_flag = 0;
c[3]=0;
Board[1][0]=0;
led[3]=1;
_delay_ms(120);
}
if(a[4]!=0){
PORTB |= (1<<PB4);
c_flag = 0;
c[4]=0;
Board[1][1]=0;
led[4]=1;
_delay_ms(120);
}
if(a[5]!=0){
PORTB |= (1<<PB5);
c_flag = 0;
c[5]=0;
Board[1][2]=0;
led[5]=1;
_delay_ms(120);
}
if(a[6]!=0){
PORTB |= (1<<PB6);
c_flag = 0;
c[6]=0;
Board[2][0]=0;
led[6]=1;
_delay_ms(120);
}
if(a[7]!=0){
PORTB |= (1<<PB7);
c_flag = 0;
c[7]=0;
Board[2][1]=0;
led[7]=1;
_delay_ms(120);
}
if(a[8]!=0){
PORTD |= (1<<PD5);
c_flag = 0;
c[8]=0;
Board[2][2]=0;
led[8]=1;
_delay_ms(120);
}
}
c_flag=1;
moveComputer(Board);
led_2();
if_win();
if(win==1){
for(q=0;q<3;q++){
for(u=0;u<3;u++){
Board[q][u]=2;
}
}
ply = 0;
win=0;
break;
}
}
}
Die wichtigsten Funktionen sind OtherPLayer, doWin, NegaMax, moveComputer und pc. USART_Util.h ist eine selbst geschriebene Binliothek, die die wichtigsten USART-Funktionen beinhaltet.
KR-500
mein rp6 wird nur gegen menschen (nicht mensch, mensch) spielen.
interesse an der PN oder email an timok95@gmail.com hätte ich aber trotzdem.
hmm. Wie hast du 9 Duo-LEDs an einem AVR angeschlossen?
Das würde mich mal interessieren. Schieberegister sehe ich auf dem Bild nicht.
es gibt duo led, die eigendlich aus zwei leds bestehen, die in einem gehäuse vereint sind, und die mit ihren kathoden verbunden sind.
dann kann man sie einfach wie ein 6x3 ledfeld multiplexen.
Hallo,
ich hatte geplant die LEDs zu multiplexen, es stellte sich aber heraus, dass die LEDs eine Entlade Zeit von bis zu 200 millisekunden benötigen. Deshalb blieb mir nichts anderes übrig als jede Kathode/Anode an einen Pin vom µc zu löten. Der ATmega32 hat 32 I/O Pins, und 9*3, weil jede LED (http://www.pollin.de/shop/dt/MjI3OTc4OTk-/Bauelemente/Aktiv/LEDs/Duo_LED.html) 3 Anschlüsse hat bleiben also sogar noch 5 Pins übrig. Vielleicht ist das ein bisschen mit Kanonen auf Spatzen geschossen einen ATmega32 für neun LEDs zu verwenden aber in diesem Fall ging es nicht anders.
KR-500
radbruch
22.12.2009, 11:08
Hallo
Über diesen helligkeitsempfindlichen Effekt von LEDs bin ich auch schon gestolpert. Hier misst mein RP6 die Helligkeit mit seinen ACS-IR-LEDs:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=39560
Gruß
mic
Moin,
mich würde noch einmal Dein Code interessieren, mit dem Du die LEDs abfragst... Kannst Du da vielleicht mal ein Fragment für z.B. eine LED reinstellen?
MfG und vielen Dank, Ozzy
Also ich besitze einen Code für BASCOM. Wenns jemanden interessiert, stell ich in rein.
Grüße
Thomas
Hallo,
hier ist einmal ein Code mit dem man die LEDs abfragen kann:
while(1){
if(led[0]==0){
PORTA |= (1<<PA0);
PORTB &=~ (1<<PB0);
}
if(led[1]==0){
PORTA |= (1<<PA1);
PORTB &=~ (1<<PB1);
}
if(led[2]==0){
PORTA |= (1<<PA2);
PORTB &=~ (1<<PB2);
}
if(led[3]==0){
PORTA |= (1<<PA3);
PORTB &=~ (1<<PB3);
}
if(led[4]==0){
PORTA |= (1<<PA4);
PORTB &=~ (1<<PB4);
}
if(led[5]==0){
PORTA |= (1<<PA5);
PORTB &=~ (1<<PB5);
}
if(led[6]==0){
PORTA |= (1<<PA6);
PORTB &=~ (1<<PB6);
}
if(led[7]==0){
PORTA |= (1<<PA7);
PORTB &=~ (1<<PB7);
}
if(led[8]==0){
PORTC |= (1<<PC7);
PORTD &=~ (1<<PD5);
}
_delay_us(10);
if(led[0]==0){
DDRA &=~ (1<<PA0);
PORTA &=~ (1<<PA0);
}
if(led[1]==0){
DDRA &=~ (1<<PA1);
PORTA &=~ (1<<PA1);
}
if(led[2]==0){
DDRA &=~ (1<<PA2);
PORTA &=~ (1<<PA2);
}
if(led[3]==0){
DDRA &=~ (1<<PA3);
PORTA &=~ (1<<PA3);
}
if(led[4]==0){
DDRA &=~ (1<<PA4);
PORTA &=~ (1<<PA4);
}
if(led[5]==0){
DDRA &=~ (1<<PA5);
PORTA &=~ (1<<PA5);
}
if(led[6]==0){
DDRA &=~ (1<<PA6);
PORTA &=~ (1<<PA6);
}
if(led[7]==0){
DDRA &=~ (1<<PA7);
PORTA &=~ (1<<PA7);
}
if(led[8]==0){
DDRC &=~ (1<<PC7);
PORTC &=~ (1<<PC7);
}
_delay_ms(k-75);
a[2] = (PINA & (1<<PINA2));
a[3] = (PINA & (1<<PINA3));
a[5] = (PINA & (1<<PINA5));
_delay_ms(10);
a[4] = (PINA & (1<<PINA4));
_delay_ms(65);
a[0] = (PINA & (1<<PINA0));
a[1] = (PINA & (1<<PINA1));
a[6] = (PINA & (1<<PINA6));
a[7] = (PINA & (1<<PINA7));
a[8] = (PINC & (1<<PINC7));
DDRA = 0xFF;
DDRC = 0xFF;
if((a[0]!=0)){
if(c_flag){
PORTB |= (1<<PB0);
c_flag = 0;
c[0]=0;
}
else{
PORTC |= (1<<PC6);
c_flag = 1;
c[0]=1;
}
led[0]=1;
_delay_ms(120);
}
if(a[1]!=0){
if(c_flag){
PORTB |= (1<<PB1);
c_flag = 0;
c[1]=0;
}
else{
PORTC |= (1<<PC5);
c_flag = 1;
c[1]=1;
}
led[1]=1;
_delay_ms(120);
}
if(a[2]!=0){
if(c_flag){
PORTB |= (1<<PB2);
c_flag = 0;
c[2]=0;
}
else{
PORTC |= (1<<PC4);
c_flag = 1;
c[2]=1;
}
led[2]=1;
_delay_ms(120);
}
if(a[3]!=0){
if(c_flag){
PORTB |= (1<<PB3);
c_flag = 0;
c[3]=0;
}
else{
PORTC |= (1<<PC3);
c_flag = 1;
c[3]=1;
}
led[3]=1;
_delay_ms(120);
}
if(a[4]!=0){
if(c_flag){
PORTB |= (1<<PB4);
c_flag = 0;
c[4]=0;
}
else{
PORTC |= (1<<PC2);
c_flag = 1;
c[4]=1;
}
led[4]=1;
_delay_ms(120);
}
if(a[5]!=0){
if(c_flag){
PORTB |= (1<<PB5);
c_flag = 0;
c[5]=0;
}
else{
PORTC |= (1<<PC1);
c_flag = 1;
c[5]=1;
}
led[5]=1;
_delay_ms(120);
}
if(a[6]!=0){
if(c_flag){
PORTB |= (1<<PB6);
c_flag = 0;
c[6]=0;
}
else{
PORTC |= (1<<PC0);
c_flag = 1;
c[6]=1;
}
led[6]=1;
_delay_ms(120);
}
if(a[7]!=0){
if(c_flag){
PORTB |= (1<<PB7);
c_flag = 0;
c[7]=0;
}
else{
PORTD |= (1<<PD7);
c_flag = 1;
c[7]=1;
}
led[7]=1;
_delay_ms(120);
}
if(a[8]!=0){
if(c_flag){
PORTD |= (1<<PD5);
c_flag = 0;
c[8]=0;
}
else{
PORTD |= (1<<PD6);
c_flag = 1;
c[8]=1;
}
led[8]=1;
_delay_ms(120);
}
if_win();
}
}
man muss am Anfang noch led[9],c[9],a[9] und c_flag declarieren. Die ganze abfrage mit "if(led[0]==0){...} braucht man, damit bereits angetippte LEDs nicht mehr aus gehen. An PORTA liegen übrigens die Kathoden und an PORTB und PORTC die Anoden. if_win() ist eine Funktion die nachguckt ob schon jemand gewonnen hat.
Der erste Link in meinem ersten Posting enthält eine gute Erklärung in C, man muss die Abfrage nur noch umkehren und vielleicht mit einer kleinen Funktion die Umgebungshelligkeit abfragen, so wie hier zum Beispiel:
unsigned char led_abfrage (unsigned char zeit) {
PORTA |= (1<<PA1);
PORTB &=~ (1<<PB1);
_delay_us(10);
DDRA &=~ (1<<PA1);
PORTA &=~ (1<<PA1);
_delay_ms(zeit);
DDRA |= (1<<PA1);
return (PINA & (1<<PINA1));
}
void init (void){
while(led_abfrage(k))if(k++>=175)break;
k=k+80;
USART_Transmit(k);
}
Später addiere ich zu k nochmal 80, weil ich Festgestellt
Hier sind noch ein paar Links zum Thema "LED als Sensor", viele Leider auf Englisch:
http://forums.linear1.org/index.php?PHPSESSID=67b425adb819f492b8c262f54aeab6 ce&/topic,445.0.html
http://forums.linear1.org/index.php/topic,469.0.html
http://www.mikrocontroller.net/topic/56759
http://blog.makezine.com/archive/2006/06/led_touch_sensor.html
http://cs.nyu.edu/~jhan/ledtouch/index.html
http://www.merl.com/publications/TR2003-035/ <- Das ist der Technische Bericht
http://projects.dimension-x.net/technology-and-projects/ledsensors
@TomEdl
Find ich ne gut Idee, vielleicht mag ja auch noch jemand ein Beispiel Programm für eine LED in Assembler schreiben und hier posten.
KR-500
Warum addiertst Du die 80 drauf? Irgendwie fehlt da was in Deinem Text...
Hallo
Sorry, passiert mir normalerweise nicht, dass ich Sätze nicht vollende. Was ich Festgestellt habe ist, dass die LEDs sehr empfindlich sind und wenn ich zu k nochmal 80 dazu addiere werden die LEDs unempfindlicher.
KR-500
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.