XLights Generic Serial with WS2811

Bear112006

New member
Hello, has anyone here used XLights with an Arduino? If so, do you know in what order the RGB values come out? If I set '<' as my prefix and '>' as my postfix, will the data come through as <R,G,B><R,G,B>, <R><G><B>, or some other combination? I know Vixen is easier to use with an Arduino, but it can't make 3D models, which I need. If there is a way to import a custom 2d matrix sequence (or a 3d one!) from XLights into Vixen, I'd LOVE to know! Thanks for your help in advance...
 
I wish I was at my computer to verify but I don't think you "got this" yet.
Generic serial pre and post are intended to designate the start and end of the packet. The data is like this (assuming you used < as pre and > as post)
<rgbrgbrgbrgb...rgb>
The data does automatically come out rgb but is driven by the model definition. So don't assume it is rgb and verify color order in the model. Also note that are telling fastled rgb in the definition
It looks like you are calling "show" every three bytes...too much overhead. Call it when you are done with the packet.
You want to optimize getting data from the serial buffer into the array for fastled. There is only a 64 byte serial buffer on something like the uno and so you need to get those values to "leds" as fast as possible to be sure you don't lose them.
I am not familiar with the colorval code but why are you hardcoding it in one section and multiplying it in another?
when you post new code, please edit post one to say "see post xx for new code"


Yeah, I was going to delete that post after I realized it only sort of worked, but I didn't see a way to delete it or anything... I'm taking your input into account as I continue to modify the code. I'll post it when I finish it (finally)...
 
This is the code I've gotten so far... it works for me. XLights, for me at least, tends to lag when using more than about 50 pixels (150 channels). I stopped using the prefixes/postfixes to try to cut down on this lag, but when using 100 pixels (300 channels), XLights takes about 6-8 seconds to output colors to lights using the sequencer. In addition, perhaps due to the lag, XLights won't send data RGB like my pixels are, but instead BRG. Once I changed the color order in XLights the colors were outputted right, but it's interesting to take note of.

I've simplified my code many times now, and now it seems to work consistently, so here it is:

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


#include <FastLED.h>
#define LED_PIN 3 //Change this for your pin
#define NUM_LEDS 15 // Change for your number of pixels
#include <stdlib.h>

CRGB leds[NUM_LEDS];
int light_num = 0;
int RGB_counter = 0;

void setup() {
FastLED.addLeds<WS2811, LED_PIN, RGB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.clear();
FastLED.show();
Serial.begin(19200); // Change this for your baud rate
}
void loop() {

while (true) {
while (Serial.available() > 0)
{
char inByte = Serial.read();



if (RGB_counter <= 0) {
leds[light_num].r = inByte;
RGB_counter++;
}
else if (RGB_counter <= 1) {
leds[light_num].g = inByte;
RGB_counter++;
}
else {
leds[light_num].b = inByte;
RGB_counter = 0;
light_num++;
}

if (light_num >= (NUM_LEDS - 1)) {
FastLED.show();
light_num = 0;
}
}
}
}
 
Code that is more resistant to XLights outputting weird values:


#include <FastLED.h>
#define LED_PIN 3 //Change this for your pin
#define NUM_LEDS 100 // Change for your number of pixels
#include <stdlib.h>

CRGB leds[NUM_LEDS];
int light_num = 0;
int RGB_counter = 0;
bool unusedVal = 0;
bool firstRun = 0;

void setup() {
FastLED.addLeds<WS2811, LED_PIN, RGB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.clear();
FastLED.show();
Serial.begin(38400); // Change this for your baud rate
}
void loop() {

while (true) {
while (Serial.available() > 0)
{

int inByte = Serial.read();

if (inByte == '<') {
while ((inByte == '<') && (firstRun == 0)){
if (Serial.available() > 0) {
inByte = Serial.read();
firstRun = 1;
}
}
while (inByte != '>') {
if ((Serial.available() > 0)) {
firstRun = 0;
if (RGB_counter <= 0) {
leds[light_num].r = inByte;
RGB_counter++;
}
else if (RGB_counter <= 1) {
leds[light_num].g = inByte;
RGB_counter++;
}
else {
leds[light_num].b = inByte;
RGB_counter = 0;
light_num++;
}
inByte = Serial.read();

}
}
FastLED.show();
light_num = 0;
RGB_counter = 0;
}
}
}
}
 
