#13: How To Make An Interactive Pop-up Book

Say you want to make a pop-up book that can react to the reader -- such as by projection mapping various different scenes onto the pop-ups. This was the initial premise behind Tome of the Seashore, a digital-physical children's book I made as a part of my capstone at Arizona State University. It's a fun idea, but almost nothing exists on the internet to really offer any guidance on such a project. Rather than let my research go to waste in some forsaken PDF, I figured I'd organize everything I've learned into a single article about building and programming just such a book.

Your welcome.

Use a Teensy

When you're considering putting electronic components into a book, it's absolutely crucial that everything remain small and flat. You can't use resistors because those are round and bulbous. You can't use a microcontroller with built-in headers because those stick out and create an uneven surface. For pretty much every component of the book, you have to find some way of making sure it doesn't push against anything or interfere with the natural functionality of the book.

You can save yourself a lot of trouble by skipping those problems and just using a Teensy. Because the digital ports on a Teensy all have built-in pull up resistors, you can actually set them to INPUT_PULLUP and save yourself the trouble of engineering a circuit with physical resistors. And, because they don't come with any headers, you can simply solder directly to the board.

Alternatively, you could use conductive thread to connect to the Teensy. In fact, seriously consider using conductive thread for this entire project. Solder is terrible at sticking to copper tape (which you'll want to use as much as possibly since it can lie flat) and it's never a joy to remove when you make a mistake. If you're like me and you like to think with your hands, the ability to easily undo and redo previous work is a must. Solder doesn't afford redoes well. Try to use conductive thread instead. 

Use Copper Tape

I love copper tape. It's flat, it's conductive, and it's cheap. Also, copper is just a nice color to look at. Even if nobody else is going to be looking at the guts of your project, you will – so pick something that inspires you to make something beautiful.

That being said, there are a few challenges inherent to using copper tape instead of wire for a circuit, all of which come down to the challenges of maintaining contact and adhesion.

Establish Contact

Sometimes you want two strips of copper to exist nearby but not form a complete circuit together. The solution to that is simple: don't let them touch. If they touch, there's a very strong chance they'll form a circuit. Obviously. However, the opposite is not necessarily true. Two strips of copper that come into contact with each other might form a connection, but they also might not. Copper tape is finicky in that regard. The only way to guarantee they will form a complete circuit is if you add a little bit of pressure to the contact point.

If the point of contact needs to remain constant, you can create that pressure by applying adhesive next to the copper tape and folding. Just make sure that you never put insulting adhesives between the two strips and check for continuity after you're done putting them together. Also, know that all adhesives add a slight amount of thickness that may be greater than the thickness of the copper tape. This is where the importance of testing really comes in. Always test on a small sample before applying to the larger project and do whatever you can to make sure the added thickness is less than the sum total of two copper strips.

If, however, you want the copper tape to move (such as on a slider), you'll have to get more creative. In the case of a slider, I recommend running the moving strip of copper through a snug paper loop which will help push a moving strip against a stationary copper lead, creating pressure. For added measure, place a small square of foam or felt behind the point of contact. 

Just please, for the love of all that is holy, check for continuity before moving on.

The Sticky Situation With Adhesion

This is one of the challenges that I was never able to fully crack for Tome of the Seashore. If you're thinking about making your own interactive book, this is something you'll have to research yourself. I can, however, offer some help and a little bit of guidance on specific types of adhesive which I used and researched for this project.

Solder

The most common and the most discussed method of connecting two conductive materials together. Technically you can solder to copper tape but the connection is flimsy and prone to just breaking off.

Conductive Paint

In my experience this is just as reliable as solder with twice the convenience and none of the risks. I even used it instead of solder on my Teensy and it worked like a charm! I was able to make a slightly longer lasting connection between the wire and copper tape, but it was still prone to randomly just disconnecting from the copper surface.

Conductive Adhesive

By which I mean copper tape with a conductive backing. I know it exists, but I have never used it. The rolls I ordered both turned out to have insulating adhesive, so tread carefully when ordering from Amazon. 

Double-Sided Tape

This is not conductive, but it needs to be discussed. I used a very specific type of double-sided tape – photo adhesive – and it is easily the most versatile material I used in the project. It's thin, it's flat, it has just the right amount of stickiness, and it comes in a convenient little tape dispenser that I basically took with me everywhere. Best of all, it hides behind the two things you're gluing together. It's a perfectly invisible adhesive!

Communicate Over Serial

I'll get to sensing which page is open and reporting user interaction in a moment, but first I want to talk about how that data should be reported to the computer.

Obviously you're going to use Serial. Sure, you could use TCP/IP or UDP if you really wanted to, but unless you're piping audio or video from your Teensy there's no point in going that complicated. A Teensy has a limited number of inputs and even if you report all of them at once, you'd have to be really determined to overflow a Serial buffer with that paltry amount of data.

The real question is how that data should be formatted. If all you're doing is reading which page is open then that's easy: just println the number of that page. No need to do anything fancy on either end of the port. If, however, you want to read when a pull tab is pulled or when a switch has been activated, you're going to have to decide which mode of delivery you prefer: all-at-once or one-at-a-time.

All At Once

Where every println contains a complete horizontal table of data. The advantage of this is that you don't have to tell the recipient of this data what each cell means. You hardcode that into the receiving software. If the book is open to page six and has three pull tabs all of which are pulled, you could just send a line like “6\t1\t1\t1\n” or “6 1 1 1” and all you'd have to do at the other end is split by “\t” or “ ”. As long as the recipient knows that cell[0] is the page number and cell[1-3] is pull tabs 1-3, you're good.

However, because you're civilized and would never do something as human unreadable as that, I recommend sending key-value pairs anyway. “Page=1 Pulltab1=1 Pulltab2=1 Pulltab3=1” is much easier on the debugging brain and all you're really doing on the other end is adding another function to split by “=”. If you have the space in your buffer, you really should use key-value pairs. They're more human readable and they're safer to change later on in the production.

One At A Time

For when you don't have room in the buffer. Other than that I have no idea why you'd do this. 

Loop Through Your Inputs

I like to change things often during production so it was important to me to have code that was easily extensible. That meant using functions and loops.

The following is the actual code I uploaded to the Teensy for the showcase, and you'll notice that it relies heavily on for-loops. Feel free to take what you want from it. I can't take credit for it anyways (that credit should go to Mike Krzyzaniak, who probably won't want it, and who spent a lot of time helping me traverse the heavily-typed and unsafe perils of the C language, for which I am eternally grateful).

First, the main file:

#include <stdio.h>
#include "data.h"

static const int pagePins[] = {2,3,4,5,6};

#define INPUT_SIZE 4
input inputPins[INPUT_SIZE] =  {{8, "Window"},
                                {9, "Door"},
                                {10, "Yarn"},
                                {11, "Key"}};

void setup() {
  // setup page pins
  for (int i=0; i<=sizeof(pagePins); i++) {
    pinMode(pagePins[i], INPUT_PULLUP);
  }

  // setup all other input pins
  for (int i=0; i<INPUT_SIZE; i++) {
    pinMode(inputPins[i].pin, INPUT_PULLUP);
  }

  // setup serial output
  Serial.begin(9600);
  while(!Serial) {
    // not necessary, but ensures safety
  }
  Serial.println("serial ready");
}

void readInputs(char * c) {
  // you could just as easily use Serial.print instead of strcat
  // and skip the need to pass a buffer through, in fact you 
  // probably should
  
  for (int i=0; i<INPUT_SIZE; i++) {
    strcat(c, "\t");
    strcat(c, inputPins[i].key);
    strcat(c, "=");
    if(!digitalRead(inputPins[i].pin)) {
      strcat(c, "1");
    }
    else {
      strcat(c, "0");
    }
  }
}

void loop() {
  //create buffer and then fill buffer
  char message[40] = "Page=5";
  readInputs(message);
  
  //print buffer over serial
  Serial.println(message);

  //chill the communication speed
  delay(500);
}

And then data.h:

typedef struct input_struct {
  int pin;
  const char * key;
}input;

Obviously looping through each input isn't going to be quite as fast and light as creating a series of if-else statements, but even the fastest speed reader isn't going to be capable of changing things fast enough for that overhead to actually get in the way and in my experience, the added safety is more than worth it.

Turn The Book Binding Into a Multistage Switch

I've heard a lot of ideas for how to read what page is open, all of which have their own unique flaws. You can decide for yourself which your prefer but I recommend you create a multistage switch.

Most popular by far is the idea of using a camera to read either a QR code or the number on the page. However, optical recognition software is still largely private and terrible. Developing good recognition software is a project in and of itself. On top of that, in order to read the book you'd have to add a camera with a persistent view of the book and a large pattern on each page which distracts from the actual content. Neither of those are ideal, so I recommend avoiding this option.

Another idea I heard was to use tilt sensors. This could work if you had two sensors per page and cycled through every page combo looking for whichever spread has two switches in different positions – if you think about it, all the other page spreads will have two sensors in the same exact position. There are a couple problems, however. Tilt sensors are round which makes them next to impossible to hide. In addition, they detect tilt in very narrow angles, meaning that a page would count as open even if it was only open by a few degrees. Depending on how slowly the user turns a page, you could end up projecting before there's anything to project onto – leading to a diminished user experience.

Instead, do what singing Hallmark cards have been doing for years: turn the binding into a switch. If you really want to be safe – which you do – make it a single switch with multiple stages. That way only one page can ever be reported as open at a time.

I go into detail on how I accomplished this while keeping all of the circuity hidden HERE and HERE, but the advantage of this system is that so long as you get the measurements right, only one page can ever be reported as open; the projections will never start before the book is set; and if you minimize the number of moving parts, you can create an incredibly reliable system that doesn't intrude on the user's experience of the book.

Final Words

That's the end of my advice. I could talk about projection systems and interaction paradigms, but I'm afraid what I have to say wouldn't be as useful. I just didn't spend enough time on those aspects of the project to gain any meaningful insights.

Well, there is one more thing: don't use anything based on Jitter to projection map onto the book. Use Unity or TouchDesigner or literally anything else with the ability to receive and interpret Serial data, because Max is not good at rescaling.

And that's it. Good luck on making your own pop-up book, and may the odds be ever in your favor.