[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] 3D printing

After we made a model of our icosahedron’s one equilateral triangle using openscad. This is the first time I used 3D printer. After two hours, the first print has finished.

The first version

As you can see, the main issue was the led strip can not fit within holes because widening holes I didn’t change the spacing’s dimension between two LEDs and two rows. So the alignment doesn’t match with our LED strip. I fixed it and I tried a new print. After two other hours, the second version is here.

The second version

The alignment is more appropriate, but it’s still not perfect. The reason remains to be determined I think we should to have more accurate data (below millimeter) and if it’s possible with 3D printer available. Tomorrow I will fix and retry another 3D printed triangle.

[bouLED] Simulation, math and component choice

Towards a blinky simulator

It’d be convenient if the simulator allowed us to test the projection algorithm. To do this, there should be coloured spheres “stuck” to the facets of the icosahedron, arranged much like the holes in my last post‘s triangle. I haven’t written the sphere layout algorithm yet, but as a proof-of-concept, I put a sphere above the icosahedron and made it orbit the icosahedron when it is rotated. It is done by rotating its position vector using the incoming quaternion. Once all LEDoids are created, for each input quaternion, the software will have to loop through all the spheres and make them rotate around the icosahedron, so that they appear not to move in its frame of reference.

That’s a scene graph: the LEDs are children of the icosahedron, and making the icosahedron rotate makes the LEDs rotate. PyQtGraph doesn’t include scene graph handling, but this is a pretty simple one, so doing it manually will probably be less hassle than picking another library for this (VisPy, for instance).

In the end, the simulated projection algorithm should be able to change the spheres’ colours: this will allow us to test it.

First ideas for a projection algorithm

There is one physical icosahedron, and a virtual, stable icosahedric image, that we’ll call V. To find what facet of V a LED is in, rotate the LED’s position vector using the quaternions from the sensor fusion algorithm, normalize it and find the facet of V whose normalized normal (rolls off the tongue, huh ?) vector has the highest cross-product with our normalized LED position vector.

Once the facet of V is known remains the task of finding the right colour, but I haven’t given it too much thought yet. Finding this triangle for each of the 2000+ LEDs is going to be really computationally expensive, so perhaps we could do some kind of dichotomy algorithm, using a first dot product to find which hemisphere we’re interested in.

MCU choice

So far, we’d like to use a STM32F7 MCU, especially for its FPU and L1 cache (16KB+16KB for instructions and cache in STM32F7x8/9 MCUs !). A specific STM32F7 MCU has not been chosen yet.

[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] Visualization shenanigans and 3D modeling

A new simulator

I was trying to replace the cube in Lucas’ simulator (see here) by an icosahedron and add some kind of clue of the icosahedron’s orientation, but the Python 3D library we used, VTK, was getting on my nerves. Adding an icosahedron worked fine, but I wasn’t able to change its colors, and what’s worse, even when using the default colours (blue everywhere), one of the model’s facets stayed red, which was pretty jarring. I also added an axes widget that was supposed to rotate with the icosahedron, but to no avail: it wouldn’t rotate. One of us had to go, and it wasn’t going to be me.

Alexis sent us a script 11 days ago that displayed a colorful icosahedron with PyQtGraph, which provides a light abstraction over OpenGL. It made a nice starting point for a new simulator, with a rotating icosahedron, a fixed grid and axes. Behold !

Granted, it’s still ugly, but it works and PyQtGraph is way nicer to deal with than VTK.

3D modeling

We’d like our icosahedron to have 13cm equilateral triangles, which would make it fit snugly inside a 25cm transparent spherical shell for protection.

At first, we wanted to build the icosahedric display with triangular PCBs, but last week, our teachers suggested trying to 3D print a facet and put a LED strip (one the ubiquitous APA102 strips) on it, to check density, and if triangular PCBs are really necessary: perhaps we could have a PCB inside the isocahedron control LED strips glued to the facets.

