Project showcase
2016 Halloween Laser Maze

2016 Halloween Laser Maze © GPL3+

Experience the challenge and thrill of deactivating the system without breaking a laser beam. Built with Arduino, BLE, and DMX lighting.

  • 33 respects

Components and supplies

Laser Module
Adafruit industries ada161 image 75px
Photo resistor
Ph a000066 iso (1) ztbmubhmho
Arduino UNO
11113 01
SparkFun Arduino Pro Mini 328 - 5V/16MHz
DMX Shield
RedBear BLE Shield
Fairchild semiconductor tip120 image
Darlington High Power Transistor
Used to power lasers.
5M RGB LED Strip
22 AWG Hook-Up Wire
3 Channel DMX Decoder
Block Terminal Strip
Cat5 Cable
Used to connect laser / sensor towers to central hub.
Barrel Jack Screw Terminal Connector (M+F Set)
Scrap Wood
Used to build laser pan/tilt brackets and laser / sensor towers.
Emergency Stop Button
Plastic Food Container
Used with diffused plastic wrap to create sensor housings.
Fog machine

Necessary tools and machines

09507 01
Soldering iron (generic)
Table Saw

Apps and online services

About this project

NOTE: This is the 2016 edition of the laser maze.

View the 2019 version here.


It's Halloween night, and trick-or-treaters are walking through the neighborhood. Looking for something fun to do, they find a laser maze! In this competitive showdown, kids carefully navigate the laser beams while their parents plan their own strategy to win. One at a time, each person gets a chance to move through the maze without hitting any beams. If a beam gets hit, red flashing lights and an alarm signal that the game is over. If the person makes it to the end and hits the huge stop button, the win is accompanied by green flashing lights.


My original laser maze began in 2014, when I was just getting started with Arduino. The maze consisted of a single laser and multiple mirrors. While it was a fun experience, the many mirrors caused quite a bit of frustration. I knew I could improve, so I decided to replace the many mirrors with 15 laser modules. Each laser now corresponds to its own sensor, so any issue is now isolated much better. In addition to this improvement, the latest version features LED strips, DMX lighting, game-play music, sound effects, and Bluetooth control with the Arduino Manager app.

Pan/Tilt Brackets for Lasers

Each laser module is embedded into its own pan/tilt bracket. The brackets are made of scrap wood and contain three parts as seen in these pictures. The laser module is hot glued into the recessed hole and a barrel jack connection allows for easy setup.

Sensor Housings

In order for Arduino to detect when someone breaks a beam, photo-resistors are used to read the light intensity. Once the level drops below a certain threshold set by Arduino Manager, the fail sequence is triggered. Each of the 15 photo-resistors is hot glued within its own plastic container and covered with plastic wrap to diffuse the laser beam. Diffusing the laser beam once it reaches the sensor housing makes the aiming process much easier, because the beam does not have to be precisely focused on the photo-resistor.

Laser / Sensor Posts & Clusters

Each corner of the maze contains a wooden post with multiple lasers and sensors. The posts are cemented into buckets for stability. In addition to the 4 posts, lasers and sensors are fixed to the back, left, and right sides of the maze using pieces of wood. This creates even more possibilities for beam angles.

Wiring using Cat5 Cable

In order to make things easy, each post / cluster uses its own cat5 cable instead of having a separate cable for each sensor and laser. The pairs are color coded for each location, and all cables lead back to the central hub in the back of the garage. To save pins on Arduino, the sensors are divided into 4 groups and wired in series. The lasers are so bright when on, that even when multiple photo-resistors are wired in series, a broken beam can be easily detected.

Central Hub (aka mess of wires)

All of the cat5 cables feed to the central hub in the back of the garage. Since this project involves two shields (DMX and BLE) that compete for Arduino pins, two separate Arduinos are used, connected using I2C and the Wire library. Arduino Uno (master) uses the BLE shield to connect with Arduino Manager on an iPad. It also receives sensor data, controls laser status, reads button pushes, and sends messages to Arduino Pro Mini (slave). Since shields do not fit Arduino Pro Mini, each needed pin from the board is connected to the DMX shield with jumper wires. Arduino Uno sends lighting commands through the Wire Library, and Arduino Pro Mini receives them and fires the appropriate lighting cues via DMX. This project uses a large DMX LED wash light and LED strips for lighting.

Arduino Manager

An iPad controls the entire experience with Arduino Manager. The "LASER" button toggles laser visibility and enables game mode. The "aim" button can disable the the alarm and lights. S0-S3 are sensor values and T0-T3 are the respective thresholds, meaning if any of the sensor values goes below its threshold, the alarm and lights trigger. The threshold values can be changed on the fly from Arduino Manager. The "sound" icon represents the "sound" variable in the sketch. If any of the sensors go below their thresholds, sound = 1, and the alarm is played.

