My friend Sean and I spent the last year creating an interactive LED cube kit for the Raspberry Pi. We became good friends whilst studying at university, but this is the first thing we’ve worked on together. The result is the LumiCube: an enclosure for the Raspberry Pi covered in 192 individually programmable LEDs and packed with electronics, from a microphone and speaker, to a hand gesture sensor and orientation sensor. We also created a simple web-based interface so people can easily run their own Python scripts on it, or just choose from the built-in applications we include by default. We launched it last week on Kickstarter, and it’s been just amazing how many people have backed us!
We wrote quite a bit on the Kickstarter page about what you can do with the LumiCube, and why we think people will enjoy using it, but we didn’t go into very much detail about how it’s built, how the electronics work, and how we decided on the design. I thought this would be a great place to share this story, with the fantastic community over here at hackster.io.
ElectronicsOverview
The heart of the LumiCube is our Raspberry Pi hat. It sits right at the centre of everything. Even the Raspberry Pi itself is powered from the hat, for good reasons, which we’ll explain. The hat contains all the control logic and power distribution for the LED panels, as well as the speaker amplifier circuit and microphone. It also acts as a bridge to connect the Pi to all of our add-on modules, such as the screen module and environment sensor module.
Although a single LED only consumes a few dozen milliamps, when you put 192 of them together this easily adds up to several amps in total. Sending all this extra current through the Raspberry Pi itself is clearly not a good idea. We don’t want our users to have to plug in two separate power adapters into the cube, so the solution is to take power to the hat, and distribute it from there to the LEDs, to the Pi over the header pins, and to all of our other modules.
It’s also a nice place to add diodes and fuses for each separate power circuit. Then the Pi is protected in case an LED blows or the panel is connected incorrectly. To avoid confusion, we have covered the original Pi power connector, and also provided both micro B and USB-C sockets, so you can use whichever type of adapter you want with any type of Pi. Just be sure it can deliver at least 2.5 amps, if you want those LEDs to shine brightly!
Most of our modules are attached to the outside of the cube, such as the screen and buttons, and must be connected using cables. Some are just internal, such as the accelerometer and orientation sensor, and slide directly onto the hat using a 2mm header. The orientation sensor is based on the wonderful Bosch BNO055 chip, which is a combined digital accelerometer, gyroscope and compass. It includes some really clever algorithms supplied by Bosch, which “fuse” all of these readings together to provide a really accurate orientation output. Without this fusion stage, the gyroscope would drift over time, and the orientation would appear to rotate, even if it was completely stationary. Using the compass as a reference, the gyroscope can be calibrated and remains stable.
After much deliberation, we decided to use flexible flat cables (FFC) to connect our modules to the hat. Whilst most people are familiar with these cables, from opening up consumer electronics, but they’re not common within hobby electronics kits. The fine-pitch push connectors which mainstream manufacturers use can be fiddly, but we chose a wide-pitch cable and flip-lock connector, which is really easy to connect, and disconnect. The real advantage of FFC cables is in their name: their flexibility! They don’t fight you when you are assembling the project, are super light, and take up hardly any volume inside. It has been so much easier to assemble our prototypes using FFC cables than traditional wires. I believe they deserve much more love from the maker community! Another nice trick with FFC cables, is that you can mirror the signals around the middle of the cable. Then you don’t have to worry at all about the polarity of the connector, since it works both ways.
Cables are great, but routing cable to every module is a headache. That’s why we added pin headers to each of our modules, so they can just plug directly into each other. This saves on a number of cables from cluttering up the inside of the cube. We have plans to create more electronics kits in the future, all based on the same module system. Our idea is to make the modules generic, so they can be reused in future kits and projects. They all work together, are plug-and-play and all have a really simple interface. You can see the status of each module from our browser based dashboard, and control them all easily from Python without even having to install a driver or library.
The microphone and speaker talk to the Raspberry Pi over a protocol called I2S. Although it sounds like it might be related to I2C, it’s actually more similar to SPI. The nice thing about I2S is that the microphone and speaker can share the same clock pin on the Raspberry Pi, so only one SPI peripheral is needed to serve both, leaving the other SPI peripheral free to share between all of our add-on modules.
Finally we’ve added a fairly large cutout in the hat, above the Raspberry Pi’s CPU, so you can still install a heat-sink or fan if you want too!
Electrical bus
From the start, we knew we wanted to fit a lot into the LumiCube. Giving our users lots of electronics to play around with means they can be more creative, and can try out loads more ideas. But we also wanted to offer these features as an optional add-on, since not everyone would be able to afford, or want the full range. So we needed to design a properly modular system of plug-and-play electronic modules. Sounds like the job for a bus, but which one?
Naturally, our first thought was I2C. It’s popular and has been used for systems like this countless times before. But it wasn’t long before we started to encounter issues. The I2C standard itself is great, but lots of components don’t actually stick to the standard very well.
For a start, the Raspberry Pi has issues with I2C devices which require a bus pause, a phenomenon called “clock stretching” (see Mike Horne’s great post about this over at https://www.recantha.co.uk/blog/?p=19880). This issue makes everything seem unreliable, since it affects certain Pi models more than others, and limits the range of hardware we could support.
There are a few other practical issues with I2C: many components do not properly implement the part of the standard called “arbitration”, which in theory allows devices to raise notifications simultaneously without corrupting the bus. So once you start putting more and more devices on your I2C bus, the reliability starts to drop. Then, finally there’s that age-old issue of address conflicts. Combined, these issues left us searching for another solution.
Enter CAN bus! Several microcontrollers in the sub-$1 price range now feature fully compliant and integrated CAN peripherals. For those not familiar with CAN bus, it’s the most common bus for connecting the electronics together in cars: you probably trust it with your life several times a day, so it’s more than reliable enough for our needs! All of the issues we encountered with I2C just disappeared, hooray!
Although CAN is primarily designed for integrating electronics over long twisted-pairs of cables, there’s a really neat trick if you want to span just a few centimetres. It’s possible to just connect each microcontrollers’ CAN pins together using a diode, and voila! This works great for a small number of devices, so long as they are not talking too fast. If you want to communicate at the fastest speed, make sure you use a Schottky type diode with low capacitance, as they can toggle quickly. If you plan to connect more than a handful of devices together, you might want to replace the diode with an “open-drain driver” chip, as we have with the LumiCube. They can handle the higher current required, as well as being fast and low capacitance: treat yourself, they are only about two cents each!
With all of our modules hooked up to the bus, we just bridge them to Raspberry Pi over SPI using the well known MCP2515 CAN controller chip. Although it does the job, the current Linux kernel driver wasn’t quite able to support the bus at full speed. We’ve made some changes to the driver, which improved performance considerably: hopefully those changes will be accepted into the kernel over the next few months, so we don’t have to continue patching the kernel ourselves… but that’s perhaps a story for another time.
EnclosureOverview
The enclosure of the LumiCube is entirely made from laser cut acrylic. This is both easy to prototype with, and can be scaled up affordably when it come to manufacturing batches for our Kickstarter backers. If you can precisely control the parameters of your laser cutter then you can make laser cut cases which just clip together. We tried this idea, but it turns out there are a lot of variables you need to control in order to get satisfactory results every time. Even good quality sheet acrylic has about a ±10% tolerance in its thickness, which can make getting everything to fit closely a challenge. Instead we decided to use trusty old captive nylon nuts and screws (M3, in case you’re curious) to hold everything together. These work reliably, are durable, and don’t tend to work loose over time.
LED panels
The main challenge in designing the case was finding a good solution for mounting the LED panels. To produce a bright and sharp pixel, you need to diffuse the light emitted from the LEDs, but also prevent it spilling into the adjacent pixels. It turns out laser cutting is a great solution for making the grids of light boxes which serve this purpose. We tried loads of different depths and wall thicknesses until we settled on our current design. It does a good job at diffusion, without making the too big, or adding really wide borders around panels, spoiling that important cube-like effect. After placing dark tinted acrylic in front of the diffuser and grid, the exterior faces look almost black… until the LED is illuminated, and then voila! A beautiful, sharp and vibrant pixel.
Overview
We probably spent at least as much time developing the LumiCube’s software as we did on the hardware. The purpose of the LumiCube is to allow our users to be creative, so it is important to be able to see that state of all the sensors in realtime, and to try out new ideas in a matter of seconds. So we implemented a web-based dashboard, from which you can plot the output of any sensor on a graph, or write a short Python script and run it with a single click.
The web server runs on the Raspberry Pi, so all your data stays local, and it means you can tinker with the cube from your laptop or your phone, whichever is most convenient. We’re making all of our software open source too, so anyone can tinker with it, and adapt it to their needs.
Dashboard
The dashboard is written in React, and data is served from a Java based web server running on the Raspberry Pi. If you’re thinking Java... wasn’t expecting that! To be honest, neither were we. All of the Pi software for our first LumiCube prototypes was written in Python. But as we pushed the features of the LumiCube further and further, Python began to show its limitations, particularly at some of the lower-level tasks.
I’m sure we could have achieved the performance we needed using Python eventually, but Java gave us really great performance straight out of the box. It has a comparably rich let of libraries to Python, and with the new ZGC garbage collector, which promises sub-millisecond pause time, it’s a technology worth considering seriously for this kind of application.
The charts on our dashboard are powered by Chart.js, the code editor uses Ace, and the rest of the user-interface is built using React Bootstrap. All the necessary libraries are already integrated and automatically setup, so users can simply write their Python scripts in the editor, and press “Start”!
Comments