Overview

The Freefall Deck

The setup: You're running an escape room, or a magic trick, or a uniquely themed Wild West baby shower. You've cast your participants/game players/soccer moms & dads as Old West gamblers.

The puzzle: A clue leads them to a sealed deck of poker cards and two rules to follow: 

  1. Unless otherwise instructed, hang on to this deck of cards -- in time it'll deliver an important message.
  2. Should the dealer suspect you've marked the cards, there's gonna be trouble, so keep it sealed and pristine!

The payoff: Later, the players/gamblers find a new clue that instructs them to "toss the deck to hear the key". Being highly clever, they try literally throwing the deck into the air and -- BEHOLD! -- when the deck reaches a state of freefall, the distinctive beeping "dits" and "dahs" of a Morse code message begin to emanate from within the pack of cards. They catch the deck and begin to transcribe the message, an important solution to the puzzle.

Thus is unlocked the mystery of The Freefall Deck!

Parts and Materials

The Circuit Playground is a powerful, compact, and capable device, making it ideal for building magic tricks, mystery boxes for escape rooms, and other wondrous effect. We'll use its built in accelerometer to detect the state of freefall and its on-board speaker to send the Morse code message.

We'll also use a small battery, a deck of Bicycle playing cards, and some wood, cardboard, or acrylic to make the cutout deck insert to hold the electronics inside the card box. Some hot glue will allow us to reseal the box and wrapper.

Optionally, you can use a small scale and calipers to precisely match the weight and thickness of the original cards. This is probably bonkers.

Sneakily Opening the Box

Part of the effectiveness of this gag is because the deck of cards appears completely standard and unopened, therefore it's surprising to have it react to being tossed or dropped and to hear sounds coming from within it!

To pull this off we need to get into the deck without ruining the cellophane or the seal on the box. We'll also need to match the feel of the deck -- it should weigh and feel the same as normal cards. Finally, we must re-seal the box and cellophane.

Unsealing the Cards

To unseal the deck we'll first use a small knife or thin piece of metal such as a feeler gauge to slide open the folded cellophane at the bottom of the deck. Go slowly to avoid tearing the thin plastic -- you want to pry and lift more than cut.

Next, carefully slice through the glue that holds the bottom flap of the cardboard box. Avoid bending the cardboard -- a sure sign of tampering!

Remove the existing cards and set them aside. You'll save a few to place back in the box in order to fill out the thickness properly, the rest you can potentially use in setting up a different puzzle.

Next, we'll set up the electronics by programming the Circuit Playground.

Coding Circuit Playground

Prep the Circuit Playground

Before you get started, make sure you've been through the basic tutorials on using the Circuit Playground. You'll need to have installed the Arduino IDE, added the Circuit Playground board to Arduino, and added the Circuit Playground library. This excellent guide, Introducing Circuit Playground and Circuit Playground lesson #0 will show you how to do all of that and get you going.

If you are using the Circuit Playground Express, be sure to check out the next page of the guide to see how to program the Freefall Deck using MakeCode

Plug your Circuit Playground into your computer now, and launch the Arduino IDE. Double check that you've selected the board and port as in the Lesson #0 tutorial and are ready to upload code.

Freefall Deck Logic

The Freefall Deck sketch is quite simple, it can only do two things: check the state of it's accelerometer, and beep a pre-coded Morse message when the accelerometer reaches a state of freefall.

 

Download: file
//Circuit Playground Freefall Deck
//created by John Park for Adafruit Industries
//a sealed deck of cards is tossed in the air or dropped, at which point it reveals a Morse code message
//Freefall detection by Phil Burgess
//Morse table by Usman Muzaffar
////////////////////////////////////////
#include "Adafruit_CircuitPlayground.h"

volatile boolean interruptHappened = false;
//*******************************************************//
//Morse code playback variables
//Adjust PITCH to your liking and DOT for speed faster/slower 
const int PITCH = 600; // Morse code audio is sent at 600-800 Hz. 680 is quite nice
const int DOT = 200;   //time duration in millis, change this to adjust transmission speed

