Setting individual LEDs

Hello,
I have been through the documentation (both Robotpy and wpilib) of the new addressable LED framework, and I am a bit stuck on how to use it in Python.

Following the led matrix @auscompgeek shared (part of the repo with the kinematics) a bit ago, I got a flood fill going.

from wpilib import AddressableLED
k_numberLEDs = 60

self.led = AddressableLED(0)
class MyRobot(wpilib.TimedRobot):
    def robotInit(self):
        #Instantiate an LED Object on PWM pin 0.
        self.led = AddressableLED(0)
        #set the number of leds
        self.led.setLength(k_numberLEDs)
        #Create an LED Data Object for the left side
        self.left = wpilib.AddressableLED.LEDData(255, 0, 0)  # I could not get this to instantiate without passing a color.
        
        #Set the length of the led strip 
        self.led.setData([self.left] * k_numberLEDs)
        #Fill the buffer with color
        self.left.setRGB(0,0,100)
        # Write the buffer to the strip
        self.led.setData([self.left]*k_numberLEDs)
        #start the strip lighting
        self.led.start()

My descriptions may be a bit off, but I think I got the jist. However, if I want to individually address a light, I cannot figure out how to do so.

If I try to write the buffer object with
self.led.setData([self.left]*n) #n is the number of lights I want lit
it fills the strip up to the nth light.

If I try to add the n instead of multiplying, python tries to concatenate the two objects.

Wpilib suggests using the AddressableLEDBuffer object like so…

for (var i = 0; i < m_ledBuffer.getLength(); i++) {
   // Sets the specified LED to the RGB values for red
   m_ledBuffer.setRGB(i, 255, 0, 0); //The java version adds the light as an integer
}

m_led.setData(m_ledBuffer);

There are a few issues with this however.
1, I am concerned about using a while loop in a timed robot framework because it may (does in sim) become a blocking call.
2, I cannot figure out how to implement AddressableLedBuffer in Python. SetData is close, but as said before, I can only use it to flood fill the LEDs. In the C++, they seem to use the LEDData Class and set it as they fill the data for (int i = 0; i < kLength; i++) { m_ledBuffer[i].SetRGB(255, 0, 0); } but that does not work in python either (it is not subscriptable).

I know this is significantly less important than our drive and auto code, but what I thought was going to be an easy thing to have the students work on (they already program LEDs using micropython), but it became a bit more involved. I am probably missing something simple. Does anyone have any ideas?

P.S. Sorry for yet another long post.

~Mr. R^2

A small loop should be fine. Maybe this?

data = [wpilib.AddressableLED.LEDData(255, 0, 0)]*n

for d in data:
  d.setRGB(whatever)

data[4].setRGB(whatever)

self.led.setData(data)
1 Like

If you want them to be different colours, you need to do something like:

data = [wpilib.AddressableLED.LEDData(255, 0, 0) for _ in range(n)]
1 Like

Edit: I had totally messed something else up when I tried implementing your recommendations.

        data = [wpilib.AddressableLED.LEDData(255, 0, 0) for _ in range(20)]

        for d in data:
            d.setRGB(0,255,0)
            
        data[4].setRGB(0,0,255)

        self.led.setData(data)

Gives me 19 green pixels and 1 blue (the 5th one). This is the exact expectation. Thank you both.
~Mr. R^2

Edit 2:

        rainbow = 0
        data = [wpilib.AddressableLED.LEDData(255, 0, 0) for _ in range(30)]
        for d in data:
            hue = (rainbow + ((i * 180 / 30) % 180))
            data[i].setHSV(int(hue), 255, 128)
            i +=1
            if rainbow > 180:
                rainbow = 0
            rainbow += 3
        self.led.setData(data)

Recreates the rainbow fill example from Wpilib