Monday, March 2, 2020

Flying Laser Tag Gun



I've picked up a new project around laser tag.  A few years ago Flite Test showed off a prototype laser tag system that mounts on an RC airplane.  It generated alot of excitement about the concept but the system never came to market.



There was a little discussion and excitement on their forums over the last few years about how to do it.  At least one project got started and has some impressive demos.  It isn't for sale yet and isn't open source so you can't pick it up and build it yourself.  With a little time off this year I decided to see if I could get the most basic system up and working.  The goals are:
  • Easy to add to an existing plane
  • Works with existing LTX/LTTO taggers for ground-to-air and testing
  • As simple to build at home as possible

The code and build instructions are going up on github.


The basic setup is identical to a LTX tagger.  Two status LEDs give the health and ammo counters.  The FPV camera provides the pilot a view of the status LEDs on the wings and chasing planes should be able to at least see the whole strip flash red on hit to get feedback.


The wiring is pretty simple and the whole thing should easily fit on an Arduino shield.  It could be miniaturized with more work.



I've ordered a batch of PCBs to make an actual sheild which should be a little more robust for mounting.



I am also designing a number of 3d printed parts for mounting the IR LED, lens and a case for the Arduino.





Thursday, December 12, 2019

Another laser tag hosting station!

It looks like a developer in Australia picked up the code and created a different hosting software for Mobile.  Really cool.



They also made an alternative hosting station.  It looks like Lazer Swarm is not selling theirs anymore.  This one has a fancy screen!









Hosting Software: https://github.com/rmick/Combobulator
Relay: https://github.com/rmick/CombobulatorRelay

And you can buy it here:
http://www.bushandbeyond.com.au/combobulator.html

Monday, September 14, 2015

Scorched Earth

So I built a simulator ... of of objects loose inside of a spinning drum with no gravity.  I am thinking Scorched Earth, unless I hear a better suggestion.

Monday, February 2, 2015

Flying Cows


My newest game in action.  You can pick up cows and fly them around.  Who needs more gameplay then that?

github: https://github.com/afaucher/space-boat


Tuesday, June 3, 2014

Lazer Tag Spinoffs!

It looks like someone forked the LazerTagHost code and added glorious features!


They even sell the base station in a swanky case!

Thursday, February 7, 2013

Indie Lan


I was writing up a list of multiplayer indie games that look to be worth trying with a big group.  This is the list I came up with:

Known Good:
Looks Interesting:
Find more: http://www.pixelprospector.com/

Monday, May 28, 2012

PortWatch, a UPnP gateway monitor applet


I got tired of having wacky issues with UPnP port forwarding on my router with no ability to determine what is going on. I had used miniupnpc in TankTank and so was familar with the interface so I took it and feedindicator, mashed them together and came up with my own app to list current UPnP port mappings off the router and pop up notifications when the current routings change.

Yay for lazy holidays. The code is up on github as always. Under GPL3 due to feedindicator doing the same. The code itself isn't pretty, I still don't claim to know python.

Saturday, May 21, 2011

I am not an electrical engineer doctor

I've been looking at boosting the output of the IR leds for the laser tag host transceiver using an SN754410 H-Bridge but the math isn't quite coming out right.

So, something about this doesn't look right:

1,2 EN = Arduino's 5V
1A = PWM control signal
1Y = 3 TSAL6200 IR LEDs in parallel -> 100 Ohm resistor -> Arduino's ground
VCC1,VCC2 = Arduino's 5V
GROUND = Arduino's ground

For one, I am just now noticing that the TSAL6200 is rated to a max of 1.6V while I've been running at 5V (Nothing exploded). Given that the SN754410 is rated for a minimum 4.5V (maybe not the most appropriate part) I might have to step down the voltage on the output like this.
Second, it appears while the digital IO pin on the Arduino (what I am currently using) maxes at 40mA, the 3.3V line only does 50mA. There is no max listed for the 5V pin but one can assume comparable. This would imply I really can't drive the max amperage for the 3x LEDS (100mA each).
So, lets start again for an easy to acquire ~4.5 V supply, divide by 3 to be within the TSAL6200's max voltage, and add a draw of 300 mA:
Ohm's law:

0.3 A = 1.5V / x Ohm
5 Ohm = 1.5V / 0.3 A

Voltage Divider:


1.5V = ( Z2 / ( Z1 + Z2 ) ) * 4.5V
1/3V = ( Z2 / ( Z1 + Z2 ) )

I am guessing here but I think we want Z1 = 5 Ohm. With little confidence that is correct lets keep going:
Update: I've been corrected and we want Z2 to be 5 Ohm, see the comments for the new result.