const int DASH = 3 * DOT; //Morse standard dash is 3x longer than dot
const int GAP = DOT; //Morse inter-element gap within a character is same length as dot
const int INTER_LETTER = 3 * DOT; //Morse short gap between letters is 3x dot length
const int INTER_WORD = 7 * DOT; //Morse medium gap between words is 7x dot length
//*******************************************************//
void setup() {

  CircuitPlayground.begin();
  CircuitPlayground.strip.clear();
  CircuitPlayground.strip.show();

  // Bypass library and brute-force LIS3DH registers for freefall detect.
  // From ST App Note AN3308 w/changes to threshold & duration.
  writeReg8(LIS3DH_REG_CTRL1  , 0xA7); // Sensor on, enable X,Y,Z, 100 Hz
  writeReg8(LIS3DH_REG_CTRL2  , 0x00); // Disable high-pass filter
  writeReg8(LIS3DH_REG_CTRL3  , 0x40); // Enable I1_INT1 interrupt gen
  writeReg8(LIS3DH_REG_CTRL4  , 0x00); // 2G
  writeReg8(LIS3DH_REG_CTRL5  , 0x00); // Interrupt not latched
  writeReg8(LIS3DH_REG_INT1THS, 0x0A); // ~160 mG threshold
  writeReg8(LIS3DH_REG_INT1DUR, 0xFF); // Duration
  writeReg8(LIS3DH_REG_INT1CFG, 0x95); // Configure free-fall recognition

  pinMode(7, INPUT_PULLUP); // LIS3DH INT1 is connected to D7
  attachInterrupt(digitalPinToInterrupt(7), interruptHandler, FALLING);
}

void writeReg8(uint8_t reg, uint8_t value) {
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  digitalWrite(CPLAY_LIS3DH_CS, LOW);
  SPI.transfer(reg & 0x7F);
  SPI.transfer(value);
  digitalWrite(CPLAY_LIS3DH_CS, HIGH);
  SPI.endTransaction();
}

void interruptHandler() {
  interruptHappened = true;
}

void loop() {
  if (interruptHappened) { //Accelerometer has detected free fall, do something here
    //*******************************************************//
    //Place your message here.
    //Each letter or number on one line.
    //Spaces between words are denoted with a slash / symbol.
    //Only use A-Z 0-9 
    //Other characters will cause trouble!
    
    playMorseLetter('/');//good to have a slight delay at the beginning
    
    playMorseLetter('O');
    playMorseLetter('N');
    playMorseLetter('/');
    playMorseLetter('P'); 
    playMorseLetter('A');
    playMorseLetter('G'); 
    playMorseLetter('E');
    playMorseLetter('/'); 
    playMorseLetter('X');

    //*******************************************************//
    interruptHappened = false;
  }
}

void playMorseLetter(char letter) {
  // Morse table by Usman Muzaffar
  // Adapted from: http://stackoverflow.com/a/28058216
  // Define two tables of strings one for letters and one for numbers,
  // that return the Morse encoding. By using two separate tables, we
  // can just offset the ASCII value of either a number or letter as
  // the index to look up the Morse encoding.
  static const char *ALPHA_TABLE[] = {
    ".-",   //A
    "-...", //B
    "-.-.", //C
    "-..",  //D
    ".",    //E
    "..-.", //F
    "--.",  //G
    "....", //H
    "..",   //I
    ".---", //J
    "-.-",  //K
    ".-..", //L
    "--",   //M
    "-.",   //N
    "---",  //O
    ".--.", //P
    "--.-", //Q
    ".-.",  //R
    "...",  //S
    "-",    //T
    "..-",  //U
    "...-", //V
    ".--",  //W
    "-..-", //X
    "-.--", //Y
    "--..", //Z
  };
  static const char *NUM_TABLE[] = {
    "-----", //0
    ".----", //1
    "..---", //2
    "...--", //3
    "....-", //4
    ".....", //5
    "-....", //6
    "--...", //7
    "---..", //8
    "----.", //9
  };
    if(letter == '/'){// use "/" as space between words
        delay(INTER_WORD);
        return;
    }

    // Look up the morseCode string for this letter
    // by finding the right table.

    char* morseCode;
    if (isalpha(letter)) {
        morseCode = ALPHA_TABLE[letter - 'A'];
    } else {
        morseCode = NUM_TABLE[letter - '0'];
    }

    for (int i = 0; i < strlen(morseCode); i++){
        int duration = morseCode[i] == '-' ? DASH : DOT;
        CircuitPlayground.playTone(PITCH, duration);
        delay(GAP);
    }
    delay(INTER_LETTER);
}

Download the Code

