Lux Lavalier - now available in the shop!

Lux Lavalier is a beautiful wearable 40mm battery powered pendant with 64 HDR RGB LEDs surface mounted in a Fibonacci distribution and powered by a Pixelblaze V3 Pico.

It’s a collaboration between Jason Coon (@JasonCoon) of Evil Genius Labs, myself (@wizard), and Debra Ansel (@GeekMomProjects) of Geek Mom Projects.

Check out the shop page for more details, or visit LuxLavalier.com.

2 Likes

I have a couple of these Fibonacci64 Micro HDR boards and they are very pretty!

One caveat: there is no clock/data out so you can’t chain them. This has changed the topology of my current project:

A poi quarterstaff with a lit shaft (by 2x 72 LED strips on both sides), 16x16 matrix wrapped around a wider tube at the ends, and then this F64 in the end of the tubes. The Pico Pro 6axis is right at the centre of the shaft, and the signal was going to flow out one of the strips, through the matrix, through the F64, then back through the other strip and all that again on the other side.

Since the F64 has no ‘out’, instead I am making the lighting symmetrical: the signal goes to all 4 strips from the centre, then from one strip on each side (the other one is a dead end) to the matrix, then to the F64. Also I’m only calculating 320 pixels instead of 928. I’ve done one end and the forking worked fine. Keeping my fingers crossed that it works with both ends.

The shaft is 32mm PVC with 25mm acrylic inside, and I have 2 32mm Anker powerbanks. Still trying to figure out how it all fits together. :smiley:

I’m glad the APA102 protocol is actually standard. I have 3 different sets of LEDs in this project and the pixels flow just fine.

1 Like

Thanks! Ah, yes, sorry about that! I usually put data & clock out pads on my LED PCBs, but since the F64 Micro HDR was originally for the wearable Lux Lavalier we decided to omit them rather than have to cover them (and reduce the risk of short circuits while being worn). Well, that and there’s just not a lot of room to put output pads on it :sweat_smile:

Your staff project sounds amazing, I can’t wait to see it!

2 Likes

The good news: forking the PB output to 4 strips works fine!

The bad news: I am the worst solderer in the world. Removed the tiny resistor (or capacitor) in the middle of my Pico, right by the output. Didn’t notice until a week later. Fortunately I have spares :slight_smile:

3 Likes

All wired up! Of course I’ll have to re-wire everything once I build the staff. I have 2M of 32mm PVC, and some 50mm PVC for the cylinders (50mm × π =~ 160mm). There’s also a pile of threaded PVC pipe ends at 32mm, 40mm, and 50mm and … somehow I’ll hide a powerbank in each cylinder!

4 Likes

Thanks to everyone in the complex mapping thread! buildFermatSpiral() is super handy! Here’s how I duct taped it all together:

Mapping function for 72 + 256 + 64 LED staff
function (pixelCount) {
  // All _base and _length measurements in mm
  handle_base =  340

  strip_pixels = 72
  strip_length = 500
  strip_gap    = strip_length / strip_pixels

  cylinder_base   = handle_base + strip_length
  cylinder_side_p = 16
  cylinder_pixels = cylinder_side_p * cylinder_side_p
  cylinder_side_l = 160
  cylinder_radius = cylinder_side_l / Math.PI

  f64_base   = handle_base + strip_length + cylinder_side_l
  f64_radius = 200
  f64_pixels = 64

  var map = []

  for (p = 0; p < strip_pixels; p++) {
    map.push([0,0, p * strip_gap + handle_base ])
  }

  for (p = 0; p < cylinder_pixels; p++) {
    x = Math.floor(p / cylinder_side_p)
    y = p % cylinder_side_p
    y = x % 2 == 1 ? (cylinder_side_p - 1 - y) : y

    theta = x * (Math.PI * 2) / cylinder_side_p

    map.push([
      cylinder_radius * Math.sin(theta),
      cylinder_radius * Math.cos(theta),
      (y/cylinder_side_p * cylinder_side_l) + cylinder_base
    ])
  }

  buildFermatSpiral(0, 0, cylinder_radius, 64, map, f64_base, 0)

  map.push([0,0,0]) // unused pixel at origin

  return map
}

function buildFermatSpiral(originX, originY, spacing, pixelCount, map, zend, angleoffset) {
  reallocation = [0, 13, 26, 39, 52, 57, 44, 31,
     18, 5, 10, 23, 36, 49, 62, 54,
     41, 28, 15, 2, 7, 20, 33, 46,
     59, 51, 38, 25, 12, 4, 17, 30,
     43, 56, 61, 48, 35, 22, 9, 1,
     14, 27, 40, 53, 58, 45, 32, 19,
     6, 11, 24, 37, 50, 63, 55, 42,
     29, 16, 3, 8, 21, 34, 47, 60 ]

  for (var i = 0; i < pixelCount; i++) {
    r = spacing * Math.sqrt(reallocation[i]/63);
    theta = reallocation[i] * 2.3998277 + angleoffset // golden angle
    y = originY - (r * Math.sin(theta));
    x = originX + (r * Math.cos(theta));
    map.push([x, y, zend])
  }
}

And here it is running xorcery: https://youtube.com/shorts/j6E4Z1tBSjc

3 Likes