Introduction: Arduino Interactive LED Coffee Table
I made an interactive coffee table that turns led lights on under an object, when the object is placed over the table. Only the leds that are under that object will light up. It does this by effectively using proximity sensors, and when the proximity sensor senses that an object is close enough, it will light up a node underneath that object. It also uses an Arduino to put on animations that don't need the proximity sensors, but add a really cool effect that I just love.
The proximity sensors are made up of photodiodes and IR emitters. The emitters use infrared light (which the human eye cannot see) to shine light up out of the table, and the photodiodes receive the infrared light reflected off an object. The more light that is reflected (the closer the object), the more the voltage fluctuates coming from the photodiodes. This is used as an indicator to tell which node to light up. The nodes are a collection of ws2812b leds and a proximity sensor.
The attached video goes over the entire build process, while I outline more of the details below.
- ws2812b LED Bulbs - https://amzn.to/370NCK7
- 5V Power Supply - https://amzn.to/36VDylP
- Any Arduino I used the 2560 - https://amzn.to/2GLqbdo
- IR Emitters
- 10 Ohms Resistors
- 1 MOhms Resistors
- 47 pF capacitors
- CD4051B Multiplexers
- SN74HC595 Shift Registers
- ULN2803A Darlington Arrays
- Any substrate to use as a large board for the leds, I used a paper composite board from home depot
Step 1: Create the Board and Insert the LEDs
The first thing I did was create the board which will contain the leds that we'll put inside the coffee table. I used a piece of paper composite board from home depot and cut it to the proper dimensions for the coffee table I had. After cutting the board to size, I drilled out all the holes for where the leds were going. The board itself had 8 rows and 12 columns of ws2812b leds separated 3 inches apart, and they were attached in a serpentine pattern. I used hot glue to secure them in place.
I also had to drill holes in the center of what will become the node: 4 ws2812b leds that make up a square, 2 photo diodes and 2 IR emitters in a smaller square in the center of that. These 4 holes in the center of the node would be the spots for the photodiodes and ir emitters (2 of each). I alternated them to ensure max exposure, and placed them about 1 inch apart in the center of each node. I didn't need to hot glue these into place, I just bent the leads on the other side to make sure they wouldn't come out the other side. I also made sure to bend the positive and negative ends in certain directions, so that they were oriented correctly in the circuit. All positive leads were on the left side of the back of the board, while all negative leads were on the right side of the board.
Step 2: Understand the Circuit
Note: All animated drawings are not exact to the implementation (some arduino pins are different, and I daisy chain a few, more on that later). The end result was a little bit different due to the complexity of the circuit, but all animated circuits serve as a great base to understand how to prototype each part. The regular schematic and circuit diagram are as it is on the PCB used in the project.
The PCB code which contains the KiCad project and gerber files can be found here: https://github.com/tmckay1/interactive_coffee_tabl..., in case you want to order the PCBs youself and create a similar project. I used NextPCB to create the boards.
There are basically three different circuits that make up this table. The first we will not go over in detail and is a simple circuit that powers the ws2812b leds. A PWM data signal is sent from the Arduino to the ws2812b led bulbs and controls what colors are shown where. We are using ws2812b leds since they are individually addressable, so we will be able to control which of the leds to turn on, and which to turn off. The ws2812b leds are powered by a 5V external power source, since the arduino alone does not have enough power to turn on all of the lights. In the animated diagram attached they use a pullup resistor of 330 Ohms, however I don't use that in my build.
The second circuit turns on the IR emitters. This circuit uses a shift register to control a darlington array which sends power to the IR emitters. A shift register is an integrated circuit that is able to send HIGH and LOW signals to multiple pins from only a small amount of pins. In our case we use a SN74HC595 shift register that is able to be controlled from 3 inputs, but controls up to 8 outputs. The benefit of using this with the arduino is that you can daisy chain up to 8 shift registers in a row (arduino can only handle up to 8 of them). This means that you only need 3 pins from the arduino to turn on and off 64 IR emitters. The darlington array enables you to power a device from an external source if the input signal is HIGH, or turn the power off for that device if the input signal is LOW. So in our example, we use a ULN2803A darlington array, which allows a 5V external power source to power on and off up to 8 of the IR emitters. We use a 10 Ohm resistor with the IR emitters in series to get maximum amperage from the IR emitters.
The third circuit uses a multiplexer to receive multiple inputs from the photodiodes, and sends the output in a data signal. A multiplexer is a device that is used to take multiple inputs you want to read from, and only needs a few pins to read from those inputs. It can also do the opposite (demultiplex), but we don't use it for that application here. So in our case we use a CD4051B multiplexer to take in up to 8 signals from the photodiodes, and we only need 3 inputs to read from those signals. Plus we can daisy chain up to 8 multiplexers (arduino can only handle up to 8 of them). This means the arduino can read from 64 of the photodiode signals from just 3 digital pins. The photodiodes are oriented reverse biased, which means that instead of oriented in the normal direction with the positive lead attached to the positive voltage source, we assign the negative lead to the positive voltage source. This effectively turns the photodiodes into photo resistors, which change in resistance depending on the amount of light that it receives. We then create a voltage divider to read a voltage dependent on the varying resistance of the photodiodes by adding a highly resistant 1 MOhms resistor to ground. This allows us to receive higher and lower voltages to the arduino dependent on how much IR light the photodiodes receive.
I followed most of this design from another person who did this here: https://www.instructables.com/Infrared-Proximity-S... In that design they also added a 47pF capacitor, as we do, across from the 1 MOhm resistor used to create the voltage divider with the photodiodes. The reason he added it was because he was fluctuating the IR emitters on and off with a PWM signal and doing this drew a small voltage drop from the photodiodes when the IR emitters were immediately turned on. This made the photo diodes change resistance even when it was not receiving more IR light from an object because the IR emitters shared the same 5V power source as the photodiodes. The capacitor was used to make sure there was not a voltage drop when the IR emitters were turned on and off. I originally planned to do this same strategy, but ran out of time to test it, so instead I left the IR emitters on always. I would like to change this in the future, but until I redesign the code and circuit, right now the PCB is designed to have the IR lights on at all times, and I kept the capacitors anyway. You shouldn't need the capacitor if you are using this PCB design, but I am going to introduce another version of the PCB that accepts an additional input to the shift register that will allow you to modulate the IR emitters on and off. This will save a lot on power consumption.
You can check the animated diagrams attached for a prototype setup for testing on your arduino. There is also a more detailed colored schematic for each circuit which outlines the setup and orientation of the electronic devices. In the attached PCB schematic, we have 4 total circuits, 2 circuits used to turn on the IR emitters, and 2 circuits to read from the photodiodes. They are oriented on the PCB 2 groups next to each other with a group consisting of 1 IR emitter circuit and 1 photodiode circuit, so that 2 columns of 8 nodes can be put into a single PCB. We also daisy chain the two circuits together, so three pins from the arduino can control the two shift registers, and 3 additional pins can control the two multiplexers on the board. There is an additional output header to be able to daisy chain to additional PCBs.
Here are a few resources that I followed for prototyping:
Step 3: Solder Wires to the Node
Now that you understand how the circuit is made, go ahead and solder the wires to each node. I soldered the photodiodes in parallel (yellow and gray wires) and the ir emitters in series (orange wire). I then soldered a longer yellow wire to the photodiodes in parallel that will be attached to the 5V power source, and a blue wire that will be attached to the photodiode input of the pcb. I soldered a long red wire to the IR emitter circuit that will be used to connect to the 5V power source and a black wire which will connect to the IR emitter input of the PCB. I actually made the wires a little to short ran out of time, so I could only connect 5 of the nodes in each column in the end (instead of 7). I plan on fixing this later.
Step 4: Solder the PCB Components and Attach It to the Board
Note: The PCB in the attached picture is the first version I made that lacked power inputs and outputs and also a daisy chain out for each inner circuit. The new PCB design corrects this mistake.
Here you just need to follow the PCB schematic to solder the components to the PCB and then once that is done, solder the PCB to the board. I used external circuit boards to attach the 5V power signal, which I distributed to all the yellow and red wires. In hindsight, I didn't need such long red and yellow wires and could have connected the nodes to each other (instead of connecting them to a common external circuit board). This will have really reduced the amount of clutter in the back of the board.
Since I had 8 rows of ws2812b leds and 12 columns, I ended up with 7 rows and 11 columns of nodes (77 nodes total). The idea is to use one side of the PCB for one column of nodes and the other side for the other column. So since I had 11 columns, I needed 6 PCBs (the last one only needing one group of components). Since I made the wires too short, I could only connect 55 nodes, 11 columns and 5 rows. You can see in the picture, I made a mistake and soldered the raw wires to the board, which would be fine if the wires were thin enough, but in my case they were too thick. This meant I had fraying wire ends very close to each other for each IR emitter input and photodiode input, so there was a lot of debugging happening from all the wire shorting. In the future I am going to use connectors to connect the PCB to the wires on the board to avoid shorts and clean things up.
Since the Arduino can only daisy chain up to 8 shift registers and multiplexers, I created two separate chains, one taking up the first 8 columns and another taking up the remaining 3 columns. I then attached each chain to another pcb that had just 2 multiplexers, so that I could read each chain of multiplexer data signals from those two multiplexers into the arduino. These two multiplexers were also daisy chained. That means that there was a total of 16 output signals and 2 analog inputs used in the arduino: 1 output signal to control the ws2812b leds, 3 output signals for the first chain of shift registers, 3 output signals for the first chain of multiplexers, 3 output signals for the second chain of shift registers, 3 output signals for the second chain of multiplexers, 3 output signals for the 2 multiplexers that aggregate each PCB data signal, and finally 2 analog inputs for each data signal from the 2 aggregate multiplexers.
Step 5: Review the Code
Note: In addition to the interactive code below, I used a 3rd party library to produce the animations for the ws2812b leds. You can find that here: https://github.com/atuline/FastLED-Demos
You can find the code I used here: https://github.com/tmckay1/coffee_table_arduino
At the top I define the arduino pins that will connect to each part of the PCB. In the setup method, I set the output pins for the multiplexers, turn on the IR emitters, set a baseVal array that keeps track of the ambient light reading for each photodiode, and initializes FastLED that will write to the ws2812b leds. In the loop method, we reset the list of leds that are assigned to be on in the ws2812b strip. Then we read values from the photodiodes in the multiplexer chains, and set the ws2812b leds on that are supposed to be on if the reading from the photodiode in the node is over a certain defined threshold from the base value of the ambient light readings. We then render the LEDs if there is any change in the node that should be on. Otherwise, it keeps looping until something changes to speed things up.
The code could probably be improved and I'm looking into doing this, but there is about a 1-2 second delay from when the lights turn on after an object is placed on the table. I believe the underlying issue is the FastLED takes some time to render the 96 leds on the table and the code has to loop through and read 77 inputs from the table. I attempted this code with 8 leds and found it to be almost instant, but am looking into the sweet spot of LEDs that will work with this code and be almost instant, as well as improve the code.
Step 6: Turn on the Arduino!
Now all you need to do is turn on the arduino and see the table function! Using the animations library previously mentioned you can put on some cool ws2812b led animations, or you can put on the coffee table code and see it light up in each section. Feel free to comment any questions or opinions, and I will try to get back to you in a timely manner. Cheers!