Simples Lasertagsystem

Hallo liebe Community,
ich bin ein Newbie am Arduino und habe mein erstes Projekt vor, war klar dass schnell die ersten Probleme auftreten werden...

Geplant ist ein sehr simples Lasertagsystem (Betonung auf sehr).
Ich verwende:
Arduino Leonardo
Vishay TSOP 38kh 950nm
IR LED 950nm
Drucktaster
Rote LED
Gelbe LED
kleiner Piezolautsprecher

Wenn der Taster gedrückt wird, soll von der IR LED ein Lichtstrahl "abgefeuert" werden. Der Lautsprecher soll ein kurzes Klack Geräusch verursachen und von der gelben LED soll auch ein kurzer Lichtstrahl ausgehen.
Wenn der IR Sensor getroffen wird soll die rote LED 5 Sekunden lang leuchten.
Es gibt also (vorerst) keine Munition, kein Leben und auch keine Informationen die mit der IR LED übertragen werden.

Meine Fragen sind:
Besteht der Code eigentlich nur aus 2 Abfragen, nämlich ob der Taster gedrückt ist und ob der Sensor ein Signal (Treffer) ermittelt?
Der Sensor spricht nur bei 38kh an, wie bekommt die IR LED eine solche Frequenz?
Wenn pro Knopfdruck nur ein Schuss gelöst werden soll, also der Taster für einen zweiten Schuss losgelassen und noch einmal gedrückt werden soll, wie bekommt man das hin (man muss ja wohl weg vom loop, hin zu einer einmaligen Aktion?)

Ich hoffe ihr könnt mir helfen, vielen vielen Dank im Voraus!
Lg Fred

Fred1234:
Der Sensor spricht nur bei 38kh an, wie bekommt die IR LED eine solche Frequenz?

Entweder über einen selbst programmierten Timer oder die IRRemote Lib:

Die ist eigentlich für Fernbedienungen gedacht, aber lässt sich auch für sowas misbrauchen

Allerdings ist eine IR-LED kein Laser. Die LED strahlt in einem bestimmten Winkel ab. Sonst müsste man mit der Fernbedienung genau auf das Gerät zielen. Reflexionen können genauso erfasst werden.

Besteht der Code eigentlich nur aus 2 Abfragen

Na ja, für das Klackgeräusch brauchst du schon mindestens 3 Anweisungen: (an, kurz warten, aus) :wink:

Fang mal damit an:

  • Wenn der Taster gedrückt wird, blitzt die gelbe LED kurz auf (unabhängig von der Dauer des Tasterdrucks)
    und der Piezo macht "klack". ( Evtl. ist ein kuzer Pieps - Ton besser )
  • Das ganze wiederholt sich erst, wenn der Taster kurz losgelassen war.
    Das ist schon kein einfaches Projekt zum Start, aber machbar.

Im freien Raum wird somit nahezu jeder Schuss ein Treffer. Die LED hat einen Abstrahlwinkel und der TSOP gute Augen XD

Das kann man zuhause leicht mit der nächstbesten Fernbedienung und dem dazugehörigen Gerät ausprobieren. Es reicht die Reflexion der Wand, sofern die nicht allzu dunkel ist und schon passiert was.

Wow, das ging ja schnell! Vielen Dank für all die Antworten!
Es ist mir klar dass ich den LED Strahl bündel muss, dafür hab ich auch alle Teile (Rohre, Linse).
Aber meine Probleme sind klar die des Code Schreibens...

"Das ganze wiederholt sich erst, wenn der Taster kurz losgelassen war."
Wie genau macht man das? Und geht bei diesem Schritt nicht die IR LED unter?

Fred1234:
Wie genau macht man das? Und geht bei diesem Schritt nicht die IR LED unter?

Ich fürchte, Du musst Dich schon ein wenig mit der Materie beschäftigen.
Schau Dir die Beispiel-Sketches an, Blink ist schon die richtige Richtung für die LED.
Dann wie man Taster abfragt, de Zustand speichert und dann bist Du so in Fahrt dass Dich nichts mehr bremsen kann.

Ohne das geht's aber leider nicht.

Ich hab mich mal rangesetzt und mal angefangen zu probieren (nach dem einlesen natürlich;) ).
Die Seiten auf denen die Infrarot-Bibliothek erklärt wurden, waren gut und ich wollte das auch gleich umsetzen.
Ein kurzer Test ob der Sensor reagiert/ die Infrarot LED wirklich mit 38kh sendet:

#include <IRremote.h> 

const int buttonpin = 12;
const int ledpin = 13;
const int sensorpin = 11;
const int roteledpin = 10;

int buttonstate = 0;
int sensorstate = 0;

IRsend irsend;
void setup(){
  pinMode(buttonpin, INPUT);
  pinMode(ledpin, OUTPUT);
  pinMode(sensorpin, INPUT);
  pinMode(roteledpin, OUTPUT);
  irsend.enableIROut(38);
  irsend.mark(0);
  
}

void loop(){
  buttonstate = digitalRead(buttonpin);
  if (buttonstate == HIGH){
    digitalWrite(ledpin, HIGH);
  } 
  else {
    digitalWrite(ledpin, LOW);
  }
  
  sensorstate = digitalRead(sensorpin);
  if (sensorstate == HIGH) {
    digitalWrite(roteledpin, HIGH);
  }
  else {
    digitalWrite(roteledpin, LOW);
  }
  
}

Der Code wird beim Überprüfen als richtig angezeigt, und normal auf das Board übertragen.
Nach dem Bau der Schaltung ergeben sich allerdings große Probleme:
Der Infrarottransistor wird unglaublich heiß, die rote LED spielt verrückt (leuchtet, schaltet sich aus, flimmert, schaltet ein wenn Knopf gedrückt..)

Ich habe den Transistor an Ground, 5 Volt und Arduino INPUT angeschlossen; passt etwas nicht (ich bin mir recht sicher die Beinchen nicht vertauscht zu haben)?
Der Druckknopf hat keinen Widerstand bekommen, aber die Fehler waren auch noch zu sehen als der IR Transistor längst entfernt worden war. Also muss noch irgendwo der Wurm liegen?

Taster ohne Widerstand geht schon mal nicht. Am besten du machst das:

pinMode(buttonpin, INPUT_PULLUP);

Und schaltest den Taster gegen Masse. Dann ist er nicht gedrückt HIGH (durch den internen Pullup) und gedrückt LOW

Der Sensor ist im Datenblatt beschrieben:

Gleich oben links. 1=OUT, 2=GND, 3=5V. Zumindest für die TSOP44xx und 48xx Serie. Schau vielleicht mal nach welchen Typ du genau hast. Da gibt es nämlich leicht verschiedene. Beim 22xx und 22xx ist GND und 5V anders herum!

Die IR-LED braucht auch einen Vorwiderstand. Genauso sonstige LEDs die du als Anzeige hast.

Fred1234:
Der Code wird beim Überprüfen als richtig angezeigt, und normal auf das Board übertragen.

Das ist schon mal gut!

Fred1234:
Der Infrarottransistor wird unglaublich heiß, die rote LED spielt verrückt (leuchtet, schaltet sich aus, flimmert, schaltet ein wenn Knopf gedrückt..)

Ich habe den Transistor an Ground, 5 Volt und Arduino INPUT angeschlossen; passt etwas nicht (ich bin mir recht sicher die Beinchen nicht vertauscht zu haben)?

Zeig uns den tatsächlichen Aufbau, mit Text beschreiben wird das nix.

Na, alles abgebrannt oder läuft's jetzt?

Es hat gut funktioniert :wink: Musste eben den Widerstand setzen.
Sobald ich wieder ein Stündchen Zeit habe möchte ich den Lautsprecher einbinden. Da werd ich mich noch einlesen müssen.

Heiho,

lustig, ich baue gerade ebenfalls an einem Lasertagsystem und kann dir dabei auch gerne helfen :slight_smile:
Ich würde dir aber abraten für IR die library zu nutzen, ich musste mich da durchwühlen wie das funktioniert, aber rausgekommen ist meine eigene Library die ich voll verstehe und die auch nur das macht, was ich brauche. Ist alles garnicht mal so schwer. Mir war ebenfalls wichtig das feuern und "getroffen werden" gleichzeitig möglich ist.

Ein paar Monate ist´s her, aber jetzt kann ich wieder durchstarten..
Na ja, fast. Ich hab ein Problem.. :stuck_out_tongue:

Ich habe den alten Code (siehe oben) wieder ausgegraben und wollte an dem weitermachen.
Was noch fehlt ist ja der Sound, und gaanz wichtig, das Multitasking, das Bauerbyter ja schon erwähnt hat.
ABER: Beim übertratgen des alten Codes, kommt eine Fehlermeldung:

C:\Program Files (x86)\Arduino\libraries\IRremote\IRremote.cpp:266: error: 'TCNT2' was not declared in this scope

Weil ich den PC zwischenzeitlich neu aufgesetzt habe, habe ich das Arduinoprogramm neu installieren müssen, aber ich hab die Library wieder hinzugefügt.

Kann es sein dass meine Version des Programs zu neu ist? Zurück auf 1.0?
LG Fred

Pfeif auf die Bibliothek, wenn sie nicht funktioniert, dann raus mit ihr aus dem Code.
Ich bringe die IR LED auf die 38khz indem ich 13 Mikrosekunden ein und ausschalte.
Um aber die Multitaskingfähigkeit zu erhalten: IR LED, Lautsprecher und gelbe AufblitzLED kann ich nicht "delay", sondern muss micros() verwenden.
Der IR Sensor behält aber weiterhin eine "delay" funktion, er schaltet eine rote LED ein, wenn er getroffen wird.

Das Problem: die Schaltung funktioniert, aber trotz der "delay" funktion wird die IR LED (Lautsprecher und AufblitzLED sind noch nicht verbaut) nur in 50% der fälle ausgeschalten wenn der Sensor getroffen wird.
Das sieht so aus:
Ich betätige den Knopf um die IR LED einzuschalten. Rote LED geht an. Die IR LED bleibt ebenfalls an.
Sollte aber eigentlich ausgehen..?
Manchmal tut sie das auch, aber eben nicht immer..!

Auch grundsätzlich bereitet mir die Schaltung Kopfzerbrechen. Die rote LED schaltet sich manchmal einfach so ein (ohne dass absichtlich ein IR Signal an den Sensor gesendet wurde), und auch wenn ich an das Kabel stoße, schaltet sie sich manchmal ein..

Ich weiß nicht woran das liegt, kann mir jemand weiterhelfen?
LG fred

micros() geht aber nur auf 4µs genau.

Du hast einen Leonardo? Dann sollte er gar nicht Timer2 suchen. Den gibt es da nämlich nicht. :~

Du kannst mal in IrRemote den Timer zu ändern. Schau dir mal IRremoteInt.h an:
https://github.com/shirriff/Arduino-IRremote/blob/master/IRremoteInt.h
Da findest du ziemlich am Anfang das:

#elif defined(__AVR_ATmega32U4__)
//#define IR_USE_TIMER1 // tx = pin 14
//#define IR_USE_TIMER3 // tx = pin 9
#define IR_USE_TIMER4_HS // tx = pin 10

Je nachdem was was man das auskommentiert wird ein anderer Timer verwendet.

Aber wie gesagt, dass er da überhaupt was mit TCNT2 kompilieren will ist seltsam

Danke für den Hinweis, aber ich möchte die IRremote library erst wieder zur Hand nehmen wenn das mit der micr() funktion geklappt hat. Erst dann möchte ich an der library "herumpfuschen", ich kenne mich mit timer noch null aus..

micros() geht aber nur auf 4µs genau

Was heißt das? Die Frequenz der IR LED stimmt einmal ziemlich sicher.

Kann es sein, dass bei meinem Code das Abschalten der IR LED dem ZUfall überlassen wird. Muss ich eventuell klarmachen, dass nicht nur die rote LED eingeschalten werden muss, sondern auch der restliche Betrieb auch?

const int led = 13;

const int sensor = 9;
int sensorstate = 0;

const int irled = 5;
int irledstate = LOW;
long prev = 0;
long interval = 13;

const int trigger = 4;
int triggerstate = 0;

const int speaker = 6;
const int muzzleled = 2;

void setup(){
  pinMode(led,OUTPUT);
  pinMode(sensor,INPUT);
  pinMode(irled, OUTPUT);
  pinMode(trigger, INPUT);
  pinMode(speaker, OUTPUT);
  pinMode(muzzleled, OUTPUT);
  unsigned long currentMicros = micros();
}


