0

Multi-tasking different regions of a neopixel strip
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Sat Jan 19, 2019 4:17 pm

Ain't no rest for the wicked
Finished my 2nd week of swing shift manual labor thanks to the US government shutdown. Saturday now and I have some time to look at this.
Challenge #1 to self, add a 3rd region or pixelGroup--Success
Challenge #2, add 1 or more regions to run on another pin independent of those running on pin 3
I added some context and questions in the following lines of code that I altered (within gogglelights.ino)
Code: Select all | TOGGLE FULL SIZE
chainPixels theRings(3);
starLight ring1;  //ring1, ring2, etc. are objects?
portLight ring2;  //starLight & portLight are objects in theRings.cpp
portLight ring3;  //that define the behavior of ring1, ring2, etc.?

//chainPixels theRings(2); //this does not work--redefinition error
                         //this code is structured around working
                         //with one daisy chain on one pin?
                         //Necessary to clone chainPixels.h as
                         //chainPixels2.h in order to define ring4, 5, and 6 etc.
                         //objects to run on a strip connected to pin 2?
//starLight ring4;

void setup() {

  setUpPattern();             // First is to set up the pattern we want.
  theRings.addGroup(&ring1);
  theRings.addGroup(&ring2);
  theRings.addGroup(&ring3);  //an indefinite number of objects can be
  //defined above under the class chainPixels xxxx whether or not they
  //called here? But if an object is called here and not defined above
  //that will be a problem
  theRings.hookup();
}

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Re: Multi-tasking different regions of a neopixel strip

by jim_lee on Sat Jan 19, 2019 8:08 pm

chainPixels theRings(3);
starLight ring1; //ring1, ring2, etc. are objects? YES
portLight ring2; //starLight & portLight are objects in theRings.cpp NO, CLASSES
portLight ring3; //that define the behavior of ring1, ring2, etc.? Sort of CLASSES that define the behavior of ring1, ring2, etc.

//chainPixels theRings(2); //this does not work--redefinition error
//this code is structured around working
//with one daisy chain on one pin? NO, chainPixels is a CLASS theRings is an OBJECT. The OBJECT can only do one pin. Define a new chainPixels say otherRingsSet(2) and add OBJECTS to it.
like this

chainPixels theRings(3); // Gives your original chainPixels object that runs pin 3.
chainPixels otherRingsSet(2); // Gives a fresh chainPixels object for pin 2.

I never tried doing two pins. The entire thing was designed to have less wiring. So it was all about running multiple groups from one pin.


//an indefinite number of objects can be
//defined above under the class chainPixels xxxx whether or not they
//called here? But if an object is called here and not defined above
//that will be a problem


Ok we have to get vocabulary straightened out here.

Define = Class thing, description of things.
Create, Spawn = Using a Definition (class) to create an object. (spawn an object)
Groups object are Created using their class definitions. Then these group objects are added to the chainPixel objects.

Umm.. class = blueprint
object = house you built from the blueprint.

Make sense?

-jim lee

jim_lee
 
Posts: 530
Joined: Thu May 24, 2012 8:24 pm

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Sat Jan 19, 2019 8:28 pm

I've got to run to the grocery store, I think I will rush to the library first and hopefully pick up a C++ for Dummies book to review over the rest of the weekend.

I did set out to change the color scheme from white, red, green, and black to something else such as purple green, red, and yellow. My first basic failure was to find where the colors are defined by name and to edit that (probably class) as needed.

My next goal milestone is to modify the lemmings type of pixel behavior. Anything will do just to demonstrate to myself an understanding of where everything is and how it works.

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Re: Multi-tasking different regions of a neopixel strip

by jim_lee on Sat Jan 19, 2019 11:11 pm

In my stuff there are color starting points. Say &blue or &green. From there you blend stuff.

colorObject myColor; // Created a color object called myColor.

myColor.setColor(&green); //set myColor to green.
myColor.blend(&red,25); // blend in 25% red into myColor.
myColor.blend(&black,50); // Then darken it by 50%

