Hacking Nodes with C++ — Part Four

If you’ve been following along with the previous tutorials you have seen a lot of the power of XOD — a visual flow-based programming language. With no prior programming experience we’ve been able to easily design states and control hardware. Another interesting tool is the ability to make completely custom nodes in C++. If there is ever something you want to customize or modify, this section will show you how to do it.

Note — If you are not interested in C++ and want to continue work in XOD you can skip this tutorial and install the gweimer/servo library and have all the required functionality to keep moving forward designing an autonomous robot.

For those wanting to see the advanced features of XOD we will dive into some of the code that controls the nodes. So far in this tutorial we’ve been working through designing states to control hardware such as motors and servos. Our current challenge is adding an extra option for the default servo functionality. The out of the box servo patch automatically connects the servo and rotates it to a certain position. The functionality we will add in this tutorial is adding an extra input to only have the servo connected when we see fit. This will allow us to control servos in multiple states. This article is meant to work in tandem with Part 3 of the tutorial series and you can reference it for the hardware used and test circuit.

Creating a Custom Patch

Let’s begin by creating a new patch (Ctrl + N) and naming it “enable-servo”. Also double click on the servo node in one of your states to see behind the curtain of what is going on inside the servo node. We will use the structure of the servo node to create our modified enable-servo node.

Copy the “inside” of the servo node to our newly created enable-servo node as a starting point. Your screen should look like the image above.

Let’s add another input to this node that will activate this node from our delay. The purpose of this node will be to enable this servo so we will name it En.

Double click to add a new node and search input-boolean to select an xod/patch-nodes/input-boolean node. In the inspector change the name of the input to En. Notice that the inputs re color coded to match different types. We can see the default PORT and VAL inputs as numbers that are green and our newly added En as a Boolean which is pink.

Customizing Nodes with C++

The next step is to dive a little deeper into how the servo is controlled; let’s take a look at how C++ code interacts with the inner workings of each patch. Double click the “not-implemented-in-xod” patch to open up the C++ code. Also head back over to the default servo patch and check out its “not-implemented-in-xod” code.

The screenshots above show the C++ implementation for enable-servo and servo. Notice that even though we copied the structure of the servo patch the C++ code isn’t copied. Go ahead and select all of the servo code (Ctrl + a), copy it (Ctrl + c), and paste it (Ctrl + v) into servo-enable replacing the existing code.

XOD Input Structure

We will first look at the structure of XOD and how inputs are handled in C++ so that we can add code for our newly handled input.

Note the circled sections of code that indicate getValue<input_PORT>(ctx). This is the part of the code that handles our current inputs, PORT and VAL. As you can see this is how we connect the input nodes to the logic of our program. We will need to eventually add in some more code to handle our newly created input, En.

Servo Commands

Also we want to take a look at how servos are controlled in C++. In order to do so we will need to understand some of the code that controls servos. We will look at two functions within the code: attach and write.

Here we can see two important functions circled above servo.attach() and servo.write(). Attach is used to define which pin on the controller the servo is connected to. We will also add in another similar function later that does the opposite servo.detach() that allows us to move between states. The second function is servo.write(). This tells the servo what angle to move to and this is a reading from our VAL input.

Program Structure

The next step is to think about how we can structure our logic so that the servo is only attached and writing if our enable input is true. The basic flow of our program is to do three things:

1) Get values from all of our inputs
2) If enable is true attach and write
3) Else if enable is false detach (to allow other states to control servo)

We will begin by taking a look at step 1: getting values from inputs.

auto port = (int)getValue<input_PORT>(ctx);
auto En = getValue<input_En>(ctx);

The code listed above uses some C++ syntax along with the getValue function that was highlighted above. We will use these two lines of code to read our state inputs PORT and En.

Now we will move on to step 2: check to see if enable is true and if so attach the servo and write the value.

if (En) {
state->servo.attach(port);
state->servo.write(getValue<input_VAL>(ctx) * 180);
}

Notice you will see the if statement checking to see if En is true and our servo.attach() and servo.write() functions within the curly braces of the if statement.

Lastly we will look at the 3rd step along the way. If enable is not true we want to detach the servo.

else {
state->servo.detach();
}

Here we see the else logic, meaning that En is false indicating our state is not active. When this is the case we will use the servo.detach() function enclosed in the curly braces of the else statement.

The last thing worth noting is we are actually removing the configuredPort variable all together because we are configuring the port each time. Therefore you can remove that code near the top of the file.

struct State {
Servo servo;
};

The only line of code inside the struct State curly braces should be the one defining the servo.

Here you can see all of the code that you can look at together and copy and paste into your project.

{{#global}}
#include <Servo.h>
{{/global}}
struct State {
Servo servo;
};
{{ GENERATED_CODE }}
void evaluate(Context ctx) {
State* state = getState(ctx);
auto port = (int)getValue<input_PORT>(ctx);
auto En = getValue<input_En>(ctx);
if (En) {
state->servo.attach(port);
state->servo.write(getValue<input_VAL>(ctx) * 180);
} else {
state->servo.detach();
}
}

Now that you have the code your newly written not-implemented-in-xod node within the enable-servo state should all be finished. The code on your screen should match up exactly with the code above.

Testing

Now we have a newly created servo node that will only be attached and write to a specific position while the En input is set to TRUE. We can write a simple program to test our setup.

The program above shows a structure that tells the servo on pin 9 to go to position 0.25 for 3 seconds. After then 3 second delay the servo should detach and spin freely. Load it up to the Arduino by selecting Deploy → Upload to Arduino.

Here we can see our intended functionality of attach → write → detach. You can see while the servo is attached it locks into that position. After it is detached it is able to spin freely.

After reading this you should be able to create custom C++ nodes to control servos and hopefully have some ideas of how this can help with your project. If you’ve made a cool project and want to share it make sure you head over to forum.xod.io and share your project or get help from the community. Also continue following along with the create a self driving robot tutorial to see how to use this node for programming an autonomous robot.