The iPad is also connected to a Bluetooth speaker which plays game music from Spotify. Check out my playlist here!

Click here for the full photo gallery!


Master (Arduino Uno)Arduino
Arduino Uno with BLE Shield processes sensor data, laser state, button state, and Arduino Manager.
/*2016 Halloween Laser Maze created by Sam Horne.
 * Note: This sketch is a work in progress and contains a few redundant variables and declarations.
 * While it worked correctly for the maze, I will definetely improve it in the future.

//#include <RBL_nRF8001.h>
//#include <SPI.h>
//#include <boards.h>
#include <IOSControllerBLE.h>  //Initialize Arduino Manager library.
#include <Wire.h>  //Initialize Wire library to connect both Arduinos.

#define LASERPIN      6     //Lasers connected with transistor to Digital pin6.
#define SENSOR0           0     //Four sensor groups, each containing photoresistors wired in series
#define SENSOR1           2
#define SENSOR2           1
#define SENSOR3           3

boolean laservalue;    //State of laser
int buttonPin = 2;     //Stop button
int buttonState = 0;
//Sensor variables.
int S0;
int S1;
int S2;
int S3;
//Threshold variables
int T0;
int T1;
int T2;
int T3;
int sound; //Variable controls audio widget in Arduino Manager
int aim;  //Allows lights and alarm to be disabled from Arduino Manager
int laserState;
int LASER = 0;
byte x = 0;  //For wire library transmission

IOSControllerBLE iosController(&doWork,&doSync,&processIncomingMessages,&processOutgoingMessages,&processAlarms,&deviceConnected,&deviceDisconnected);  //Necessary for Arduino Manager

void setup()

  pinMode(buttonPin , INPUT);  //Stop button
  pinMode(LASERPIN,OUTPUT);  //Laser
  pinMode(SENSOR0, INPUT);
  pinMode(SENSOR2, INPUT);
  pinMode(SENSOR3, INPUT);

  laservalue = 0;  /Set the laser value.
  digitalWrite(LASERPIN,laservalue);  //Set the laser value.

void loop() {  
  buttonState = digitalRead(buttonPin);
  if(buttonState == HIGH) {         //User presses stop button to win game.
    Wire.beginTransmission(9); //Begin transmitting on channel 9.
  Wire.write(9);  //Send a single byte (9) which triggers the win sequence on the Pro Mini.
    LASER = LOW;   //Laser turns off if someone wins.
    aim = HIGH;  //This prevents the alarm from sounding when the sensor values drop due to the inactive laser.
    iosController.writeMessage("aim", HIGH);  //Sync switch positions.
    digitalWrite(LASERPIN,LOW);  //Laser turns off if someone wins.
    iosController.writeMessage("laserState", LOW); //Sync switch positions.
  if (S0 < T0 && aim == 0)  {  //When sensor value drops below threshold and aim mode is not enabled.
    sound = 1;  //Sound the alarm
    x = 0; 
  Wire.write(0);  //Send value 0 to Pro Mini to trigger flashing red lights.
    digitalWrite(LASERPIN,LOW); //Turn the laser off.
  else if (S1 < T1 && aim == 0) {  //When sensor value drops below threshold and aim mode is not enabled.
    sound = 1;  //Sound the alarm
    x = 0;
  Wire.write(0);  //Send value 0 to Pro Mini to trigger flashing red lights.
    digitalWrite(LASERPIN,LOW); //Turn the laser off.
  else if (S2 < T2 && aim == 0) {  //When sensor value drops below threshold and aim mode is not enabled.
    sound = 1;  //Sound the alarm
    x = 0;
  Wire.write(0);  //Send value 0 to Pro Mini to trigger flashing red lights.
    digitalWrite(LASERPIN,LOW); //Turn the laser off.
  else if (S3 < T3 && aim == 0) {  //When sensor value drops below threshold and aim mode is not enabled.
    sound = 1;  //Sound the alarm
    x = 0;
  Wire.write(0);  //Send value 0 to Pro Mini to trigger flashing red lights.
    digitalWrite(LASERPIN,LOW); //Turn the laser off.
  else {
    sound = 0; //If no sensor events occur, no sound will happen.


void doWork() {
//Read the sensor group values from the analog pins.
  S1 = analogRead(SENSOR1);
  S2 = analogRead(SENSOR2);
  S3 = analogRead(SENSOR3);
  S0 = analogRead(SENSOR0);

void doSync (char *variable) {

void processIncomingMessages(char *variable, char *value) {

  if (strcmp(variable,"LASER")==0) { //Process incoming messages from Arduino Manager

    laservalue = atoi(value);
    laserState = atoi(value);

    digitalWrite(LASERPIN,laservalue);  //If LASER switch goes HIGH, turn on laser

  if (strcmp(variable,"T0")==0) {

    T0 = atoi(value);   
  if (strcmp(variable,"T1")==0) {

    T1 = atoi(value);   
  if (strcmp(variable,"T2")==0) {

    T2 = atoi(value);   
  if (strcmp(variable,"T3")==0) {

    T3 = atoi(value);   
  if (strcmp(variable,"aim")==0) {  //Sync aim value.
    aim = atoi(value);


void processOutgoingMessages() {

//Sync sensor values to Arduino Manager.
  iosController.writeMessage("sound", sound);
void deviceConnected () {

void deviceDisconnected () {


void processAlarms(char *alarm) {

  iosController.log("Alarm fired: ");


float getVoltage(int pin) {

  return (analogRead(pin) * .004882813);  // converting from a 0 to 1023 digital range
  // to 0 to 5 volts (each 1 reading equals ~ 5 millivolts
Slave (Arduino Pro Mini)Arduino
Arduino Pro Mini with DMX shield reads I2C commands from Arduino Uno and controls lighting devices.
This code is not essential to the project, and the project can function without the second Arduino (lighting).
#include <DmxSimple.h>

#include <Wire.h>
#include <wiring.h>
int DE = 2;  //DMX enable
int x = 0; //Wire transmission variable
int v = 15; // brightness value

void setup() {
  /* The most common pin for DMX output is pin 3, which DmxSimple
  ** uses by default. If you need to change that, do it here. */
  pinMode(DE, OUTPUT);
  digitalWrite(DE, HIGH); //DMX enable
  DmxSimple.write(1, 0);  //Startup scene
  DmxSimple.write(2, 0);
  DmxSimple.write(3, 0);
  DmxSimple.write(27, 10);


