Source: https://mokxi.com/learn/arduino-ir-transmitter
Updated: 2026-10-25

Learn

# Infrared laser tag with two Arduino Nanos

Intermediate

Written by the Mokxi team, updated October 25, 2026

Start building free Open the editor

Or see every lesson.

- 455 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Press a trigger button to tag the other player

The Laser tag example: two simulated ATmega328Ps, an IR LED and a VS1838B each, and no wire between them.

An infrared LED looks like any other LED with a clear or blue-tinted lens, and it is how every TV remote talks. Put one on an Arduino pin and the IRremote library can send the same codes a remote sends, to a VS1838B receiver on another board. That is all laser tag is: each player has an IR LED to shoot with and a receiver to be hit on.

The circuit above is two Arduino Nanos facing each other, each with a trigger button, an IR LED behind a 220 ohm resistor, a VS1838B receiver and a red hit LED. Press a trigger and that player fires one NEC code; the other player’s receiver decodes it, counts the hit and lights its LED. Five hits and you are out. Both boards run the same sketch.

## What you need

- Two Arduino Nanos (or Unos)
- Two 940 nm IR LEDs, or two KY-005 modules, with a 220 ohm resistor each
- Two VS1838B IR receivers (or KY-022 modules)
- Two pushbuttons
- Two red LEDs with a 220 ohm resistor each
- A breadboard and jumper wires for each player

## Wiring

Part and pin | Goes to | Note

IR LED, through 220 ohm | Pin 3 | IrSender’s pin; the LED’s short leg to GND

VS1838B OUT | Pin 2 | IrReceiver.begin(2)

VS1838B VCC and GND | 5 V and GND |

Trigger button | Pin 4 and GND | INPUT_PULLUP, so pressed reads LOW

Hit LED, through 220 ohm | Pin 5 |

## Why the LED has to flash at 38 kHz

A VS1838B does not answer infrared light. Sunlight and lamps are full of it. It answers light that flashes on and off about 38,000 times a second, and turns each burst of that into a LOW on its OUT pin. So an IR LED that is simply switched on with digitalWrite() lights up (a phone camera shows it glowing violet) and the receiver sees nothing at all.

IrSender does the flashing for you. Every burst of a frame, it switches the pin on and off at 38 kHz in software, on any pin you give it. In the simulator you can see the difference: drive the LED with digitalWrite(3, HIGH) and the receiver’s dome stays dark; send with IrSender and it lights for every burst.

## One shot, one NEC frame

A shot is an NEC frame with address 0x1A and command 0x01, which takes about 70 milliseconds to send. The receiving player checks all three before counting a hit: the protocol, the address and the command. Anything else in the room, a TV remote for instance, is ignored.

The trigger fires on the moment the button goes from HIGH to LOW, and then the gun reloads for half a second. Holding the button fires once, and the few milliseconds of contact bounce never fire twice.

Firing and counting hits, from the Laser tag example

## Aiming

Infrared goes in a straight line. A 5 mm IR LED throws a beam about 20 degrees either side of straight ahead, and a VS1838B sees light that arrives within about 45 degrees of where its lens faces. Each player’s LED and receiver point the same way, at the other player, so you can never tag yourself.

Mokxi works the beam out from the canvas: the LED’s rotation, its aim setting, its range (the canvas is to scale, and the default reaches about 5 m) and anything in the way. Hover over an IR LED to see its beam. Turn one away while the circuit runs and its shots stop landing; put a part on the line between the two players and nothing gets through.

## Try it in the editor

Rotate the left player’s IR LED, or set its aim to 60, and fire: the serial monitor says "Fire!" and the other player hears nothing. Set it back to 0 and the next shot is a hit.

Copy one player’s parts and wires, with a third Nano, and you have three-way laser tag. Every receiver a LED is pointed at gets the shot.

Give each player a different TAG_ADDRESS and have the receiver print who hit it: decodedIRData.address is the shooter.

## Common mistakes

Turning the IR LED on with digitalWrite(). It lights, but a receiver ignores anything that is not flashing near 38 kHz.

No resistor on the IR LED. Its drop is only about 1.2 V, so a pin straight into it tries to pass far more than the pin’s 40 mA limit.

Calling tone() on a board that is also receiving. IrReceiver uses timer 2 on a Nano, and so does tone().

Expecting to see the LED light up. Infrared is invisible to the eye; look at it through a phone camera.

## Questions

Which pin does IrSender use?

Any pin: IrSender.begin(pin) makes the carrier in software on the pin you give it. Older sketches that call IrSender.begin() with no pin use IR_SEND_PIN, which is 3 on a Nano or Uno.

Do I need a KY-005 module or a bare LED?

Either. The KY-005 is the same 940 nm LED on a small board, from S to the - pin, and most boards carry no resistor, so add one as you would for a bare LED.

How far does an IR LED reach?

A few meters indoors from a 20 mA LED, more from a remote that pulses its LED harder. Mokxi gives each LED a range you can set, 5 m by default, and anything in range and in the beam is seen.

Related

## Keep going

Arduino IR Remote: Decode NEC, Switch Lamps Arduino nRF24L01: Wiring, Code and a Radio Doorbell Arduino Button Debounce: See the Bounce, Then Fix It How the IR LED and the KY-005 are modeled The IR receiver, pin by pin The Arduino Nano simulator The project page, with the full sketch Intermediate

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