colorObject nextColor(LC_DARK_GREEN); // Another way to start or..
nextColor.setColor(LC_PURPLE); // ..to "setColor"

myColor.blend(&nextColor,44); // Mix 44% of nextColor into myColor the possibilities are endless.

See colorObj.h in the LC_baseTools library folder. For the starting points.. There are two types

&color are actual colors. Addresses to colors. LC_COLOR are Red,Green,blue values that can be dropped into things that take these three values. Like setColor().

In the case of the example, its a color map. Works kinda' like a christmas light string. You place colors anywhere along the string. Then you can specify any point on that string and it'll give you the color blend where you land. Example 4=yellow, 8=blue. 5.6 = some sort of green.

That'll give you something to chew on.

-jim lee

jim_lee
 
Posts: 530
Joined: Thu May 24, 2012 8:24 pm

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Tue Jan 29, 2019 12:41 pm

I'm coming along slowly.
First the create another object to run stuff on another pin:
If I am following everything correctly, it looks like chainPixels is a class and also a function in that class?
This is a portion of the code from goggle_Lights:
Code: Select all | TOGGLE FULL SIZE
chainPixels theRings(3); //where chainPixels is a class in this case, and theRings(3) is a declared object (parameter "3" indicates to run on pin 3--defined in the 'background' of the chainPixels class)?
starLight ring1;   //starLight is a class (in theRings.h)  and ring1 is a newly declared object?
portLight ring2;  //portLight is a class (in theRings.h) and ring2 is a newly declared object?

void setup() {
  setUpPattern();             // First is to set up the pattern we want.
  theRings.addGroup(&ring1); //theRings is the class we want to work with
                                                 //addGroup is a function in that class (with a decimal separator)
                                                //and &ring1 is our object--we are giving our object(s) definition here, where
                                                //they were merely declared above, much like defining a variable, then populating
                                                //it's contents?
  theRings.addGroup(&ring2);
  theRings.hookup();
}

So if I wanted to declare an object which would ultimately run something on pin 2, it would go something like this:
Code: Select all | TOGGLE FULL SIZE
chainPixels rightStrip(2);      //where chainPixels is a class and rightStrip(2) is a declared object with 2 as a parameter
somePattern strip1;             //where somePattern is a class and strip1 is an object first declared here
someOtherPattern strip2;  //where someOtherPattern is a class and strip2 is an object first declared here

