Objects & XOD: Chaining Best Practices?

Objects or pulses? Or some other way?

XOD aligns best with a stateless (cf. functional, or dataflow, or clock-driven-EE) style. But, many useful things require a sequence of actions, and/or maintain some state. In the c++ world, those are usually objects & methods. And, many Arduino IDE libraries are written in that style (and even some XOD libraries).

It seems necessary to me that we need some mechanism to thread, or chain, nodes (methods) so that things happen in the right order. Is it (usually) a better practice to use pulses, or the object?

Typical Arduino IDE classes have a pattern of: construct object, call .begin(), do-some-action, get-some-value, etc. Here’s an example for neopixels in XOD:

We want a pixel to turn on, some time to pass, then another pixel to turn on.

As you can see in the screen-shot, this attempt was to use the “object” as the thread/chain mechanism. It seems to be a plausible mechanism. However, other things in XOD like “pulses” better (“select”, “branch”, “delay”, etc.), and already exist. The “gate-delay” is just a composite I made.

Here’s the same thing using pulses to chain things:


Which doesn’t require the composite delay-gate, so uses less nodes. But, the “method” nodes all need “trigger” now.

Here’s another one: turn on a pixel (pixel_index=step), but when the step-value is zero, clear the string first. So, like an if:
if step == 0 {
clear-string()
}
set-pixel-color(step, …)
show()
Using the object to chain things, I worked out this:

But, here it is using pulses:

It actually takes more nodes, because it has to produce a pulse from the step’ping (actually, there is a pulse available in this case, from the clock that drives the counter, but, for illustration purposes…). I also don’t like that “pulse-on-change”. I may be confused about whether I need something like that. I was tempted to use “pulse-on-true” (and pulse-on-false), but I wouldn’t get a pulse for every step.

I notice that xod-dev/w5500 has a mixed model. Some nodes take the object (e.g. xod-dev/w5500/lan-ip), and some take pulses. I think that nodes that only take the object are saying “do this only once (as setup)”.

I haven’t done that much XOD coding, so what’s your experience of what works best? Objects or pulses? Other? I’m hoping we can produce a guide from this discussion (especially for me, and especially for my arduino-to-xod library converter).

If that wasn’t enough to think about, don’t forget getters, setters, and instance-variables.

1 Like

@awgrover , I read some post when it was discussed about adding or not pulses, in some patches really do not make much sense or if, it should be configured in boot or continuously, but in other patches is necessary to achieve a correct sequence, for me they are important :guiño:

Unless the object is constantly changing as it passes through the nodes, I don’t think it is going to provide the sequencing you are looking for. If the object is created once during startup & simply passed through each node, there will be nothing changing on the 2nd node using object to indicate it is time for that node to be active. A pulse would provide that change to activate the node. I haven’t worked with objects yet…maybe there is a way to have it include the pulse… Can you create a loop passing object like this? What if other parts of the program don’t use this object (like display to LCD); how would they be included in the flow using object?

An alternative method would be to have a single set-pixel-color node and change the values that are passed to it, but you still need to deal with how to cycle through the desired values (perhaps an nth-input node with pulses sent to show node each time nth-input index is changed). Not a pretty solution…

A compelling point. I was a bit too focused on just the one device/object. Pulses let different devices (their method/nodes) get chained together.

I still get confused about the execution model. A node should “do it’s thing” only according to the pulse (if it has a “trigger” input). If it doesn’t have a pulse-input, then, um, some other rule applies. It feels like set-pixel-color would “do it’s thing” on pulse.

With just the “object” as input, it does seem like the node wants to act only once, like at “setup”. That is imposing a policy, which you can’t get around. The xod-dev/w5500, for example, has a “lan-ip” node, that gets the local-ip-address. There is no way to re-request if the local-ip changes (expired lease, changing wifi).

I tend to err on the other side, and make everything “non-setup time”, putting the burden on the user. Sometimes it is because I know there are useful cases, but much of the time it’s because I don’t know if there might be, so I leave the option open.

Maybe there are some other strategies? Maybe w5500 re-emits the object when the network connection comes up again?

Yes, as gweimer, above, finally got me to understand.

In general, XOD nodes “do their thing” when the program initializes. Each node gets “executed” again whenever any of its inputs change. Most nodes that accept a pulse input return immediately without taking any action if pulse is not dirty, so during initialization (and when other inputs change), they get “executed”, but do nothing. Aside from the flow of pulses and coding nodes to do nothing without pulse, everything will happen all-at-once on startup. “Execute when inputs change” provides an automatic flow-control when calculations are chained together, but can provide undesirable results when there are parallel calculations, so sometimes a defer node is used to wait for other branches without having to hard-code in a specific time-delay.

Use of a gate node to make sure inputs don’t change is one way to void conflict. Something like a robot with a “travel” node to start/stop the motors with PWM is a good example. You call the same “travel” node to go straight or turn right with different speeds for left/right motor. This results in there being multiple travel nodes in the final program, all trying to control the same pins for the motor controller. A gate node feeding the direction/speed/PWM pin for each motor and only enabled when the travel node gets a pulse or enable signal keeps the “turn right” copy of the travel node from firing when you are trying to go straight (or all travel nodes executing during initialization). The PWM pins are just getting set to a specific value each time a travel node executes, so the motor maintains the speed set by the last execution.