1/3V = ( Z2 / ( 5 Ohms + Z2 ) )
5/3 Ohms + Z2/3 = Z2
5/3 Ohms = Z2 * 2 / 3
5 Ohms = Z2 * 2
2.5 Ohms = Z2

This gives:

1,2 EN = Arduino's 5V
1A = PWM control signal
1Y = 5 Ohm resistor -> 3 TSAL6200 IR LEDs in parallel -> Battery ground
-> 2.5 Ohms -> Battery ground
VCC1 = Arduino's 5V
VCC2 = 4.5V Battery
GROUND = Arduino's ground

So, where did I do it wrong?

Saturday, March 12, 2011

Less Lazy Code

I finally got around to getting rid of the UI glitches cause by TX in the laser tag host. New version here. Or you can grab the code here.

Yay lazer tag!

Friday, January 21, 2011

Lazer Tag Host Binaries part 2

Ok, I took the previous post of binaries down because I thought those binaries might have been broken but it was just me. Here is a new link. They are tested and work in ubuntu 10.10 and windows 7. I know in windows 7 I had to install gtk# as well to get it to open. If your arduino isn't programed the app may hang, if it isn't plugged in you should be fine but won't get past the setup menu.

Download gtk 2.22
More Versions

Update: You also need a recent version of GTK installed in addition to gtk#.
Update 2: It appears that the release version doesn't work for everyone. Try the debug version if you are having issues.

Sunday, January 16, 2011

Patents?

Someone apparently located the LTTO patent (US7632187). That would have been totally useful.

Actually, reading it now it would have been super useful. It details all the bit fields. Most of mine just switch the whole byte on the game type because the LTTO only starts games with one set of settings. I guess there is quite a bit more I can do. Rapid tags? Neat!

Friday, January 14, 2011

This is how you build a laser tag hosting station

Official Note: This works better if ground is connected to something, I suggest the middle pin of the IR receiver.



Saturday, November 13, 2010

Clearanced-based Hierarchical Pathfinding (HPA*)

Aigamedev.com seems to always have something interesting to read. This week it is using Annotated A* to find a path of at least minimum clearance through a graph. They also go into how you can reduce the graph to an annotated hierarchical pathfinding graph for near-optimal results at much greater speeds. The article is well explained and comes out with a very practical result.

If your not convinced maybe their talk on zombie brain AI from last month will convince you.

Saturday, October 9, 2010

LazerTag Team Ops Packet - Part 4



I figured out the final scoring details and completed the GUI. You can host a complete game from the GUI now and get all the score readouts.

The fields worked out as follows:

COMMAND_CODE_PLAYER_REPORT_SCORE_RECORDS
0x041-0x043, //command code (last two bits are the team number)
0x00, //game id
0x10, // team_number << 4 | player_number
0xXX, //player hit mask
0xXX, //hits from player indicated by first set bit in mask
0xXX, //hits from player indicated by second set bit in mask
... (the hit bytes sum to count_ones(mask_byte)
0x100, //checksum

The secret to determine the SCORE_RECORD was noticing that COUNTDOWN varied more then I noticed in my initial testing.

COMMAND_CODE_COUNTDOWN_TO_GAME_START
0x000, //command code
0x00, //game id
0x30, //seconds left in digit hex
0x08, //players on team 1
0x08, //players on team 2
0x08, //players on team 3
0x100, //checksum

If t2p0 shoots t1p0 and "players on team 2" == 0, then t1p0's gun will ignore the shot. Hence, those shots won't show up in the score report.

The following packets still have unknown values:
COMMAND_CODE_SCORE_ANNOUNCEMENT
COMMAND_CODE_PLAYER_REPORT_SCORE
COMMAND_CODE_GAME_OVER

Hey you, decode!

As always, get the code here.

Wednesday, September 29, 2010

LazerTag Team Ops Packet - Part 3

More features working, more fields decoded. Still no score reporting. I found the 'damage' field and the 'still alive' field but not the who hit you with a candlestick in the library section. Get the Code.

COMMAND_CODE_SCORE_ANNOUNCEMENT
0x031, //command code
0x00, //game id
0x11, // team_number << 4 | player_number
0x0F, //unknown
0x100, //checksum

COMMAND_CODE_PLAYER_REPORT_SCORE
0x040, //command code
0x00, //game id
0x10, // team_number << 4 | player_number
0x00, //damage received
0x01, //still alive
0x00, //unknown
0x00, //unknown
0x00, //unknown
0x02, //unknown
0x100, //checksum

COMMAND_CODE_PLAYER_REPORT_SCORE_RECORDS
0x041, //command code
0x00, //game id
0x10, // team_number << 4 | player_number
0xXX, //unknown
0xXX, //unknown
0xXX, //unknown, looks like hits from a certain player but unable to determine which
0x100, //checksum

I also determined that 0x41 is actually sent by the gun. I am pretty sure it contains the hit report but I have been unable to decode it. With 3 guns it is sometimes 2 bytes of unknown data and sometimes 3. Lastly the 'rank' announce that cycles through all the players.

COMMAND_CODE_GAME_OVER
0x042, //command code
0x00, //game id
0x10, // team_number << 4 | player_number
0x00, //player rank
0x01, //team rank
0x00, //unknown
0x00, //unknown
0x00, //unknown
0x00, //unknown
0x100, //checksum

Tuesday, September 28, 2010

LazerTag Team Ops Packet - Part 2

Good progress with the LTTO hosting gun!

The hosting packets are composed of:

9 bit command packet
[ 1 bit zero ] [ 8 bit command code]
8 bit data packet * n
9 bit crc packet
[ 1 bit one ] [ 8 bit sum of previous bytes ]

All of which use the 3000 ms mark, 6000 ms sleep, 3000 ms mark header.

The command codes discovered so far are:
COMMAND_CODE_CUSTOM_GAME_MODE_HOST = 0x02,
COMMAND_CODE_PLAYER_JOIN_GAME_REQUEST = 0x10,
COMMAND_CODE_ACK_PLAYER_JOIN_RESPONSE = 0x01,
COMMAND_CODE_CONFIRM_PLAY_JOIN_GAME = 0x11,
COMMAND_CODE_COUNTDOWN_TO_GAME_START = 0x00,
COMMAND_CODE_SCORE_ANNOUNCEMENT = 0x31,
COMMAND_CODE_PLAYER_REPORT_SCORE = 0x40,

The packet groups look like:
COMMAND_CODE_CUSTOM_GAME_MODE_HOST

0x002, //command code
0x00, //Game ID
0x10, //game time minutes
0x10, //tags
0xFF, //reloads
0x15, //sheild
0x10, //mega
0x20, //unknown
0x01, //unknown
0x100, //checksum

Where the first and last packets are 9 bits. The known values are base 10 hex where 9=0x09 but 10=0x10 and 0xff is 'unlimited'.

The join game request is sent by the joining gun on recv of the above advertisement.

COMMAND_CODE_PLAYER_JOIN_GAME_REQUEST
0x010, //command code
0x00, //game id
0x00, //player id
0x00, //unknown
0x100 //checksum

The host then confirms the join by sending back the ids and team/player numbers

COMMAND_CODE_ACK_PLAYER_JOIN_RESPONSE
0x001, //command code
0x00, //game id
0x00, //player id
0x09, //some combination of team/player number
0x100 //checksum

The gun must then confirm this join to be part of the game by sending back both id's

COMMAND_CODE_CONFIRM_PLAY_JOIN_GAME
0x011, //command code
0x00, //game id
0x00, //player id
0x100 //checksum

If the host goes 60 seconds without getting another player it starts the game countdown at 30 seconds and starts sending countdown announcements once a second.

COMMAND_CODE_COUNTDOWN_TO_GAME_START
0x000, //command code
0x00, //game id
0x30, //seconds left in digit hex
0x02, //unknown
0x00, //unknown
0x00, //unknown
0x100, //checksum

Once the game starts the LTTO gun sends the 5 bit, all zero, 3k,6k,6k pulse once a second but it is not required. All guns will end the game after the timeout in the game announce. Then the host gun starts the score announce beacon.

COMMAND_CODE_SCORE_ANNOUNCEMENT
0x031, //command code
0x00, //game id
0x11, //unknown
0x0F, //unknown
0x100, //checksum

The player gun response is still a mystery but it looks like:

COMMAND_CODE_PLAYER_REPORT_SCORE
0x040, //command code
0x00, //game id
0x10, //unknown,
0x00, //unknown, hits?
0x01, //unknown
0x00, //unknown
0x00, //unknown
0x00, //unknown
0x00, //unknown
0x100, //checksum

More then one similar looking packet is exchanged. Determining the meanings will require multi-gun controlled tests. After the score is reported the host sends back command 0x41 which appears to report the hits per player. When all players have checked in the host spits out command 0x32 periodically, with still contents of unknown meaning.

Sunday, September 26, 2010

LazerTag Team Ops Packet - Part 1

Phoenix LTX

[ 3 bits - zero ] [ 2 bits - team ] [ 2 bits - damage ]

Team:
0x00 = Solo
0x01-0x03 = Team 1-3

Damage:
0x00-0x03 = Damage 1-4 (3-4 are only usable by LTTO as Mega-Tag)

LTTO

[ 5 bits - zero (for solo at least) ]

Location Pulse

#define LTTO_HDR_MARK_ONE 3000
#define LTTO_HDR_MARK_TWO 6000
#define LTTO_HDR_SPACE 6000
#define LTTO_ONE_MARK 2000
#define LTTO_ZERO_MARK 1000
#define LTTO_SPACE 2000

Thursday, September 2, 2010

Goal-Oriented Action Planning

I found a very good paper on AI planning by the guy that did the F.E.A.R. AI architecture.

Jeff Orkin's page on GOAP contains lots more links to even more details.

Learn something!

Monday, August 23, 2010

Phoenix LTX

Hey look I made a lazer tag gun! It runs on Arduino using the IRremote library.

Send:
void IRsend::sendPHOENIX_LTX(unsigned long data, int nbits) {

enableIROut(36);
//HEAD
mark(PHOENIX_HDR_MARK);
space(PHOENIX_HDR_SPACE);
mark(PHOENIX_HDR_MARK);
int i = 0;
for (i = 0; i < 7; i++) {
if (i % 2 == 0) {
space(PHOENIX_LTX_SPACE);
} else {
mark(PHOENIX_LTX_ZERO_MARK);
}
}
//DATA
if ((data >> 2) & 1 == 1) {
mark(PHOENIX_LTX_ONE_MARK);
} else {
mark(PHOENIX_LTX_ZERO_MARK);
}
space(PHOENIX_LTX_SPACE);
if ((data >> 0) & 1 == 1) {
mark(PHOENIX_LTX_ONE_MARK);
} else {
mark(PHOENIX_LTX_ZERO_MARK);
}
//TAIL
for (i = 0; i < 4; i++) {
if (i % 2 == 0) {
space(PHOENIX_LTX_SPACE);
} else {
mark(PHOENIX_LTX_ZERO_MARK);
}
}
space(PHOENIX_LTX_SPACE);

}

Receive:
long IRrecv::decodePHOENIX_LTX(decode_results *results) {

long data = 0;

int offset = 1;

int i = 0;

//HEAD

if (results->rawlen != 18) {

return ERR;

}

if (!MATCH_MARK(results->rawbuf[offset], PHOENIX_HDR_MARK)) {

return ERR;

}

offset++;

if (!MATCH_SPACE(results->rawbuf[offset], PHOENIX_HDR_SPACE)) {

return ERR;

}

offset++;

if (!MATCH_MARK(results->rawbuf[offset], PHOENIX_HDR_MARK)) {

return ERR;

}

offset++;

for (i = 0; i < 7; i++) {

if (i % 2 == 0) {

if (!MATCH_SPACE(results->rawbuf[offset], 2000)) {

Serial.println(i, DEC);

return ERR;

}



} else {



if (!MATCH_MARK(results->rawbuf[offset], 1000)) {

Serial.println(i, DEC);

return ERR;

}

}

offset++;

}

Serial.println("Data");

//DATA

for (i = 0; i < 3; i++) {

if (MATCH_MARK(results->rawbuf[offset], PHOENIX_LTX_ONE_MARK)) {

data << 1;

data |= 1;

} else if (MATCH_MARK(results->rawbuf[offset], PHOENIX_LTX_ZERO_MARK)) {

data << 1;

data |= 0;

} else {

Serial.println(i, DEC);

return ERR;

}

offset++;

}

Serial.println("Tail");

//TAIL

for (i = 0; i < 2; i++) {

if (!MATCH_SPACE(results->rawbuf[offset], 2000)) {

return ERR;

}

offset++;

if (!MATCH_MARK(results->rawbuf[offset], 1000)) {

return ERR;

}

offset++;

}



// Success

results->bits = 3;

results->value = data;

results->decode_type = PHOENIX_LTX;

return DECODED;

}

Defines:
#define PHOENIX_HDR_MARK 3000
#define PHOENIX_HDR_SPACE 6000
#define PHOENIX_LTX_ONE_MARK 2000
#define PHOENIX_LTX_ZERO_MARK 1000
#define PHOENIX_LTX_SPACE 2000

Sunday, May 30, 2010

TankTank 0.3.1 (Experimental)



Less 'crashing into walls' Edition.

Download