You can click "Copy Code" in the code above, then paste it into a new sketch in Arduino. Save the file as CircuitPlaygroundFreefallDeck.ino in your Arduino sketch directory, then upload it to your Circuit Playground.

To test it out, drop the powered Circuit Playground from one hand to another. Thanks to the physics and programming prowess of our own Phil Burgess, the Circuit Playground will detect a state of freefall and begin beeping the coded message.

Adjust the Code

If you'd like to change the message, look for this section in the code:

Download: file
    //*******************************************************//
    //Place your message here.
    //Each letter or number on one line.
    //Spaces between words are denoted with a slash / symbol.
    //Only use A-Z 0-9 
    //Other characters will cause trouble!
    
    playMorseLetter('/');//good to have a slight delay at the beginning
    
    playMorseLetter('O');
    playMorseLetter('N');
    playMorseLetter('/');
    playMorseLetter('P'); 
    playMorseLetter('A');
    playMorseLetter('G'); 
    playMorseLetter('E');
    playMorseLetter('/'); 
    playMorseLetter('X');

    //*******************************************************//
    

Place any message you like by replacing the letters in the single quotes on each line with letters A-Z or numbers 0-9. Use a slash / symbol to represent the spaces between words.

Morse code follows conventions on timing for the lengths of dots and dashes, spaces between elements, spaces between letters, and spaces between words. These are represented in the code above.

It's a good idea to keep your messages short and easy to transcribe. One thing you may want to adjust is the speed of the message transmission. Do this by changing the variable DOT in the code. It is currently set to 200 milliseconds, a fairly moderate rate, but you can certainly increase that number to slow things down further.

MakeCode for Circuit Playground Express

MakeCode works with the Circuit Playground Express. If you have the original Circuit Playground Classic, check out the Arduino version of this code on the previous page

Lots of Coding Options

There are many options for programming the Circuit Playground Express! You can hand-code it with the traditional, text-based Arduino IDE, as seen in the previous page of this guid, you can try your hand at the exciting new CircuitPython methods, or you can harness the incredibly user-friendly, yet powerful block-based interface of Microsoft's MakeCode web app!! (You can even go full circle and hand type code inside the MakeCode interface with Javascript!)

By simply dragging and dropping elemental code blocks, you can create Circuit Playground Express software in no time, and even test it out with the virtual Circuit Playground Express simulator built into the page.

Be sure you've gone through the tutorial here on the basics of MakeCode for Circuit Playground Express. 

MakeCode

You're now ready to begin coding your own program with the MakeCode interface to use the Circuit Playground Express as a Freefall Deck.

Click the Projects button so you can start a new project, then click the New Project... button to create a fresh, clean project.

Input

Your Freefall Deck will give up its secret Morse code message only after its accelerometer has detected a free fall. To do this, you'll create an input that check the accelerometer for free fall, and then plays the appropriate tones.

The first block you'll add is is an input block that can read the accelerometer on the Circuit Playground Express. Click on the Input category and choose the on shake block, then drag it to the canvas. (All of the accelerometer-based inputs are contained within this one block.)

Click on the shake dropdown, and select the free fall option from the list.

Freefall Test

You can test the free fall by adding a play tone block to the on free fall input.

Click the music category and drag the play tone at Middle C for 1/2 beat block into the on free fall block.

Upload this code to your Circuit Playground Express by downloading the file, pressing the reset button on the Circuit Playground Express to enter bootloader mode, and dragging the file to the CPLAYBOOT drive.

Now, drop your Circuit Playground Express from one hand to the other and it will play a tone!

Morse Code Setup

Next, you'll make blocks to play Morse code dots and dashes. These will be represented in the play tone blocks as frequencies, instead of music notes, and as timings in milliseconds, instead of musical note durations.

Morse code follows conventions on timing for the lengths of dots and dashes, spaces between elements, spaces between letters, and spaces between words. 

You can set up all of the timing in variables in a setup loop, and then use these variables throughout the your on free fall code block.

From the loops category, get an on start block.

Variables

You can declare your variables, and assign to them values using the set item to 0 block. Go ahead and get one of these from the variables category, and place it in the on start block.

Since you'll be using the variable block on its own as well, drag a copy of the item variable to your work space as well.

Let's use the first variable to set the pitch of the tone you'll play. Audible Morse code is usually between 600 and 800 Hz. Click on the dropdown in the set item to 0 block, and choose the Rename variable... item.

