RGB Led Display

The attached code came from a Arduino lesson (https://osoyoo.com/2017/08/23/arduino-lesson-rgb-led/).
What i would like is a version in XOD, has anyone done anything like this ?
I am far to stupid to write the code myself,
Please help.
looser.

int redPin = 9;
int bluePin =10;
int greenPin = 11;
int redIn = 0;
int greenIn = 1;
int blueIn = 2;
int redVal;
int greenVal;
int blueVal;
void setup() {
redVal = 255;
greenVal = 255;
blueVal = 255;
update();
}
// This function updates the LED outputs.
void update() {
analogWrite(redPin, redVal);
analogWrite(greenPin, greenVal);
analogWrite(bluePin, blueVal);
}
// This function updates one of the color variables
// either getting brighter or getting dimmer.
// It also updates the outputs and delays for 10 milliseconds.
void color_morph(int* value, int get_brighter) {
for (int i = 0; i < 255; i++)
{
if (get_brighter) (*value)–;
else (*value)++;
update();
delay(15
);
}
}
void loop() {
// start out at black (all off)
color_morph(&redVal, 1);
// transition to red
color_morph(&greenVal, 1);
// transition to yellow
color_morph(&redVal, 0);
// transition to green
color_morph(&blueVal, 1);
// transition to aqua
color_morph(&redVal, 1);
// transition to white
color_morph(&greenVal, 0);
// transition to violet
color_morph(&redVal, 0);
// transition to blue
color_morph(&blueVal, 0);
// transition to black (all off)
}

XOD has built-in nodes to help put this together. There is an “led” node to control the LEDs. There is “fade” node that basically implements the morph function. Performing the steps in sequence gets a little tricky in this case.

The easiest way to sequence actions in XOD is to use pulses to control program flow. A direct implementation to just turn the LEDs on & off would look like this:


Which is basically a variation of the basic traffic light example in XOD documentation https://xod.io/docs/guide/simple-traffic-light/ The problem with this is it is difficult to insert the fade node into this code and have it work correctly.

The simplest brute-force option is probably to note that this code has 9 states:
1 everything off
2 Only red on
3 Red & green on

8 Red and Blue on
9 Only Blue on
Loop back to the 1st step.

Knowing this, we can setup a clock & counter to loop through the 9 steps, then use nth-input nodes to select the value for each LED. Note that XOD starts counting at 0, so XOD will be using steps 0-8 rather than 1-9. Adding the fade node before the led node causes the LED to slowly come on & go off.


Note that we do not actually wait for each LED to reach its final value before continuing. Instead, we set the fade function to take 5 seconds to go from 0 to 1 (or 1 to 0), then set the counter to increment every 5 seconds. We could change this so count increments every time all the fade values reach their target value. This replaces the clock node with “equals”, “and”, and a “defer” node to loop back to the count node.

Another alternative is to replace the nth-input nodes with “select” nodes. These require a pulse to determine which value to pass out. This gets us a little closer to the traffic light example, except that we only have one “led” node for each LED that is always active instead of activating the led node with the value we want.


Rather than crossing wires all over the place, I’ve used bus nodes in this example (from-bus & to-bus). Buses with the same label are basically linked by invisible wires. On the right side is a stack of delay nodes that control when each change happens by sending a pulse to select what value we want for each LED. Note that you could link any pulse to multiple LED values instead of just one if you wanted to change more than one at the same time. Green & Blue LEDs only turn on/off once each. Since the Red LED turns on/off multiple times in the cycle, we need “any” nodes to join the multiple inputs.

Like the earlier example, this one has set delays between each step. If you want to trigger each step when LEDs reach their target value, You’ll need the same equal/and logic to determine when we are ready to step. The delay nodes also need replaced. In this case, we need a way to remember which step we are on. One way to do that is to use a flip-flop for each step. The pulse to continue gets sent to all the steps, but only the step that has the previous step active receives the pulse because of the “and” nodes. We also have a “defer” node to reset the previous step.
Here is just the 1st couple steps implemented:

As you can see, there are usually multiple ways to program a single action. Which one is “correct” is not always obvious. It may not matter at all. Inputs needed for other parts of the program might make one an obvious choice. In this example, you might have other actions going on that need to know which step you are in. Having a counter might make that easier…or perhaps pulses will make it easier depending on what you are doing.

In this case, if you didn’t need the fade function, the 1st example would probably be the easiest solution. The way the fade node works, it is not easy to insert it into that code. Since you are always fading from 0-1 or 1-0, you could write your own specialized delay/fade node (morph) that would initialize to the opposite number from your target on SET pulse, then provide outputs for current value, ACT (active) boolean, and DONE pulse so that it could replace the delay nodes.

Morph node (copy of fade node with extra pins & code):
image

#pragma XOD evaluate_on_pin disable
#pragma XOD evaluate_on_pin enable input_UPD
#pragma XOD evaluate_on_pin enable input_SET

struct State {
    TimeMs lastUpdateTime;
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    State* state = getState(ctx);
    if (isInputDirty<input_SET>(ctx)) {
        Number start = !getValue<input_TARG>(ctx);
        emitValue<output_OUT>(ctx, start);
        emitValue<output_ACT>(ctx, true);
    }
    if (!isInputDirty<input_UPD>(ctx)) {
        return;
    }

    TimeMs now = transactionTime();
    Number target = getValue<input_TARG>(ctx);
    Number position = getValue<output_OUT>(ctx);

    if (target == position) {
        // Already done. Store timestamp anyway so that an animation to a new
        // value would not jump at the first update
        state->lastUpdateTime = now;
        if (getValue<output_ACT>(ctx)) {
            emitValue<output_DONE>(ctx, true);
            emitValue<output_ACT>(ctx, false);
        }
        return;
    }

    Number rate = getValue<input_RATE>(ctx);
    TimeMs dtMs = now - state->lastUpdateTime;
    Number step = (Number)dtMs / 1000. * rate;

    if (target > position) {
        position = min(target, position + step);
    } else {
        position = max(target, position - step);
    }

    emitValue<output_OUT>(ctx, position);
    state->lastUpdateTime = now;
}

NOTE: UPD pin is not intended to be used…it is only to allow the node to update without having to add an alarm so that code copied from fade node would work with minimal changes. All I did was add 2 sections of code for the additional pins:

    if (isInputDirty<input_SET>(ctx)) {
        Number start = !getValue<input_TARG>(ctx);
        emitValue<output_OUT>(ctx, start);
        emitValue<output_ACT>(ctx, true);
    }
        if (getValue<output_ACT>(ctx)) {
            emitValue<output_DONE>(ctx, true);
            emitValue<output_ACT>(ctx, false);
        }

The tricky part was realizing I needed an additional pragma line at the top to enable the isInputDirty check for the SET pin:

#pragma XOD evaluate_on_pin enable input_SET

NOTE: Normally this would not work for numbers:

Number start = !getValue<input_TARG>(ctx);

We can only use it here because the TARG and start will always be 0 or 1. “!” is logical “not”. 0 is false and 1 is true, so the “!” of 0 is 1, and the “!” of 1 is 0, so this provides a shortcut to determine the “opposite” number we need to start from.

Hello gweimer,

What can i say you leave me speechless.
Thank you very much for your help.
I decided to try the attached code first but i got an error
“Bus floats
Bus ‘’ source is not linked anywhere
Link the ‘to-bus’ node with label ‘’ to an output pin of another node”
I haven’t used “to_bus / from_bus” nodes before.
I have run out of time i will try to sort the error out and try the code, get back to you tomorrow thanks again.

looser.

It sounds like you have a to-bus somewhere that does not have a name and has not been linked to anything yet.

Hello gweimer,
the fault was like you said (too much cut & paste)
that piece of code works great the only thing is between the blue turning off and the red turning on there is a time when every led is off.
It would be nice to have continuous led output.the gap would be
“1 everything off”

I have loaded the code using nth-input functions and it also works great ( same as first piece of code gap “1 everything off”

I tried loading the code that uses the flip/flops but got the fault message_
Loops detected The program has a cycle Use xod/core/defer node to break the cycle.
i have run out of time get back tomorrow.
once again many thanks.
looser.

You had listed all LEDs off as one of your states, so I added that. In the example you pasted, removing the last delay would eliminate that pause with all LEDs off.

The flip-flop example probably needs a “defer” node between the Step to-bus & the “and” node above it.

hello gweimer,
i put a defer node in the code as the attached graphic,
but same fault no change.
i am still working on the remaining sketches and are becoming more familiar with XOD, is there a node that moves analog values, integer values eg a node with 2 values in one out and a digital in to select the value.
Will the morph node you created be included in the XOD library ?
Thanks again,
looser.

o

image

My flip-flop example didn’t have the entire stack. Did you create a loop from the bottom of the stack back to the top to repeat? The loop back to the top would need a defer node also.

The if-else node will allow you to select between 2 values (which could be numeric) based on COND being true/false

The morph node I show above is too specific to bother adding it to XOD, but you can create your own copy. Just create a new patch and make it look like what I have shown. Then you can use it in your own patch.

Sketch with flip flops-
I had completed the entire stack with the loop back to the top but without the defer node.
by adding the defer node to both the stack and the and Step function the code will upload but refuses to run (still looking at )

The if-else node is fine i am still trying to come to grips with the title/function of the XOD nodes.

I am not shure how to go about making my own morph node.
It would be handy and possibly take up less memory ?

flip-flop code not working: Do you have the boot node to get it started? Did you change the X1 value of each select to 1 instead of the default 0?

Making a new node: In the upper-left corner of the XOD screen it says Project Browser. Just to the right of that are icons, the first one being a sheet of paper with the corner turned down. If you hover over this, it says Add Patch. Click on this and it asks you for the name of the new patch. Type in “morph”. This will create a new tab over the workspace and a blank workspace. Start adding nodes for the morph patch. TARG & RATE are input-number. SET & UPD are input-pulse. The not-i… is not-implemented-in-xod. OUT is output-number. ACT is output-boolean. DONE is output-pulse. Double-click on not-implemented-in-xod node to see the C++ code for the node. Delete whatever is already there & paste in the code I provided above. Now go back to the first tab for your workspace and you can add a morph node.

Using the morph node is very likely to use less memory (and fewer timers than any of options using delay or clock).

There shouldn’t be more than 1 state true at a time if RST is getting triggered the same time next state is set. What does the code for your flip-flops look like? Can you post a xodball of your code?

Hello gweimer,

I created the morph node with the code you supplied but i get a fault as per the screen dump.
Not sure if its anything i done or not.

I cant seem to find an attach file icon.
Not sure how to exchange files with other members of the forum.The flip/flop code is physically hard to get on a screen dump.
looser.

Don’t know what you might have done differently. It works for me.

When typing a reply, there is a row of icons above the text box. The highlighted one is for uploading a file.
image

Here is my copy of the morph code that works on my UNO. rgb-morph.xodball (10.1 KB)

Your morph node worked perfectly, i will have another look at mine.
I have attached the flip/flop xodball code.
once again many thanks stay safe looser.
RGB_3.xodball (36.6 KB)

Bah. Just realized there is a major bug once I saw the code in action. What happens is the boot sets the 1st flip-flop to true. This slowly turns on the 1st LED. You don’t see pulses in debug mode because they happen too quickly, but once the 1st LED gets to 1, it immediately starts going to 0. This indicates that State3 and/or State7 must have pulsed. That’s when I realized that until the fade starts updating LED, Step is still true, so when the 2nd flip-flop changes to true, the “and” after it fires immediately RST 2nd flip-flop & SETs 3rd flip-flop…etc. This is one of those cases where trying to “cheat” and use boolean as a pulse has burned me. The easiest fix I can think of is to replace the "and"s between the flip-flops with "gate"s and convert Step to a real pulse using pulse-on-true:


But it turns out, this code has the same problem of the pulse immediately passing through the flip-flop, so the pulse to SET the next flip-flop also needs to be deferred so that Step pulse has cleared before gate to next flip-flop is enabled.

Hello gweimer,
i modified the code to reflect the gates but got the following fault when i tried to upload.
"Can’t deduce types for patch
Connect links or bind values to generic inputs"
i have attached the code
looser.

I don’t see your code attached, but it sounds like one of your gate or defer nodes has an input pin that is not wired to anything.

Hello gweimer.
i looked at the code and cant see any issues.
ill upload it again and see if you can pick it. RGB_3_gates.xodball (42.8 KB)

Your puls… node just above the Step to-bus is pulse-on-change and the input pin is white, indicating it doesn’t know what type it should be. I’m not sure why since the wire going into it is clearly a boolean, but it doesn’t really matter since you really want pulse-on-true, not pulse-on-change. If you needed pulse-on-change, you could probably fix it by swapping the defer and pulse-on-change node, but pulse-on-true has boolean input instead of generic input, so using the correct node for this code resolves the issue.