void loop(){
  triggerstate = digitalRead(trigger);
  if(triggerstate == HIGH){
   
    if((micros() - prev) > interval) {
      prev = micros();
      irledstate = !irledstate;
      digitalWrite(irled, irledstate);
    }
    
  }
  else{
    digitalWrite(irled, LOW);

  }
  
  sensorstate = digitalRead(sensor);
  
  if(sensorstate == LOW){
    digitalWrite(led, HIGH);
    delay(5000);
    digitalWrite(led, LOW);
  }
  
  else{
    digitalWrite(led,LOW);
  }
}

Gute Nacht, Fred

Was heißt das? Die Frequenz der IR LED stimmt einmal ziemlich sicher.

Der TSOP hat auch etwas Toleranz, aber micros() kann ab und zu mal um +/- 4 µs schwanken.

Bei 13µs hast da auch nicht besonders viel Zeit anderen Code dazwischen zu machen. digitalRead()/digitalWrite() z.B. ist ziemlich langsam und braucht ca. 60 Takte. Das sind selbst schon 3-4µs. Damit geht es schneller:
https://code.google.com/p/digitalwritefast/downloads/list

Deswegen nimmt man bei sowas schnellem am besten einen Timer.

Das macht nichts:

unsigned long currentMicros = micros();

Existiert nur in setup()

long prev = 0;

Die Variable läuft nach 70 Minuten über. Unsigned verwenden

Existiert nur in setup()

Es befindet sich ja im Setup?

Auch diese library macht Probleme "'COM2B1' was not declared in this scope".
Muss ich in der library etwas verändern, damit die Timer passen? Gibt es ein paar gute Seiten um sich in die Timer einzulesen?

Grundsätzlich, gibt es ein Problem mit meinem Code? Mal abgesehen von dem Problem dass es dem Zufall überlassen bleibt, ob sich IR LED, Lautsprecher und gelbe LED ausschalten wenn der Sensor getroffen wird (trotz der delay-Zeile für die rote Treffer LED).

Vielen Dank für die schnelle Hilfe!
Lg fred

Es befindet sich ja im Setup?

Und die Variable existiert auch nur dort. Das macht also nichts und ist überflüssig

Wie gesagt, du hast einen Leonardo und da gibt es keinen Timer2. Also sollte der gar nicht gesucht werden. Mach mal was ich in #Reply14 gesagt habe und schalte mal auf Timer1 oder Timer3 um.

Es scheint fast so als ob er nicht erkennt dass du einen Leonardo hast. Du kannst dir da mal am Ende dieses Bereichs den #else Zweig anschauen:

#else
//#define IR_USE_TIMER1 // tx = pin 9
#define IR_USE_TIMER2 // tx = pin 3
#endif

Und auch hier mal Timer1 statt Timer2 aktivieren. Das ist eigentlich für den UNO gedacht. Aber wenn er das Atmega324U #define nicht erkennt und statt dessen in den #else Teil rutscht, dann wärst du bei Timer2 gelandet.
Wenn du nun die Kommentare herumdrehst wird statt dessen Timer1 verwendet.

Wobei das beim Atmega324U mit den Pins für den Leonardo nicht stimmt (das ist für den Teensy). Wenn ich mir das ansehe:
http://pighixxx.com/leonardopdf.pdf
Dann ist Timer1 = Pin 9
Timer3 und Timer4 = Pin 5

Hast du beim Compilieren das richtige Board ausgewählt? Ich nehme mal an ja, sonst würde er es nicht hochladen. Außerdem wird das Grund sein weshalb die IDE die Register für Timer2 nicht kennt.

OK. Die IR library, wie´s aussieht hatte ich eine veralterte Datei (entschuldige, ich war mir verdammt sicher, dass ich die aktuelle heruntergeladen hatte!), also die Int.h Datei. Jetzt habe ich die aktuelle. Habe trotzdem in dem else Zweig auf timer1 umgestellt:

 #else
  #define IR_USE_TIMER1   // tx = pin 9
  //#define IR_USE_TIMER2     // tx = pin 3
#endif

Folgende Fehlermeldung: 529: error: 'volatile struct irparams_t' has no member named 'rawlen'

Liegt der Fehler bei der digitalWriteFast-library auch am falschem Timer? Kann man bei der auch den Timer anderst setzten?
In dem Code mit der micros() funktion bleibt es dem Zufall überlassen ob die delay funktion den Rest des Codes stoppt, oder bloß pausiert (also weiterleuchten usw.)

Arduinoboard ist das richtige ausgewählt.

Lg fred