In the rename popup window, type in the name PITCH, then press 'Ok'. This will rename all instances of the variable item used in your code.

Change the value to 680, which will be the frequency of the tone.

Now, you can drag the PITCH variable block into the play tone block to replace the Middle C that's currently there.

Repeat the same process as above to create a variable for the duration of a Morse code dot, which is 200 milliseconds. The steps are:

  • Drag a set item to 0 block from the variable category
  • Rename item to DOT
  • Change the DOT variable value to 200

Place the new variable declaration into the on start block.

Drag a copy of the DOT block out of the variables category and onto 1/2 beat value that's currently in your play tone block

Download the .uf2 code and upload it to your Circuit Playground Express to test it out. You'll now hear a single dot tone play upon freefall.

There isn't a way currently to trigger the 'free fall' input in the simulator, so you can switch the block to read 'shake' temporarily while testing (a 'shake' button appears over the board graphic). Just remember to switch it back to 'free fall' before moving the code to your Circuit Playground Express!

Repeat the same steps as above to define the rest of the Morse code timing variables as seen here.

Note how most of the values are defined as multiples of the dot value. This is how Morse code is defined, so you can adjust the pitch and duration of the DOT and everything else will update accordingly!

Using Morse Code

Morse code uses different length pauses between the dots (short tones) and dashes (long tones) to indicate separation between characters (short pause), letters (medium pause), and words (long pause). 

To create the letter A, which is .-  or "dot dash", we need to use a play tone at PITCH for DOT, followed by a short gap pause, and then a play tone at PITCH for DASH block.

For the gap pause, get a pause (ms) 100 block from the loops category.

Next, get a copy of the GAP variable from the variables category, and drag it onto the pause (ms) value.

To complete the .- you can duplicate the play tone block, place it under the pause block, and change the duration with the dropdown from DOT to DASH.

Creating Messages

You've now created all the blocks you need to make your Morse code messages! Here's an example of SOS, or ... --- ... created by duplicating blocks and adjusting their variables from the dropdown menus:

We've also added a half second delay before the tone plays, so the to give the listener a moment.

Now, you can make up your own messages, and they will be revealed when the Freefall Deck falls! You can use this handy chart as a reference for the letters and numbers of international Morse code.

Assembling the Deck

Building the Card Insert

Remove the Circuit Playground from the USB cable and plug in the lipo battery. You can wrap it in some tissue paper or foam, and slip it back into the deck with a few cards in front and back -- this will work just fine. However! The weight and feel will be pretty suspicious. Too light, and too squishy!

So, instead, I recommend cutting out some card stock or cardboard to accommodate the electronics, similar to a hollowed out book. Or, you can take some thin plywood to the bandsaw or scrollsaw or a hand coping saw to create a similar insert.

I designed an insert to be cut from 3mm acrylic on the laser cutter. You can download the file and use it on a laser cutter, mill, or even print out on an inkjet or laser printer as a template for cutting cardboard or other materials.

Measured with calipers, the thickness of these five layers comes up just shy of a regular deck of cards, so I shimmed it by adding eight cards to the insert, four on top and four on the bottom.

The additional cards also bring the weight up to nearly identical between the "gimmicked" deck and that of a regular deck of cards.

Re-Sealing the Box

You'll now reverse the process. When you're ready to use the Freefall Deck (you'll have plenty of battery life, so this can be set up hours before needed) insert the electronics, insert, and any extra cards for padding into the box.

Now, you can use a thin bead of hot glue to close the cardboard flap, and then do the same for the cellophane.

You'll want to use a very light touch with the glue -- big blobs of hot glue are a sure giveaway. You can also try super glue if you like. Should you need to, you can take off the wrapper from another deck of cards to replace the original, just use the same careful opening methods as before.

Next, take the Freefall Deck for a spin.

Using the Freefall Deck

The deck is fairly immune to inspection -- and it doesn't tend to trigger from being handled, only from a toss in the air or a drop. Try throwing and catching it, dropping it from one hand to another, or letting it go a short distance above a table or other surface.

A gambler's poker cards are just one example of how to theme this effect. If you like, you can use the gag inside any kind of object you like -- a sealed wooden box, inside a stuffed animal, hidden in the heel of a boot -- you can get creative with it!

This guide was first published on Jan 15, 2017. It was last updated on Jan 15, 2017.