[bouLED] Adding Wifi

BouLed will be inside a plexiglas sphere, so there will be no button. The two ways of interacting with it are its orientation and a WiFi remote control, which I made with an ESP32 DevKit. It opens a access point and runs an HTTP server. You connect to it with your phone (or whichever WiFi-enabled device you like), select some parameters on a web page, and send them to the ESP32. Which in turn sends them to our main board via SPI. Naturally, there’s no noticeable latency.

However, I noticed something strange. The card doesn’t automatically boot in flash when powered on, while it should (according to Espressif) when GPIO0 is not grounded. I tried connecting it to Vcc instead of letting it floating, and it boots in flash. Same behaviour on other kevkits. Except for the brand new one soldered on our main PCB, fortunately.

Clever mistake

When Matthias was working with the simulation, he noticed the faces weren’t ordered correctly. The top 5 faces of the icosahedron, enumerated in clockwise order, would haves indices 0 1 2 4 3 in the array of matrices giving their position, instead of 0 1 2 3 4. Yet I could do all the pretty map projections without any issue, as my implementation didn’t rely on a particular ordering of the matrices. Here’s a pseudo-code version of the function that would compute these matrices :

mat4 face = some_correct_somputation();

mat4 rotation = some_rotation(2*pi/5);


for (int i = 0; i < 4; i++) {

faces.add(rotation * face);

rotation = rotation * rotation;

The purpose of this was to place one face, rotate it by 2*pi/5 around the correct axis and use this as the second face. Rotate the 2nd face by 2*pi/5 to get the 3rd one, etc… This is obviously not the behaviour of this code, as the rotation matrix is squared each time, instead of being rotated by 2*pi/5. But this actually computes the right matrices! Basic group theory in Z/5Z you’d say. Funny bug I say.

Finishing the firmware

For the different features of bouLED, we worked on different devboard, because we can’t all work on our only STM32H7 devboard. Git merge after git merge, we’re done making it all work on the same board.

Finishing the hardware

We soldered the LEDs on the triangular PCBs last week. That was not too painful thanks to our teachers and a pick and place machine.

The pick-and-place machine in action, x16 speed up

We’ll now start mounting the whole thing.

[bouLED] Drawing on bouLED

During the holidays, I worked (a bit) on displaying an image on bouLED. I first chose the simplest method that came to my mind: the equirectangular projection, used for world maps.

This is a very convenient representation because it’s simple. Storing a rectangular image in memory is straightforward. And, given the position of one LED as a height and an angle around the vertical axis, computing its color is easy: these two values are the actual latitude and longitude.


Computing this angle from the cartesian coordinates, however, involves a trigonometric function, atan2. This is probably the most expensive part of the computation. If we cannot avoid it, we should at least find an efficient implementation of it.

On the other hand, getting the cartesian coordinates of each LED is cheap. The faces of bouLED are flat, so you only need to make additions if you already have the position of the corners of the triangle.
As we chose an MCU with an FPU, using floating point numbers was a no-brainer.

Of course, the first thing I tried to display on the simulation was a world map. Here are the results:

The map is stabilized while the icosahedron rotates
Without the icosahedron rotating
Camera rotating around rotating bouLED

The simulation uses the exact same code as the MCU. On our 400MHz STM32H7, the function that takes a quaternion as argument and computes each LED’s color takes about 10ms to compute. This represents a very small yet sensible lag. The function can still be optimized, but we’ll need to add some smoothing/antialiasing.

Why are the LEDs so big on the gif ? Aren’t they smaller in reality ? Yes they are, but the result is far less convincing with small light points. That means we may need to “smoke” the plexiglass ball to discern the image.

Also, the equirectangular representation makes it easy to draw on the ball, but leads to some distortion. Matthias is currently working on another, possibly faster method.

We should very soon receive the PCBs. By that time, I’ll be playing with the WiFi module.

[bouLED] Done with the PCBs

We finished the PCB design this week (they are currently being reviewed by Alexis). The voltage regulator placed in the center of the triangular PCB had a few constraints, but routing the LEDs was simple enough so I could use the autorouting and just make a few modifications to it, like shortening the VCC paths and widening these traces.

The voltage regulator

We placed a few mounting holes, to screw the triangles on folded metal sheets keeping the icosahedron together.

The triangular PCB

By the time the PCBs are delivered, we’ll write as much software as possible. We’ll use our devkit to play with the ESP32 and some SD card reader, and, most important, we’ll write the display algorithm (we fortunately happen to have a simulation to help us).

[bouLED] Placing LEDs

This week, we did a few corrections and improvements on the schematics and started the the actual design of the PCBs.

We chose the plexiglass sphere for bouLED. Its internal diameter is 350mm so we took a margin and reduced the triangles’ sides to 179mm. This was enough information to place the LEDs. Having done the triangle design with OpenScad revealed helpful to check the placing as I imported a DXF version of it in Mentor’s software, as Alexis suggested. I was also happy that we chose a rather regular LED repartition,  so I could use grids instead of manually copying 78 coordinates.

The triangle PCB in Xpedition PCB

For the routing, however, we’ll need to know the positions of the screw holes in the PCB. Hichem is currently working on that, designing the pieces with SolidWorks. (I started doing it with FreeCAD but the SolidWorks lobby had the last word.)

This will be a 2-layer PCB, with a ground plane on the bottom. The voltage regulator will go on the back side of the PCB, with the jumpers.

[bouLED] Triangles’ circuit diagrams

The electrical design of the faces is almost done. The triangles were first thought to be the equivalent of the LED strips:

78 APA102C

But then we chose to put one 14.8 to 5V regulator on each face:

The buck regulator

Add a few connectors and that’s all there is to these PCBs.

In addition to not being decided about the internal structure of bouLed, we also need to choose the enclosing transparent sphere. This constitutes an important size constraint, and we might have to reduce bouLED’s size by a few millimeters to fit it. More on that soon.

[bouLED] Physical structure

Hichem got the MARG working last week-end, so we tested it with our simulation (see his post) and confirmed this model would suit us and go on our central PCB. With this and the voltage regulators chosen, we have almost all we need to design the PCBs. The triangular ones may be simpler to design, but before we want to know precisely the physical structure of bouLED.

For ease of conception and of battery management, it should be possible to open the icosahedron. One way to do it is to make five faces removable, as shown on this simple model.

Made with Tinkercad

The inner armature would support the electronics and the LiPos, ideally keeping the MARG in the center of the icosahedron. Thus the stick supporting the removable part should be moved, and probably replaced with something stronger. The faces would be connected to the central part with JST-like connectors, easy to plug and unplug.

We want to chain the triangles without using too long wires, and we want a removable part. This will dictate how we’ll position each face and how we’ll place the connectors on it, while keeping all triangular PCBs identical. The LED repartition we think we’ll use surely is even enough not to be considered when choosing the face’s orientations.

[bouLED] Update on power consumption

Following the suggestions of the teachers, we measured the maximum power consumption of the LEDs again. We may have misused the power generator the first time, or didn’t set the LEDs at full brightness. Anyway, under rigorous measurements, our first triangle of 133 LEDs uses 4.5A under 5V. This is at a blinding brightness, nevertheless this is a huge power if you have 20 triangles and we’re thinking about how to provide it.

After finishing the 3D visualization (though it’s not merged on master yet and one could argue it’s therefore not finished), I joined Hichem on his work with the MARG. We want it working ASAP, so we can be sure we’ll use this chip, and we can start designing the PCBs. We spent some time today debugging his code. We suspect the I2C timings are the reason why we couldn’t get an acknowledge from the MARG, and we hope to solve it tomorrow.

[bouLED] A pretty triangle and a pretty simulator

Last week we finally printed a triangle of the right size (see Hichem’s post). Hichem cut the led strip into smaller ones, and I re-soldered them to fit the triangle, which was not hard but took some time.

92 welding points

For the final object, we won’t have to solder 20 times as many LEDs. We’ll just put individual LEDs on triangular PCBs -we just started drawing the circuit diagrams. The point of this first triangle is to be able to display stabilized animations before all the PCBs are built.

I also worked on the 3D visualisation. Matthias had re-written the first one with PyQtGraph, because VTK didn’t suit him. But this new one had terrible performance: computing the new LED positions every frame made the framerate drop to around 1fps. Therefore, we had to write another simulator. This time, no more compromises, no more Python, just C++, OpenGL and sweat. Matthias set up the OpenGL context and let me have fun with matrices, geometry, textures and instancing. It’s not quite finished yet (not to mention glitches), but we can dynamically color each LED, rotate the model by feeding the simulator quaternions via stdin, and still get 300 fps on integrated graphics.

Virtual bouLED

When it’s done, we’ll be able to display images on it, and get an idea of the final result. However we haven’t decided yet how we’ll store and project images on the icosahedron. We’re also unsure if displaying text is possible with our relatively low resolution.

[bouLED] More on the LED strip

Yesterday I stopped making knots with the wires: I soldered them to the LED strip on one end, and put pins on the other.

Before / After

The issues I had to control the last LEDs of the strip were actually due to the APA102 datasheet being wrong, in addition to being poorly translated from Chinese into English. The “end frame” of the SPI message it described was indeed required, to supply more clock signals than the length of the payload. But not enough if you have a hundred LEDs, as explained on this very informative blog. The data signal being delayed by half of clock cycle by each LED, the length of the end frame should be proportional to the number of LEDs.

Then there’s the brightness setting, 5 bits on each LED frame, which everyone agrees to set to 0b11111 and forget about.

It turns green on the 100th time

We should soon have a 3D printed triangle that fits the LEDs (see my friends’ posts). The LEDs shall then be rearranged: we’ll cut the ribbon into smaller ones and re-solder them. Then we’ll look at the signal coming out on the end of the ribbon and see if we can put another one in series.

To build the 19 other faces, we might need a few more LED strips. We did some measurements, and one 5V LED strip consumes a bit more more than 1A. Until now our test card could supply enough power when using a reasonable brightness, but with more than 15 times as many LEDs, we’re looking at big batteries for bouLED to be autonomous.

[bouLED] Turning LEDs on

As we want to use led strips for bouLED, trying to turn these LEDs on with our microcontroller would be a good start.

Our STM32L475 luckily happened to have SPI controllers. I used one in the frequency range recommended in the APA102 LED strip datatsheet, that is around 1MHz, to display simple animations on the ribbon. After some playing with the wires and some endianness considerations, I could control almost all of the 133 LEDs (and I’m investigating why some won’t obey). 
Thanks to ChibiOS, the current implementation already makes use of the DMA, so that SPI transactions don’t take up much CPU time.

The next step will be to see if we can increase the frequency. Then we’ll need to consider more LED strips: the SPI controllers can only send data on a few GPIOs, while we might need to plug 20 LED strips (or less if we can put some in series).