void setup() {
  setUpPattern();             
  theRings.addGroup(&strip1); //theRings is the class we want to work with
                                                 //addGroup is a function in that class (with a decimal separator)
                                                //and &ring1 is our object--we are giving our object(s) definition here, where
                                                //they were merely declared above, much like defining a variable, then populating
                                                //it's contents?
  theRings.addGroup(&strip2);  //what is the "&" here btw, bitwise AND operator?
  theRings.hookup();
Last edited by BykeCommuter on Tue Jan 29, 2019 1:05 pm, edited 1 time in total.

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Re: Multi-tasking different regions of a neopixel strip

by adafruit_support_bill on Tue Jan 29, 2019 12:52 pm

If I am following everything correctly, it looks like chainPixels is a class and also a function in that class?

Every class needs a 'constructor'. The constructor is a function with the same name as the class. When you declare an instance of the class, the constructor is executed to build it..

So this line:
Code: Select all | TOGGLE FULL SIZE
chainPixels rightStrip(2);      //where chainPixels is a class and rightStrip(2) is a declared object with 2 as a parameter

constructs an instance of chainPixels called "rightStrip" and tells it to use pin 2.

adafruit_support_bill
 
Posts: 74030
Joined: Sat Feb 07, 2009 10:11 am

Re: Multi-tasking different regions of a neopixel strip

by jim_lee on Tue Jan 29, 2019 1:59 pm

Ok remember class=blueprint object=the tool you build with it.


Code: Select all | TOGGLE FULL SIZE
chainPixels theRings(3); //where chainPixels is a class in this case, and theRings(3) is a declared object (parameter "3" indicates to run on pin 3--defined in the 'background' of the chainPixels class)?>>YES!<<
starLight ring1;   //starLight is a class (in theRings.h)  and ring1 is a newly declared object?>>YES!!<<
portLight ring2;  //portLight is a class (in theRings.h) and ring2 is a newly declared object?>>YES!!!<<

void setup() {
  setUpPattern();             // First is to set up the pattern we want. >> YES!
  theRings.addGroup(&ring1); //theRings is the >>OBJECT<< we want to work with
                                                 //addGroup is a function in that class (with a decimal separator)  >> Close enough. "->" is also used.<<
                                                //and &ring1 is our object--we are giving our object(s) definition here, where
                                                //they were merely declared above, much like defining a variable, then populating
                                                //it's contents?>> No, theRingss & ring1 are both OBJECTS you created above. This is just hookining them together.<<
  theRings.addGroup(&ring2);
  theRings.hookup();


You're getting it! Really, it'll be a "click" in you head and all of a sudden the entire c++ will start to make sense. "They" told me the click would happen when I was learning it back when it was new. "Worthless new fangled stuff" is what I thought at the time. Then after awhile I got the "click" and it suddenly became clear. And a very slick way to code things.

-jim lee

jim_lee
 
Posts: 530
Joined: Thu May 24, 2012 8:24 pm

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Tue Jan 29, 2019 5:37 pm

OK, small breakthrough:
Code: Select all | TOGGLE FULL SIZE
chainPixels theRings(2);
starLight ring1;
starLight ring2;
starLight ring3;

chainPixels LeftStrip(3); //added this line
portLight region1; //added this line
portLight region2; //added this line
portLight region3; //added this line


void setup() {

  setUpPattern();             // First is to set up the pattern we want.
  theRings.addGroup(&ring1);
  theRings.addGroup(&ring2);
  theRings.addGroup(&ring3);
  LeftStrip.addGroup(&region1); //added this line
  LeftStrip.addGroup(&region2); //added this line
  LeftStrip.addGroup(&region3); //added this line
  theRings.hookup();
  LeftStrip.hookup(); //be sure not to forget to add this line or no worky
}

Video:
https://youtu.be/KsZorAAIPpM

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Re: Multi-tasking different regions of a neopixel strip

by jim_lee on Tue Jan 29, 2019 9:02 pm

There you go!

Now made each group of lights do a different pattern so you can see that they are independent.

-jim lee

jim_lee
 
Posts: 530
Joined: Thu May 24, 2012 8:24 pm

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Fri Feb 01, 2019 7:34 pm

Trying to get to a point where I can define a new pattern. First though, trying to follow the goggle_lights.ino through to the end to see what makes it tick etc. (integral to knowing where / how to define an additional pattern).

In goggle_lights.ino, I got down to
void setup () {
setUpPattern();
theRings.addGroup(&ring1); //theRings is an object declared previously in the ino file? addGroup looks to me to be a function defined in chainPixels.cpp and part of the class "chainPixels"
ie. void chainPixels::addGroup(pixelGroup* inGroup) //it looks like to me, this function needs two parameters passed into it--pixelGroup* and inGroup, but I only see &ring1 from this example sample. I must be misunderstanding something.
Also, in these contexts, what do the & and * do?
Thanks

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Re: Multi-tasking different regions of a neopixel strip

by jim_lee on Sat Feb 02, 2019 6:23 am

addGroup(pixelGroup* inGroup);

pixelGroup = This is the kind of thing we are passing in to the function. always in pairs (whatWeArePassing theThing, whatElse theOherThing) you will see functName(int aNumber); or setPoint(float x,float y); What I'm passing and the thing I'm passing.

pixelGroup* = The star means, this is not actually the thing itself, but the address to where the thing is. (So you can go get it.)

inGroup is whatever was listed before it. In this case inGroup is the address to a pixelGroup Object. Passing addresses is a common way to do things. Easier on memory usage etc. Also means multiple things can access something by address.

When you create an object, lets say "myPattern" you would pass it in as &myPattern. The "&" sign means use the address to this thing, not the thing itself.

Another bit of the mine field ahead..

You will see two different ways to call a function from an object

myChain->addGroup(&myPattern);

and

myChain.addGroup(&myPattern);

one uses "." and the other uses "->" Oh lord.. This is going to be tough to explain..

If you declare a new object like this..

chainPixel myChain(1); <--- it is declared on the stack.

If you declare a new object like this..

chainPixel myChain = new chainPixel(1); <--- It is declared on the heap.

There are reasons why you want to choose one over the other.

And.. you call them in different ways..

myChain->addGroup(&myPattern); <-- Heap type. (Because myChain here is actually an address.)

and

myChain.addGroup(&myPattern); <-- Stack type. (Because myChain in this case is the object itself.)

The big difference is, the heap ones "live" until you delete them.

delete myChain; This recycles all the bits that made up this object.
myChain = NULL; I like to do this as a flag after deleting to tell me there is no longer an object at that address.

Stack objects recycle themselves whenever the function you were in when you created them ends. >>poof<<

So for temporary stuff, stack is good. Things you want to pass around Heap is good.

Stack ones declared OUTSIDE of any function... Last forever and everyone can see them.

Good luck with that pack of headache. :)

-jim lee

jim_lee
 
Posts: 530
Joined: Thu May 24, 2012 8:24 pm

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Sat Feb 02, 2019 4:17 pm

OK, so another baby step forward for me. I think.

theThing* // means the type of theThing ie. int, double, string etc., so in the context above it isn't a 2nd parameter but an inherited type definition
In the case of chainPixels::addGroup(pixelGroup* inGroup), the format follows:

class::NewfunctionInThatClass(typeThatPixelGroupIs newVariableCalledinGroup)

inGroup->setChain(this); //if I follow this correctly, inGroup is a pointer, setChain is a variable. Altogether, get the value in setChain pointed to by inGroup and store it in variable this?

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Re: Multi-tasking different regions of a neopixel strip

by jim_lee on Sun Feb 03, 2019 1:37 am

In the case of chainPixels::addGroup(pixelGroup* inGroup), the format follows:

class::NewfunctionInThatClass(typeThatPixelGroupIs newVariableCalledinGroup)

ok

chainPixels::addGroup(pixelGroup* inGroup) - This is the DEFINITION of a method/function of the class chainPixels.
It has one parameter that its looking for to be passed in. The parameter must be an address to an object of class pixelGroup.
Inside the method/function we will refer to this address as.. inGroup.

Since it "knows" what kind of thing you are going to pass in, it "knows" what it can do with it.

And here is pixelGroup (Directly from the .h file) :
Code: Select all | TOGGLE FULL SIZE

class pixelGroup : public linkListObj {

   public:
            pixelGroup(word inNumPixels);
   virtual   ~pixelGroup(void);
           
            void      setIndex(word inIndex);
            void      setChain(chainPixels* inChain);
            word      getNumPixels(void);
             
            colorObj   getPixelColor(word pixelNum);                     // What color is THIS pixel now?
            void      setPixelColor(word pixelNum, colorObj* color);   // Set THIS pixel this color.
            void      setPixels(colorObj* color);                     // Set ALL our pixles this color.
            colorObj   shiftPixels(bool toEnd=true);                     // Even handier!
            void      roll(bool clockwise=true);
   virtual   void      draw(void);                                       // This will be called repeatedly.
   
   protected:
            chainPixels*   ourChain;
            word            numPixels;
            word            index;
};


Everything between the words public: & protected: are methods/functions of pixelGroup that you can use.

For example:

Assume you have a (GOBAL defined on the STACK outside of any function) pixelGroup object called myGroup.

We see here's a method we can call.
colorObj getPixelColor(word pixelNum); <-- pass in a number and it will pass back a colorObj of that pixel's color.

colorObj aColor; // Define a color object to hold our color.
aColor = myGroup. getPixelColor(3); // Grab the color from pixel 3 of my group and stuff it into this color object called aColor.

Here is another method..
void setPixelColor(word pixelNum, colorObj* color); <-- pass in a number and an address of a color, it will set that pixel to that color.

myGroup. setPixelColor(0, &aColor);

Now you have taken the color from pixel #3 and used that to set the color of pixel #0.



nGroup->setChain(this); //if I follow this correctly, inGroup is a pointer, setChain is a variable. Altogether, get the value in setChain pointed to by inGroup and store it in variable this?


inGroup - is a pointer to an object. Or an address of an object.
setChain() - is a method/function of inGroup.
this - is.. Hmm, this is.. myself. When an object needs to reference itself, it uses "this". Think of it as &me. "this" is an object's address.

Here is that call from the .h file.

void setChain(chainPixels* inChain);

Lets look at what it actually does. the .cpp file..

Code: Select all | TOGGLE FULL SIZE
void pixelGroup::setChain(chainPixels* inChain) { ourChain = inChain; }


Ok this is a call that is used by the class chainPixels to put its address into the pixel group.

void - I return nothing, don't bother looking.
pixelGroup:: - Syntax telling the compiler who's method/function we are describing here.
setChain - The name of the method, lets just call them methods so we're in sync with the rest of the universe.
chainPixels - the kind of object that is to be passed in.
* - except its an address to this kind of object.
inChain - what we will refer to as this address.
{ - instruction set starts..
ourChain - this is a variable of our pixelGroup class. It has to be typed as a pointer to a chainPixels object.
= - set the first like the rest.
inChain - you seen this above.
} - End instruction set.

This is an internal call you will never use. But here's what its for..
When a pixelGroup object is added to a chainPixels object, the chainPixels object uses this call to hand its address to the pixelGroup. Its like; you go into a party and the owner of the house is by the door handing everyone his business card. This is what the method setChain is doing. Now, if the pixelGroup needs to contact its chainPixels, it has that address stored under.. "ourChain"


Here's a video of what this code was originally developed for : https://vimeo.com/120994547.
And another : https://vimeo.com/120866527

Hope this helps!

-jim lee

jim_lee
 
Posts: 530
Joined: Thu May 24, 2012 8:24 pm

Re: Multi-tasking different regions of a neopixel strip

by BykeCommuter on Sat Apr 06, 2019 12:51 pm

Hi Jim, I'm back!
I had a somewhat minor surgery on Jan 24th and spent a week recovering going through as many of the tutorials as I could on learncpp.com. I got through the section on classes in chapter 8 about 2 weeks ago.

Before I started on the tutorials, I printed all of the code that I downloaded from your github and tabbed it so I could turn back and forth easily and try to understand it.

I think I'm ready to ask a couple of slightly more informed questions in general terms.

I'm looking at the class definitions in chainPixels.h and the code in chainPixels.cpp and the goggle_lights.ino. Let me make sure I've got my terminology and understanding correct.

chainPixels.h declares a number of functions with parameters in the class chainPixels including: chainPixels, resetChain, push, pop, addGroup, idle, getPixelColor, setPixelColor

chainPixels.cpp creates objects from the chainPixels.h classes (or templates)

In goggle_lights.ino, ring1 and ring2 are declared as objects taking their contents from the starLight function defined in theRings.cpp
chainPixels theRings(2); //this line creates object theRings with a parameter of 2 for pin 2.

I'm still trying to think through where I start to define my own 4 independent regions on 2 strips each on a pin of their own. And where to define their behavior.

BykeCommuter
 
Posts: 30
Joined: Tue Sep 06, 2016 9:46 am

Please be positive and constructive with your questions and comments.