Arduino Lasergame - Duino Tag (8 / 11 steg)
Steg 8: Koden
KodenKoden anteckningar:
Jag kommer inte att gå in i detalj om hur koden fungerar förhoppningsvis ganska omfattande kommentarerna i koden kommer att vara tillräckligt för att förklara det, om inte där är redan bra tutorials ute.
Begränsningar:
Koden fungerar bara är inställd på ett sätt att det bara kan göra en sak i taget och till och med dubbla kärnor arduino är enklast att bara klara som.
Detta betyder att när en tagger skjuter det inte kommer att märka om det blir skott/taggade. Du kan försvåra koden med hjälp av avbrott, men i verkligheten inte är det egentligen ett stort problem, skytte eller få skottet ske så snabbt att de mycket sällan stör varandra.
Iterationer av koden jag kommer förmodligen göra det så att tagger kontroller för att se om det har varit märkta däremellan varje bit det sänder i framtiden, vilket gör det mycket mycket osannolikt att det skulle missa ett inkommande meddelande (hit / tag). Jag har spelat några spel med hjälp av denna kod och liknande kod och det verkar fungera bra.
------------------------------------------------------------------------------------------------------------------
Början av kod (kopiera och klistra in i arduino skiss)
//
Duino Tag release V1.01
Laser Tag för arduino baserat på Miles Tag protokollet.
Av J44industries: www.J44industries.blogspot.com
För information om att bygga din egen Duino Tagger gå till:
//
Mycket beröm förtjänar att gå till Duane O'Brien om det inte hade varit för de utmärkta Duino Tag tutorials skrev han jag skulle aldrig kunnat skriva denna kod.
Duane's tutorials rekommenderas läsning för att få en bättre förståelse av arduino och IR kommunikation. Se hans webbplats http://aterribleidea.com/duino-tag-resources/
//
Denna kod anges grunderna för arduino baserade laser tag system och försöker hålla sig till protokollet miles tag om möjligt.
Miles Tag Detaljer: http://www.lasertagparts.com/mtdesign.htm
Det finns mycket utrymme för att utöka funktionerna i detta system, och förhoppningsvis spelet kommer fortsätta att utvecklas för en tid framöver.
Licens: Erkännande dela lika: ge kredit där kredit beror, men du kan göra vad du vill med koden.
Om du har kod förbättringar eller tillägg vänligen gå till http://duinotag.blogspot.com
//
Digital IO
int triggerPin = 3; Tryckknapp för primära brand. Låg = tryckte
int trigger2Pin = 13. Tryckknapp för sekundär brand. Låg = tryckte
int speakerPin = 4; Direkt utgång till piezo ekolod/högtalare
int audioPin = 9; Audio Trigger. Kan användas till kvittning ljud inspelade i sorten av elektronik kan du få i hälsningar kort att spela ett eget meddelande.
int lifePin = 6; En analog utgång (PWM) nivå motsvarar återstående livslängd. Använda PWM stift: 3,5,6,9,10 eller 11. Kan användas för att driva LED stolpdiagram. t.ex LM3914N
int ammoPin = 5; En analog utgång (PWM) nivå motsvarar återstående ammunition. Använda PWM stift: 3,5,6,9,10 eller 11.
int hitPin = 7. LED utgångsstiftet används för att ange när spelaren har drabbats.
int IRtransmitPin = 2; Primära brand läge IR sändare pin: använda stift 2,4,7,8,12 eller 13. GÖRA inte använda PWM stift! Mer information: http://j44industries.blogspot.com/2009/09/arduino-frequency-generation.html#more
int IRtransmit2Pin = 8; Sekundär brand läge IR sändare pin: använda stift 2,4,7,8,12 eller 13. GÖRA inte använda PWM stift!
int IRreceivePin = 12; PIN-koden som inkommande IR-signaler Läs från
int IRreceive2Pin = 11; Möjliggör kontroll av externa sensorer är kopplade som skilja mellan sensor platser (t.ex spotting huvud skott)
Krav på minsta pistol: trigger, mottagare, IR ledde, slå LED.
Spelare och Detaljer
int myTeamID = 1; 1-7 (0 = systemmeddelande)
int myPlayerID = 5; Spelar-ID
int myGameID = 0; Interprited av configureGane subrutin; möjliggör snabb förändring av speltyper.
int myWeaponID = 0; Deffined av Speltyp och configureGame subrutin.
int myWeaponHP = 0; Deffined av Speltyp och configureGame subrutin.
int maxAmmo = 0; Deffined av Speltyp och configureGame subrutin.
int maxLife = 0; Deffined av Speltyp och configureGame subrutin.
int automatisk = 0; Deffined av Speltyp och configureGame subrutin. Automatiska brand 0 = Semi Auto, 1 = helt Auto.
int automatic2 = 0; Deffined av Speltyp och configureGame subrutin. Sekundär brand auto?
Inkommande signal Detaljer
int fick [18]. Upplysningar: fick [0] = vilken sensoren, fick [1] - [17] byte1 byte2 paritet (Miles taggstrukturen)
int kolla = 0; Variabel som används i paritetskontroll
Statistik
int ammo = 0; Aktuella ammunitionen
int liv = 0; Nuvarande liv
Koden variabler
int timeOut = 0; Deffined i frequencyCalculations (IRpulse + 50)
int brand = 0; 0 = inte eld, 1 = primär eld, 2 = sekundär brand
int TR = 0; Trigger behandlingen
int LTR = 0; Senast utlösa behandlingen
int T2R = 0; Utlösa 2 läsning (för sekundär brand)
int LT2R = 0; Sista behandlingen utlösa 2 (för sekundär brand)
Egenskaper för signal
int IRpulse = 600; Grundläggande puls varaktigheten av 600uS MilesTag standard 4 * IRpulse för huvudet lite, 2 * IRpulse för 1, 1 * IRpulse för 0.
int IRfrequency = 38. Frekvens i kHz Standard värden är: 38kHz, 40kHz. Välj beroende på din mottagare egenskaper
int IRt = 0; LEDDE den tid att ge korrekt överföring frekvens, beräknas i installationsprogrammet.
int IRpulses = 0; Antalet svängningar som behövs för att göra en full IRpulse, beräknas i installationsprogrammet.
int huvud = 4; Sidhuvud längd i pulser. 4 = Miles etiketten standard
int maxSPS = 10; Maximal skott Per sekunder. Ännu inte utnyttjats.
int TBS = 0; Tid mellan skotten. Ännu inte utnyttjats.
Överföring data
int byte1 [8], Sträng för lagring av byte1 av de uppgifter som får överföras när spelaren bränder.
int byte2 [8], Sträng för lagring av byte1 av de uppgifter som får överföras när spelaren bränder.
int myParity = 0; Sträng för att lagra paritet av de uppgifter som får överföras när spelaren bränder.
Mottagna data
int minne = 10; Antalet signaler som skall registreras: möjliggör spel data granskas efter matchen, ingen bestämmelse om överföring / att komma åt den ännu dock.
int hitNo = 0; Slå nummer
Byte1
int spelare [10]. Matris måste vara så stor som minne
int team [10]. Matris måste vara så stor som minne
Byte2
int vapen [10]. Matris måste vara så stor som minne
int hp [10]. Matris måste vara så stor som minne
int paritet [10]. Matris måste vara så stor som minne
void setup() {
Seriella coms ställa in för att hjälpa till med felsökning.
Serial.BEGIN(9600);
Serial.println("startup...");
PIN deklarationer
pinMode (triggerPin, ingång);
pinMode (trigger2Pin, ingång);
pinMode (speakerPin, produktionen);
pinMode (audioPin, produktionen);
pinMode (lifePin, produktionen);
pinMode (ammoPin, produktionen);
pinMode (hitPin, produktionen);
pinMode (IRtransmitPin, OUTPUT);
pinMode (IRtransmit2Pin, OUTPUT);
pinMode (IRreceivePin, indata);
pinMode (IRreceive2Pin, indata);
frequencyCalculations(); Beräknar puls längder etc för önskad frekvens
configureGame(); Leta upp och konfigurera spelet Detaljer
tagCode(); Baserat på spelet Detaljer etc fungerar ut de data som överförs när ett skott avfyras
digitalWrite (triggerPin, hög); Egentligen inte behövs om din krets har rätt dra upp motstånd redan men inte skadar
digitalWrite (trigger2Pin, hög); Egentligen inte behövs om din krets har rätt dra upp motstånd redan men inte skadar
för (int jag = 1; jag < 254; i ++) {/ / Loop lekar börja upp buller
analogWrite(ammoPin, i);
playTone((3000-9*i), 2);
}
Nästa initiera 4 rader displayen lysdioder
analogWrite (ammoPin, ((int) ammo));
analogWrite (lifePin, ((int) life));
lifeDisplay();
ammoDisplay();
Serial.println("ready...");
}
Main loop de flesta av koden är i sub rutiner
void loop() {
receiveIR();
om (eld! = 0) {
Shoot();
ammoDisplay();
}
triggers();
}
SUB RUTINER
void ammoDisplay() {/ / uppdateringar Bullet LED utgång
float ammoF;
ammoF = (260/maxAmmo) * ammunition;
om (ammoF < = 0) {ammoF = 0;}
IF(ammoF > 255) {ammoF = 255;}
analogWrite (ammoPin, ((int) ammoF));
}
void lifeDisplay() {/ / uppdateringar Bullet LED utgång
float lifeF;
lifeF = (260/maxLife) * liv.
om (lifeF < = 0) {lifeF = 0;}
IF(lifeF > 255) {lifeF = 255;}
analogWrite (lifePin, ((int) lifeF));
}
void receiveIR() {/ / Void kontrollerar om en inkommande signal och avkodar det om det ser en.
int fel = 0;
IF(digitalRead(IRreceivePin) == låg) {/ / om ta emot PIN-koden är låg en signal tas emot.
digitalWrite(hitPin,HIGH);
IF(digitalRead(IRreceive2Pin) == låg) {/ / är inkommande signal som tas emot av huvudet sensorer?
fick [0] = 1;
}
annat {
fick [0] = 0;
}
While(digitalRead(IRreceivePin) == låg) {
}
för (int jag = 1; jag < = 17; i ++) {/ / upprepas flera gånger för att se till hela signalen har tagits emot
fick [i] = pulseIn (IRreceivePin, låg, timeOut); pulseIn kommandot väntar en puls och sedan registrerar dess varaktighet i mikrosekunder.
}
Serial.Print ("sensor:"); Skriver om det var ett huvud skott eller inte.
Serial.Print(received[0]);
Serial.Print("...");
för (int jag = 1; jag < = 17; i ++) {/ / ser på var och en av de mottagna pulserna
int receivedTemp [18].
receivedTemp [i] = 2;
om (fick [i] > (IRpulse - 200) & & mottagna [i] < (IRpulse + 200)) {receivedTemp [i] = 0;} / / funkar från puls längden om det var en data 1 eller 0 mottogs skriver resultatet till receivedTemp sträng
om (fick [i] > (IRpulse + IRpulse - 200) & & mottagna [i] < (IRpulse + IRpulse + 200)) {receivedTemp [i] = 1;} / / fungerar från puls längden om det var en data 1 eller 0 som tagits emot
fick [i] = 3; Våtservetter raw mottagna data
fick [i] = receivedTemp [i]; Ingångar tolkad data
Serial.Print("");
Serial.Print(received[i]); Skriva ut tolkad data resultat
}
Serial.println(""); Ny rad att städa upp utskriftsresultat
Paritetskontroll. Var uppgifterna fick en giltig signal?
Kontrollera = 0;
för (int jag = 1; jag < = 16; i ++) {
om (fick [i] == 1) {kontrollera = check + 1;}
om (fick [i] == 2) {fel = 1;}
}
Serial.println(check);
kontrollera = kontrollera >> 0 & B1;
Serial.println(check);
om (kolla! = received[17]) {fel = 1;}
om (fel == 0){Serial.println ("giltig Signal");}
Else{Serial.println("Error");}
om (fel == 0){interpritReceived();}
digitalWrite(hitPin,LOW);
}
}
void interpritReceived() {/ / efter att ett meddelande har tagits emot av ReceiveIR subrutinen denna subrutin inleder hur det ska reagera på data
IF(hitNo == Memory) {hitNo = 0;} / / hitNo sorterar ut var data ska lagras om det uttalandet innebär gamla data blir skrivs över om för mycket
Team [hitNo] = 0;
spelare [hitNo] = 0;
vapen [hitNo] = 0;
HP [hitNo] = 0;
Nästa par rader Effectivly omvandlar binära data till decimal
Im måste säker på att det finnas ett mycket effektivare sätt att göra detta
om (fick [1] == 1) {team [hitNo] = team [hitNo] + 4.}
om (fick [2] == 1) {team [hitNo] = team [hitNo] + 2;}
om (fick [3] == 1) {team [hitNo] = team [hitNo] + 1;}
om (fick [4] == 1) {spelare [hitNo] = spelare [hitNo] + 16.}
om (fick [5] == 1) {spelare [hitNo] = spelare [hitNo] + 8.}
om (fick [6] == 1) {spelare [hitNo] = spelare [hitNo] + 4.}
om (fick [7] == 1) {spelare [hitNo] = spelare [hitNo] + 2;}
om (fått [8] == 1) {spelare [hitNo] = spelare [hitNo] + 1;}
om (fick [9] == 1) {vapen [hitNo] = vapen [hitNo] + 4.}
om (fick [10] == 1) {vapen [hitNo] = vapen [hitNo] + 2;}
om (fick [11] == 1) {vapen [hitNo] = vapen [hitNo] + 1;}
om (fick [12] == 1) {hp [hitNo] = hp [hitNo] + 16.}
om (fick [13] == 1) {hp [hitNo] = hp [hitNo] + 8.}
om (fick [14] == 1) {hp [hitNo] = hp [hitNo] + 4.}
om (fick [15] == 1) {hp [hitNo] = hp [hitNo] + 2;}
om (fick [16] == 1) {hp [hitNo] = hp [hitNo] + 1;}
paritet [hitNo] = mottagna [17].
Serial.Print ("slå nr:");
Serial.Print(hitNo);
Serial.Print ("spelaren:");
Serial.Print(Player[hitNo]);
Serial.Print ("Team:");
Serial.Print(Team[hitNo]);
Serial.Print ("vapen:");
Serial.Print(Weapon[hitNo]);
Serial.Print ("HP:");
Serial.Print(HP[hitNo]);
Serial.Print ("paritet:");
Serial.println(Parity[hitNo]);
Detta är förmodligen där mer kod bör läggas utöka de spelet funktionerna i koden kontrolleras bara att den mottagna datan inte var ett systemmeddelande och drar ett liv om det inte var för tillfället.
om (spelare [hitNo]! = 0){hit();}
hitNo ++;
}
void shoot() {
IF(Fire == 1) {/ / avtryckaren har tryckt?
Serial.println ("FIRE 1");
sendPulse (IRtransmitPin, 4); Överföra Header puls, skicka puls subrutin behandlar Detaljer
delayMicroseconds(IRpulse);
för (int jag = 0; jag < 8; i ++) {/ / överföra Byte1
om (byte1 [i] == 1) {
sendPulse (IRtransmitPin, 1);
Serial.Print ("1");
}
Else{Serial.Print ("0");}
sendPulse (IRtransmitPin, 1);
delayMicroseconds(IRpulse);
}
för (int jag = 0; jag < 8; i ++) {/ / överföra Byte2
om (byte2 [i] == 1) {
sendPulse (IRtransmitPin, 1);
Serial.Print ("1");
}
Else{Serial.Print ("0");}
sendPulse (IRtransmitPin, 1);
delayMicroseconds(IRpulse);
}
IF(myParity == 1) {/ / paritet
sendPulse (IRtransmitPin, 1);
}
sendPulse (IRtransmitPin, 1);
delayMicroseconds(IRpulse);
Serial.println("");
Serial.println ("gjort 1");
}
IF(Fire == 2) {/ / där en sekundär brand läge skulle läggas
Serial.println ("FIRE 2");
sendPulse (IRtransmitPin, 4); Header
Serial.println ("gjort 2").
}
ELD = 0;
ammo = ammo - 1.
}
void sendPulse (int pin, int längd) {/ / importera variabler som denna kan för sekundär brand lägen etc.
Denna ogiltiga genertates bärvågsfrekvensen för informationen som skall överföras
int jag = 0;
int o = 0;
medan (jag < längd) {
i ++;
medan (o < IRpulses) {
o ++;
digitalWrite (pin, hög);
delayMicroseconds(IRt);
digitalWrite (pin, låg);
delayMicroseconds(IRt);
}
}
}
void triggers() {/ / kontrollerar om utlösarna har varit pressar
LTR = TR; Poster tidigare tillstånd. Primära brand
LT2R = T2R; Poster tidigare tillstånd. Sekundär brand
TR = digitalRead(triggerPin); Ser upp nuvarande trigger knappen tillstånd
T2R = digitalRead(trigger2Pin); Ser upp nuvarande trigger knappen tillstånd
Koden ser ut för ändringar i utlösande tillstånd att ge det en semi automatisk skytte beteende
om (TR! = LTR & & TR == låg) {
ELD = 1;
}
om (T2R! = LT2R & & T2R == låg) {
ELD = 2;
}
om (TR == låg & & automatisk == 1) {
ELD = 1;
}
om (T2R == låg & & automatic2 == 1) {
ELD = 2;
}
om (brand == 1 || ELD == 2) {
IF(ammo < 1) {brand = 0; noAmmo();}
IF(Life < 1) {brand = 0; dead();}
Fire rate kod läggas här
}
}
void configureGame() {/ / om spelet egenskaper lagras, kan flera spel typer skall registreras och du bara behöver ändra en variabel (myGameID) för att plocka spelet.
IF(myGameID == 0) {
myWeaponID = 1;
maxAmmo = 30.
ammo = 30.
maxLife = 3;
livet = 3;
myWeaponHP = 1;
}
IF(myGameID == 1) {
myWeaponID = 1;
maxAmmo = 100;
ammo = 100;
maxLife = 10;
livet = 10;
myWeaponHP = 2;
}
}
void frequencyCalculations() {/ / funkar alla timings behövs för att ge rätt bärvågsfrekvensen för IR-signalen
IRt = (int) (500/IRfrequency);
IRpulses = (int) (IRpulse / (2 * IRt));
IRt = IRt - 4.
Varför-4 jag hör gråter du. Det möjliggör för kommandon som ska köras.
Mer information: http://j44industries.blogspot.com/2009/09/arduino-frequency-generation.html#more
Serial.Print ("Oscilation tid period /2:");
Serial.println(IRt);
Serial.Print ("pulser:");
Serial.println(IRpulses);
timeOut = IRpulse + 50; Att lägga 50 till förväntade puls tid ger läsa en liten felmarginal på pulsen timeout värde
}
void tagCode() {/ / fungerar ut spelare tagger koden (koden som överförs när de skjuter)
byte1 [0] = myTeamID >> 2 & B1;
byte1 [1] = myTeamID >> 1 & B1;
byte1 [2] = myTeamID >> 0 & B1;
byte1 [3] = myPlayerID >> 4 & B1;
byte1 [4] = myPlayerID >> 3 & B1;
byte1 [5] = myPlayerID >> 2 & B1;
byte1 [6] = myPlayerID >> 1 & B1;
byte1 [7] = myPlayerID >> 0 & B1;
byte2 [0] = myWeaponID >> 2 & B1;
byte2 [1] = myWeaponID >> 1 & B1;
byte2 [2] = myWeaponID >> 0 & B1;
byte2 [3] = myWeaponHP >> 4 & B1;
byte2 [4] = myWeaponHP >> 3 & B1;
byte2 [5] = myWeaponHP >> 2 & B1;
byte2 [6] = myWeaponHP >> 1 & B1;
byte2 [7] = myWeaponHP >> 0 & B1;
myParity = 0;
för (int jag = 0; jag < 8; i ++) {
om (byte1 [i] == 1) {myParity = myParity + 1;}
om (byte2 [i] == 1) {myParity = myParity + 1;}
myParity = myParity >> 0 & B1;
}
Nästa par rader ut full tagger koden.
Serial.Print ("Byte1:");
Serial.Print(byte1[0]);
Serial.Print(byte1[1]);
Serial.Print(byte1[2]);
Serial.Print(byte1[3]);
Serial.Print(byte1[4]);
Serial.Print(byte1[5]);
Serial.Print(byte1[6]);
Serial.Print(byte1[7]);
Serial.println();
Serial.Print ("Byte2:");
Serial.Print(byte2[0]);
Serial.Print(byte2[1]);
Serial.Print(byte2[2]);
Serial.Print(byte2[3]);
Serial.Print(byte2[4]);
Serial.Print(byte2[5]);
Serial.Print(byte2[6]);
Serial.Print(byte2[7]);
Serial.println();
Serial.Print ("paritet:");
Serial.Print(myParity);
Serial.println();
}
void playTone (int tonen, int längd) {/ / en sub rutin för att spela toner som standard arduino melodi exemplet
för (länge jag = 0; jag < varaktighet * 1000L; i += tonen * 2) {
digitalWrite (speakerPin, hög);
delayMicroseconds(tone);
digitalWrite (speakerPin, låg);
delayMicroseconds(tone);
}
}
void dead() {/ / void bestämmer vad tagger gör när det är ur livet
Gör några ljud och blinkar några lampor
för (int jag = 1; jag < 254; i ++) {
analogWrite(ammoPin, i);
playTone((1000+9*i), 2);
}
analogWrite (ammoPin, ((int) ammo));
analogWrite (lifePin, ((int) life));
Serial.println("Dead");
för (int jag = 0; jag < 10; i ++) {
analogWrite (ammoPin, 255);
digitalWrite(hitPin,HIGH);
fördröjning (500).
analogWrite (ammoPin, 0);
digitalWrite(hitPin,LOW);
fördröjning (500).
}
}
void noAmmo() {/ / gör vissa ljud och flash några lampor när slut på ammunition
digitalWrite(hitPin,HIGH);
playTone (500, 100);
playTone(1000, 100);
digitalWrite(hitPin,LOW);
}
void hit() {/ / gör några buller och några lampor att blinka när du bli skjuten
digitalWrite(hitPin,HIGH);
livet = liv - hp [hitNo];
Serial.Print ("liv:");
Serial.println(Life);
playTone (500, 500);
om (livet < = 0){dead();}
digitalWrite(hitPin,LOW);
lifeDisplay();
}