Some nodes get really messy, like the built-in servo node. The servo node uses a library that basically starts a background process to continuously send the appropriate pulses to the servo. Changing inputs on the servo node will update the background process, but having two servo nodes with the same output pin will result in the pin bouncing between the two values and the servo going spastic trying to be in two places at the same time. Adding a gate node to the servo input doesn’t help because the background process is already running with the old value. One workaround is to add an enable pin to the servo node and code the node to stop the background process (run “detach”) when the pin is false. As long as only one servo node with the same port # is enabled at a time, things work OK. Disabling all servo nodes allows the servo to free-wheel. Pulse doesn’t work very well in this case because the servo needs to be active long enough to travel to the desired destination, and free-wheeling is a bad thing in some cases (a servo-controlled arm would just collapse if allowed to free-wheel). You could work around the time-to-position issue by adding a built-in timer to the servo node so on every pulse it would be active for a specific amount of time; this might work for some things like a range-sensor that turns to read left, forward, and right values, but you would not want to read the range-finder value until servo has quit moving anyway (adding a done output to the servo would help with this). gweimer/servo has examples for both solutions.

What a discussion! :nerd_face:

Yes, this is a weak point in XOD docs. The main reason is in the fact we did not settle on a “right” concept when those docs were written. There are several orthogonal variants of doing things on this planet, thus the confusion. For quite much time (:grimacing: ) XOD employs the functional approach where data-to-pulse should not possible at all (albeit it is technically achievable now). This way is chosen to make XOD accessible to Pete.

So if you have a node which has a number output the scenario of outputting “five-five-five-five” is indistinguishable from “fiiiiiiiiiive” to downstream nodes. Again, it is not enforced in C++ currently to save a few clock cycles by skipping the check of whether emitValue indeed changes the value and so should we notify downstream nodes.

If you want to run some side-effects on demand with parameters kept constant, add an input pulse to your node. A rule of thumb: if a node makes side effects (it is impure), there should be an intput pulse to trigger it.

In yet other words: a node will evaluate (a) on boot and (b) whenever an input value changes or a pulse input receives a pulse. Whether the node will be evaluate’d in other moments or not is unknown, the behavior must not depend on it.

The mentioned lan-ip node violates nothing, it is pure. It extracts an IP from the connection object. When the object changes it gets re-evaluated. Think of it as of red component extractor from a color object.

Because the nature of each particular method in an Arduino C++ library is not generally known in advance, adding a trig pulse looks fine to me.


Even in this paradigm, some creative tricks are possible. You can “bake” some state changes to the object passed around and react to these changes. For example, the adafruitneopixel custom type might be

struct Type {
    Adafruit_NeoPixel* neopixel;
    int seqStep;
    int erroredAtStep;
}

Then each method can take such value, do its job, and make a copy of this value with seqStep incremented, then emit it down effectively producing a new value to be consumed by a downstream node. :thinking: looks like we’re inventing the Haskell IO monad or JavaScript Promise.

I said it is possible, but I’m not sure whether it will work well. I’m watching at Pete.

So, for the low-level wrapping, I would stick to pulses on the nodes. A clever layer, if required, might be built on top of these nodes by hand then.

Hi all, my first post about this marvellous software. XOD is a gift for those that can’t follow the precise text of programming so well!
I have been trying to programme a servo routine, but have come up against the exact issue Gweimer writes about above, the servo going crazy.
Gweimer, your servo disconnect node seems seems the ideal solution, but I can’t work out how to add it to a rotate-slow type node to adjust the rate? Is this possible?

The simplest solution is to only have one servo node in your program for each servo and change the input value for that one node.

To have the servo slowly move from one position to another, the fade node can be very useful. Instead of feeding servo-VAL directly, you feed the target destination to fade-TARG, then the fade output pin feeds servo-VAL. If you can have different parts of the code providing target positions, one option is to have a select node feeding the fade-TARG pin. Each part of the program requests control of the servo by sending a pulse to the appropriate select-S* pin. The select-X* pins can be hard-coded, or get their value from some other calculation.

For example: pulse each tweak node to have the servo start moving to left, center, or right position:

Sometimes it is REALLY inconvenient to create your patch so there is only one servo node – for example when the servo node is inside another node that is called from multiple locations. Pulling all those patches into a single patch and flattening your program could create a huge mess just to allow you to program using a single servo node.

NOTE: servo control has been completely re-done in recent XOD versions. I haven’t tested, but it looks like if you want to have multiple servo nodes, you will not be able to use the std servo node; instead you will need to open the std servo node and split it up so that you actually have multiple rotate nodes, all fed the same servo-device.

Current servo node:
image

Untested servo-position patch as an example of splitting out the servo node:

Note that the ACT boolean pin has been converted to a DO pulse pin (using flip-flop to provide boolean to act node with auto-reset of flip-flop when rotate completes). Also, the PORT pin has been replaced with a DEV pin so the same device can be passed to all servo-position nodes that control the same servo.

To avoid conflicting values being sent to a single servo, all copies of servo-position controlling the same servo need the same servo-device passed to them.

Here is an example where pulsing one of the servo-position nodes with tweak will update the servo desitination:
image

Sorry I don’t have time to pull out my equipment and actually test this. In one sense, it complicates things because you need to pass device down through your patches to the servo-position, but it eliminates the free-wheel problem created by gweimer/servo/servo-enable option built on older versions of XOD.

This is really helpful! Thank you so much, and such a fast reply!
I will get testing this and report back hoping I can contribute to the forum.

I did some testing, and the select node is a lifesaver.
I managed to fit it all on a single page and it does what I want it to do, more or less!
Thank you for your help, it’s a wonderful forum.