void receiveEvent(int bytes) {
  x =;    // read one character from the I2C

void loop() {
  if (x == 9) {  //Flashing green sequence
  DmxSimple.write(6, 0);
  DmxSimple.write(18, 0);
  DmxSimple.write(15, 0);
  DmxSimple.write(27, 0);
  DmxSimple.write(5, 255);
  DmxSimple.write(8, 255);
  DmxSimple.write(11, 255);
  DmxSimple.write(14, 255);
  DmxSimple.write(17, 255);
  DmxSimple.write(20, 255);
  DmxSimple.write(23, 255);
  DmxSimple.write(26, 255);
  DmxSimple.write(41, 255);
  DmxSimple.write(5, 0);
  DmxSimple.write(8, 0);
  DmxSimple.write(11, 0);
  DmxSimple.write(14, 0);
  DmxSimple.write(17, 0);
  DmxSimple.write(20, 0);
  DmxSimple.write(23, 0);
  DmxSimple.write(26, 0);
   DmxSimple.write(41, 0);
  if (x == 0) { //Flashing red sequence.
  DmxSimple.write(6, 0);
  DmxSimple.write(9, 0);
  DmxSimple.write(12, 0);
  DmxSimple.write(15, 0);
  DmxSimple.write(18, 0);
  DmxSimple.write(21, 0);
  DmxSimple.write(24, 0);
  DmxSimple.write(27, 0);
  DmxSimple.write(42, 0);
  DmxSimple.write(4, 255);
  DmxSimple.write(7, 255);
  DmxSimple.write(10, 255);
  DmxSimple.write(13, 255);
  DmxSimple.write(16, 255);
  DmxSimple.write(19, 255);
  DmxSimple.write(22, 255);
  DmxSimple.write(25, 255);
   DmxSimple.write(40, 255);
  DmxSimple.write(4, 0);
  DmxSimple.write(7, 0);
  DmxSimple.write(10, 0);
  DmxSimple.write(13, 0);
  DmxSimple.write(16, 0);
  DmxSimple.write(19, 0);
  DmxSimple.write(22, 0);
  DmxSimple.write(25, 0);
  DmxSimple.write(40, 0);


Note: Shields are not shown in this representation. BLE shield is stacked on Arduino Uno. DMX shield pins are connected to Arduino Pro Mini. Also, an LED is the placeholder for lasers. This image shows the series wiring of the photoresistors, even though they are not actually on the breadboard.
Screen shot 2017 01 14 at 12 u1k0uowtsg


Similar projects you might like

PIR Sensor Activated Halloween Scare Prank

Project tutorial by Kristian Blåsol

  • 27 respects

Fallout Doctor Halloween Costume

Project tutorial by Cameron Coward

  • 19 respects

Arduino Laser Tripwire

Project tutorial by Ian Cumming

  • 69 respects

WW2 Tank Laser Tag Sherman & Panther

Project tutorial by Arduino “having11” Guy

  • 1 comment
  • 64 respects

You Can't Creep up on This Creepy Cauldron!

Project tutorial by Barton Listick

  • 50 respects

Talking Raven - Animatronic for Halloween

Project showcase by pibyte

  • 29 respects
Add projectSign up / Login