LaserComm is a communication device that uses Huffman encoding to transmit a message of 0s and 1s over a laser.

Step 1: Step 1: Coding Your Message

First of all, you need to choose and code a message to send over the laser. Watch this video on Huffman coding to learn how to condense your message into 0s and 1s.( advantage of Huffman coding is that the most commonly used characters use less bits(1s and 0s). Just remember to include spaces! The receiving end will get 1s and 0s, they will have to be decoded by hand with a key. The key will look something like E5R3G2H1K1_1, this gives the character and the number of times said character appears in the message. If you create a tree based on this type of key, there is only one way to decode the messgae of 1s and 0s.

Step 2: Step 2: Gather Supplies and Tools

To make this project you will need these supplies:

  • 2 Arduino Uno micro controller boards
  • 2 breadboards
  • 2 tripods (one should swivel)
  • 1 laser
  • 1 ping-pong ball
  • 1 photo resistor(light sensor)
  • 1 10KΩ resistor
  • 1 330Ω resistor
  • 1 transistor
  • Wires (plenty of them)
  • Pieces of ribbon cable
  • USB cable for Arduino

Now for the tools:

  • Hot glue gun
  • Soldering iron and wire
  • Wire snips

Step 3: Build Transmitting End

Solder some ribbon cable to the positive and negative terminals of the laser. Then hot glue the laser to the swiveling tripod. Attach the laser to your breadboard along with everything else in this diagram that I made. You should try it first without the transistor so you don't burn out your laser.(By the way, the resistor is a 330Ω)

Step 4: Step 4: Build Receiving End

Solder the photoresistor to some ribbon cable. This will make it easier to organize your wires. Use the diagram shown to organize the pin out of your circuit. I hot glued a ping pong ball to the photoresistor in order to disperse the light enough for the sensor to read and to make the target for the laser bigger. Glue the ping pong ball to the tripod, and you are set up. This end will be the end that attaches to a computer to gather readings from the serial ports on the Arduino.

Step 5: Step 5: Upload Code on Arduino IDE

If you do not already have the Arduino software go to to download it.

Code for transmitter:

// LaserComm
// Laser Communication Device // Corbin Newhard

int laserPin = 13;

String message = "HELLO WORLD";

byte l[] = {0, 0};

byte o[] = {0, 1, 0};

byte h[] = {0, 1, 1, 0};

byte e[] = {0, 1, 1, 1};

byte w[] = {1, 0, 0};

byte r[] = {1, 0, 1};

byte d[] = {1, 1, 0};

byte space[] = {1, 1, 1};

void setup(){


pinMode(laserPin, OUTPUT); }

void loop(){

for (int i = 0; i < message.length(); i++){



Serial.println(); }

delay(5000); }

void sendCode(char x){


case 'L' : for (int i = 0; i < sizeof(l); i++){ if (l[i] == 0){dot();} else{dash();} } break;

case 'O' : for (int i = 0; i < sizeof(o); i++){ if (o[i] == 0){dot();} else{dash();} } break;

case 'H' : for (int i = 0; i < sizeof(h); i++){ if (h[i] == 0){dot();} else{dash();} } break;

case 'E' : for (int i = 0; i < sizeof(e); i++){ if (e[i] == 0){dot();} else{dash();} } break;

case 'W' : for (int i = 0; i < sizeof(w); i++){ if (w[i] == 0){dot();} else{dash();} } break;

case 'R' : for (int i = 0; i < sizeof(r); i++){ if (r[i] == 0){dot();} else{dash();} } break;

case 'D' : for (int i = 0; i < sizeof(d); i++){ if (d[i] == 0){dot();} else{dash();} } break;

case ' ' : for (int i = 0; i < sizeof(space); i++){ if (space[i] == 0){dot();} else{dash();} } break; }


void dash()

{ Serial.print("-"); digitalWrite(laserPin, HIGH); delay(600);

digitalWrite(laserPin, LOW);



void dot()

{ Serial.print("."); digitalWrite(laserPin, HIGH); delay(200);

digitalWrite(laserPin, LOW);



(Replace and add your own letters and message)

Code for receiver:

const int sensorpin = 0;
boolean isStarted = false;

long lastTime = 0;

long duration = 0;

long darkTime = 0;

long darkDuration;

int threshold = 600;

long highPulse = 75;

long lowPulse = 10;

void setup() {



void loop() {

float light;

light = analogRead (sensorpin);


if (light < threshold && !isStarted) {

isStarted = true;

lastTime = millis();

darkDuration = millis() - darkTime;

if (darkDuration > 600) {

Serial.println ();



if (light >= threshold && isStarted) {

isStarted = false;

duration = millis() - lastTime;

darkTime = millis();

if (duration > highPulse) {

Serial.print ("1");


if (duration > lowPulse && duration <= highPulse) {

Serial.print ("0");


} }

Step 6: Testing

Set your two stations a few hundred yards from each other. Position the laser so that it visibly lights up the ping pong ball. once you see this, check the computer on the receiving end to see the ones and zeroes being displayed in the serial monitor. from there you can decode and read your message. Good luck and happy hacking!!!



    • Arduino Contest 2019

      Arduino Contest 2019
    • Tape Contest

      Tape Contest
    • Trash to Treasure

      Trash to Treasure

    3 Discussions


    3 years ago

    Huffman is very nice. I programmed it some 35 years ago in IBM/370 assembler. Later I found out that the zip programs use Huffman as well. There are different ways to create the Huffman tree. The easiest is to use a ready made tree that is optimized for a certain language where you know how often characters are used in average. So the 'e' will have only a few bits while the 'q' will have a long bit chain. The better is to read the text you want to encode and create a statistics of characters on which you build the tree. I put one on top and made a statistics on words (basically consecutive letters and numbers) and used a tree for words and "the rest". This was by far more effective but of course more computation intensive.

    2 replies

    Reply 3 years ago

    That is a great idea! The method I used was for specific messages and needs a key to decipher. For a more general communication, your method is perfect.


    Reply 3 years ago

    Actually what I did was to store the deciphering key in the analyzed file (which is AFAIK also what zip does). I guess if you plan a laser communication you should use a mix of the above. Start with a standard tree and analyze the data which flow. Then after some time you could use the new tree based on the analysis for the following communication. That means of course that you must transmit the tree to the other side. As this takes bandwidth you need some heuristics to tell you when to transmit (only if there is "substantial change" - how to detect that?) the new tree.

    Another thing to mention: if you have a bit flip it has more serious consequences than in uncompressed mode. Interestingly the but error will not completely ruin the transmission. After a few characters the stream will somehow catch up and continue with correct data. However, you would need some sophisticated recovery procedure.

    As a side note: your

    for (int i = 0; i < sizeof(d); i++){ if (d[i] == 0){dot();} else{dash();} } break;

    should better be written as a procedure. And the single

    byte d[] = {1, 1, 0};

    were better stored in an array of 256 bytes (if you are using just ascii and not unicode, which would make it overly complex).