Hichem and I made a model using OpenSCAD to understand how to lay the LEDs out. It’s a pretty neat piece of software for 3D declarative modeling. I really appreciated that because in this case, we had to be explicit and think about our constraints. So far, here’s what we’ve got:

The LED strips are meant to go under this. Using this model, we see that with the strips and dimensions we chose, there’s 111 LEDs per facet, so 2220 LEDs overall. That’s huge, and we’ll have to discuss whether having that many LEDs is feasible (or desirable, for that matter).

[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).

[bouLed] Visualization and 3D printing

For bouLED, we will need to know its orientation. The orientation can be represented as a quaternion but we haven’t implemented Madgwick’s algorithm yet. So, I wrote a python script to simulate a rotation. The script generates and writes a quaternion on the script standard output.

In fact the sphere will be an icosahedron. It‘s the regular polyhedron made of 20 equilateral triangles. So I drew a equilateral triangle on openscad in order to print it in 3D. Then we will stick on this triangle a LED strip, and we will judge if the resolution is high enough.

BouLED: display in a sphere

Overall idea

BouLED is, as its name implies, a spherical-ish LED display (in fact, an icosahedron), made of triangular PCBs.

The displayed image is stabilized: there’s an AHRS (accelerometer, gyroscope, magnetometer) array that computes the ball’s orientation and rotates the image so that it appears not to move, even if the ball itself does. Here’s what it looks like in the simulator:

The LEDs are not to scale here, so that it’s more obvious that the algorithm works. However, it will be enclosed in a plastic sphere that will diffuse the LED’s light, so this is a reasonable preview of the final product

The triangles are nothing more, electrically speaking, than a LED strip with APA102 LEDs and a 5V switching power supply. There’s also a main board with the main MCU, a SD card for image/animation storage, an AHRS array, and an ESP32-DevkitC that handles network communication. The triangles are divided in a few chains and are connected to the main board over SPI as you’d do with a regular APA102 LED strip.

An archive of the repository is available on GitHub. You can also find bouLED on Hackaday.io.

Post index

[bouLED] Visualizing an orientation

The first thing I did for our project bouLED was to write a python script to visualise the orientation of our test card.

bouLED will need to know its orientation, which will be computed from a MARG (Magnetic, Angular Rate, and Gravity) sensor using Madgwick’s algorithm. In order to easily check the results of this computation, we want to draw and rotate a 3D shape as we rotate the card with the MARG sensor. The orientation of the card is represented as a quaternion, and will be sent to my python script via a serial port.

We haven’t implemented Madgwick’s algorithm yet, so I just sent arbitrary quaternions to test the visualization. Its latency was at first unacceptable (~0.5s) when I used PySerial to read the serial port.  Sending the serial port to the script standard input made the latency imperceptible.

[bouLED] Polling an AHRS array

For image stabilisation, there must be some way of computing bouLED’s 3D orientation. We chose the Madgwick sensor fusion algorithm using an AHRS (Attitude and Heading Reference System), which comprises a magnetometer, an accelerometer and a gyroscope.

Alexis gave us STM32 «IoT node» Discovery kits, which feature this AHRS array among the extensive list of on-board sensors. I wanted to use ChibiOS, but this devboard uses a STM32L475VG microcontroller, whereas the closest supported microcontroller is in the STM32L476 series. Therefore, I had to port ChibiOS, which gave me some interesting insight about the inner working of its MCU abstractions.

I had to manually query the LSM6DSL accelerometer/gyroscope combo over I2C, but fortunately, a driver for the LIS3MDL magnetometer is already provided in ChibiOS/Ex. For the moment, the unfiltered values are sent to the computer over J-Link RTT; we will eventually use UART-over-USB instead.

The final board will use a AHRS combo in one chip, because in the current setup, the gyro and accelerometer are synchronized with each other, but not with the magnetometer.