I have a "code" I used with 100 pixels, anything more it wasn't powerful enough and started to lag. If you need it let me know and I will post, at work now.
 
Your latest code is starting to look better. I see you put start logic back in. That is so your controller doesn't output garbage not so "more resistant to XLights outputting weird values". xLights is not outputting weird values!

I don't think While TRUE has any value inside loop() as that is exactly what loop() does.

Those IFs to load the data are costly. You can skip a bunch if you do something like this (untested):
Code:
while (Serial.available() >= 3)
{
char inByte = Serial.read();
leds[light_num].r = inByte;
inByte = Serial.read();
leds[light_num].g = inByte;
inByte = Serial.read();
leds[light_num].b = inByte;
light_num++;
}

and the fastled documentation says you can do it in one statement:

Serial.readBytes( (char*)(&leds), 3); // read three bytes: r, g, and b.

The documentation also says you can read the whole array of data with one statement:
Serial.readBytes( (char*)leds, NUM_LEDS * 3);

One reason you are running into problems with number of packets is probably your low communication speed. I see the latest code is now up to 38xxx. That is good but usually you can do better...How long is the cable from computer to controller? What are you using to get from the computer to controller? You should test with higher speeds. I would start my test at 115200 and work up from there.


Interestingly, the 12-inch cable that came with my Arduino Uno seems to be slower than the 12-foot cable I just got. I just have my Arduino plugged into one of my laptop's USB ports through a printer cable to transfer data. The code runs faster now without the if statements, but where the second string starts, the color is one value off (blue instead of red for the second string, even though the first string is red). If you have code for an Arduino connected to XLights via USB, I'd love to learn from it!

UPDATE:
The lights are no longer half a different color, just had to restart XLights. Only issue now is that lights in between two different colors are now the right color (pink and yellow lights between red and white for some reason).

UPDATE 2:

Code works (sometimes you have to restart output...)
Code:
#include <FastLED.h>
#define LED_PIN 3 //Change this for your pin
#define NUM_LEDS 100 // Change for your number of pixels
#include <stdlib.h>

CRGB leds[NUM_LEDS];
int light_num = 0;
bool firstRun = 0;

void setup() {
FastLED.addLeds<WS2811, LED_PIN, RGB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.clear();
FastLED.show();
Serial.begin(115200); // Change this for your baud rate
}
void loop() {
while (Serial.available() > 0)
{

int inByte = Serial.read();

if (inByte == '<') {
while ((inByte == '<') && (firstRun == 0)){
if (Serial.available() > 0) {
inByte = Serial.read();
firstRun = 1;
}
}
firstRun = 0;
while (inByte != '>') {
while ((Serial.available() >= 3) && (inByte != '>'))
{
leds[light_num].r = inByte;
inByte = Serial.read();
leds[light_num].g = inByte;
inByte = Serial.read();
leds[light_num].b = inByte;
inByte = Serial.read();
light_num++;
}
}
FastLED.show();
light_num = 0;
}
}
}
 
Last edited:
Here is the code that worked great for me for a few years before buying a Falcon F16:

Posting it for reference.

Code:
/*=====================================
=            VixPix Sketch            =

  For basic control of RGB Pixels 
  using Vixen Generic Serial3 Protocol
=====================================*/

/**
 * VIXEN Setup:
 * In Vixen display setup...
 *    - Add an element group containing one element for each pixel attached to arduino
 *    - Configure the 'Color Handling'  as "They can be any color: Full RGB"
 *    - Add a "Generic Serial3 Controller"
 *    - Name it what you want (Although... Jdc928IsAwesome is great controller name)
 *    - Set the channel count to 3x the number of Pixels you have 
 *    - Save, then configure these options
 *    - Com Port: choose the correct port for your arduino's Serial3
 *    - Baud Rate: 115200 (or whatever you changed it to below)
 *    - Click OK
 *    - Check the box "Send a text header"
 *    - Type "VIXStart" in the header text box
 *    - Click "OK"
 *
 *    - Click and highlight the newly added Element in the elements list
 *    - Click and highlight the newly created controller
 *    - Your "Total Patch Points" and "Output" counts should match
 *    - Click "Patch Elements to Controllers"
 *    - Click OK and you should be ready to go
 *
 *
 *    You should now be able open a Sequence
      add some effects to the new channels
      and see the strips responding accordingly

 */



/**
 * Pixel Strip Setup
 *    Strips setups vary but generally as follows
 *    - If your using a large number of strips you will
 *      probably want to power them externally. 
 *       
 *    - Connect external V+ to strip Vin
 *    - Connect external Gnd to strip Gnd
 *    - Connect external Gnd to Arduino Gnd
 *    - Connect Strip Data to proper pin on Arduino
 *    - Connect Strip DataClock to proper pin on Arduino if not using ws2812
 */



#include <Adafruit_NeoPixel.h>    //  This is the Neo-Pixel library (ws2812)
                                  //  Change to the library for your pixel types
                                  //  Suggest using a library created by Adafruit
                                  //  so the function names will be the same                               
                                  
                                  
                                  
#define DPIN 6                    //  Change this to the pin# connected to your pixels DataIn
                                  //  Will probably need to define a ClockPin for other pixel


int   PixelCount = 101;             //  Set this to the number of Pixels connected

int   bugLevel  = 0;              //  This is just a way I manage turning debugging over Serial3 on/off

 

/*  Sets up the NeoPixel Strip object
 Replace with proper Object initiation for your pixel types */
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PixelCount, DPIN, NEO_RGB + NEO_KHZ800);   



void setup()
{
  delay(100);                    //  A delay for a reason I can't remember. I can live with one in the setup.  
  strip.begin();                 //  Get strip started
  strip.show();                  //  Initialize all pixels to 'off'
 
  Serial3.begin(57600);          //  Start the Serial3 communication 57600
  bugit("Setup Complete",10);    //  DEBUG: Confirm setup is complete

}


void loop()
{                                       // START LOOP
 
  if (Serial3.available()>2)             // Wait for a few bytes to be recieved
  {
    bugit("Waiting for Header",10);     // DEBUG: Header waiting started
    waitForVixenHeader();               // Header check function
    bugit("VixStart Triggered",10);     //  DEBUG: Header found; getting color data
  
    for (int pixCount=0; pixCount<PixelCount;pixCount++)       // Do this for as many Pixels defined in PixelCount
    {
      int RGB[3];                             // Create array to hold this pixels RGB value                   
      for (int color = 0;color<3;color++)     // For the next 3 incoming bytes
      {                       
        while (Serial3.available() < 1)        // Wait for bytes to be received
        {
          delay(10);
        }
        RGB[color] = Serial3.read();           // Save this byte to the correct RGB value
      }                                       // Repeat until bytes for this pixels RGB value have been recieved

      strip.setPixelColor(pixCount,RGB[0],RGB[1],RGB[2]);  //Set this pixels new color
      
    }                                         // Repeat untill all pixels have had new RGB value set
    strip.show();                             // Update the strip and show with new color                             
  }                                           // YAY! DO IT AGAIN!
}                                              // END OF LOOP



/**
 *  FUNC    bugit           [manages printing of debugging based on debugging level]
 *  @param  String  bugstr  [string to be be printed]
 *  @param  int     blevel  [the level at which this debugging should be ignored]
 *    
*/


int bugit(String bugstr,int blevel)
{
  if (blevel < bugLevel)
  {
    Serial3.println(bugstr);
  } 
  return;
}


/**
 * I 'borrowed' snippets of this waitForVixenHeader() function from some code I found online
 * Can't find the originator now but thank you. It works well.  
 * 
 */
void waitForVixenHeader()
{

    bugit("Waiting Loop",10); 
    char *header="VIXStart";
    char buffer[3];
    int index = 0;

    while (true) 
    {

        int inByte = Serial3.read();
        if(inByte==-1)
        {
          continue;
        }
        
        buffer[index] = inByte;
        if(buffer[index]!=header[index])
        {            
            index=-1;                     // not the right sequence restart
        }
        
        buffer[index+1] = 0;              // add null
        index++;
        if(index==8)
        {
          return;
        }
    }
}
 
Back
Top