Académique Documents
Professionnel Documents
Culture Documents
To work with XOD, you use the XOD integrated development environment (IDE for short), which comes in two
flavors: browser-based and desktop version.
Browser-based IDE #
You can start the browser-based XOD IDE simply by visiting the link. However, because the browser has
relatively few permissions to access the computer’s file system and USB-ports, its capabilities are quite
limited.
Notably, you can’t upload your program directly to the board from within your browser and you won’t get the
convenient save/load functionality.
However, you can import/export your programs as a single file (known as a xodball), generate source code
that you could copy and paste into an Arduino IDE, and then upload it to the board via the Arduino IDE.
Desktop IDE #
XOD IDE for desktop requires installing, but provides all features. It works on Windows, macOS, and Linux. Find
a distribution package for your system on downloads page.
What’s next #
Once you start XOD IDE, you’ll see the welcome-to-xod project open. It’s a tutorial project split on many small
lessons. Follow instuctions in its comments to learn XOD. There is a web version of the tutorial if you just want
to get shallow understanding.
You’ll need some hardware components to compete the tutorial, here is the list of parts.
Browser-based IDE #
You can start the browser-based XOD IDE simply by visiting the link. However, because the browser has
relatively few permissions to access the computer’s file system and USB-ports, its capabilities are quite
limited.
Notably, you can’t upload your program directly to the board from within your browser and you won’t get the
convenient save/load functionality.
However, you can import/export your programs as a single file (known as a xodball), generate source code
that you could copy and paste into an Arduino IDE, and then upload it to the board via the Arduino IDE.
Desktop IDE #
XOD IDE for desktop requires installing, but provides all features. It works on Windows, macOS, and Linux. Find
a distribution package for your system on downloads page.
What’s next #
Once you start XOD IDE, you’ll see the welcome-to-xod project open. It’s a tutorial project split on many small
lessons. Follow instuctions in its comments to learn XOD. There is a web version of the tutorial if you just want
to get shallow understanding.
You’ll need some hardware components to compete the tutorial, here is the list of parts.
Required Hardware
XOD is not tied to a particular vendor of hardware. It is compatible with various controller boards, sensors,
and peripherals devices that can be programmed with Arduino IDE.
Nevertheless, for the best experience with this tutorial we recommend you using Arduino Starter Kitbecause it
contains all the components you’ll need to complete the lessons.
Components you’ll need #
1× Arduino (or compatible) board
1× USB cable
1× Breadboard
2× LED
1× TMP36 temperature sensor
1× Servo
2× Tactile buttons
1× Photoresistor (aka LDR)
1× Potentiometer
2× 220 or 330Ω resistors
3× 10kΩ resistors
Jumper wires
Ready? #
Go to the first lesson →
Welcome to XOD, dear Maker! Here, in XOD, we do not use text to code, but visual objects instead.
Patch board #
The large gray field with a box is your program. It’s called a patch. In this patch you can see one interesting
object – the led node — a grey rectangle with little circles. You will be able to make complicated programs,
using these rectangles.
You can move nodes by dragging them. Position on the patch board does not affect your program, but can
make it more readable.
You can see a comment as well. Even though it is there, it does not affect the patch, because it is invisible to a
machine. It’s only visible to you, a clever human. You can drag it to move too.
Project browser #
On the left side you will find a list of patches grouped by a project or library name. The list is called a Project
Browser. When you launch XOD for the first time the first item in the list is welcome-to-xod. This is a special
tutorial project you can follow to learn XOD right inside the XOD IDE.
To expand a project click on it. Projects consist of many patches. The welcome-to-xod is not an exception.
You can double-click any patch name to open it on the patch board.
Next lesson →
#02. Upload to Arduino
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning
experience we recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same
tutorial there.
Let’s learn how to upload your patch with the node to Arduino! For an example we’re going to use
the welcome-to-xod/02-deploy patch. Although the process is the same for any patch.
Test circuit #
↓ Download as a Fritzing project
NoteIf you’ve previously seen what code to blink an LED looks like for Arduino, you might be astonished
looking at the amount of code produced by XOD. Don’t worry — most of it is code for the XOD runtime
environment, which actually creates little overhead after compilation. You don't need to understand how it
actually works. For now, think of it as a black box.
The led is a simple LED controlling node. It can control only a one-colored LED. The node has input
pins PORT and LUM along with a few other pins you can ignore for now.
Pins #
The small colored circles on nodes are called pins. Pins are divided into inputs and outputs. Inputs are always
on the top side of nodes, outputs — on the bottom.
Pins are used to transfer data between nodes. Nodes process these values and take some action or give a
result. In this example, the led node transfers the led brightnes value (set in LUM) to the Arduino port (set
in PORT).
You can change values of pins with a sidebar called Inspector. You will see the Inspector on the left under the
list of projects.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
1. Click on a node for which you want to change pin values. In our example, the led node. It will make the
node selected.
2. In the Inspector, change the values you desire.
3. Upload the patch again to apply the changes.
Next lesson →
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
Use Inspector to enter a value with floating point. The following notations are supported:
0.4
.4 (same as 0.4)
4e-6 (scientific, 4×10-6 = 0.000004)
Next lesson →
By a convention the leftmost pins are used to define the wiring information. If the device is simple and
communicates with the Arduino via a single hardware port the corresponding XOD pin is called a PORT.
Note, that many devices require some specific hardware capabilities from the port they are connected to.
Notably, to smoothly control a parameter (like LED’s brightness) the port should support PWM (pulse width
modulation). PWM-enabled ports have a tilde (~) symbol printed next to their numbers on Arduino boards.
Test circuit #
↓ Download as a Fritzing project
How-to #
You can set port values exactly the same way as you do with other pins.
Next lesson →
There are several ways you can add a new node to the patch in XOD. The effect is the same, use one that is
more handy for a given situation.
Test circuit #
One way is using the Project Browser. In the node list, you will find the xod/common-hardware section. This is
a library where you can find nodes for working with specific hardware. Find the led node there. Note that the
nodes are arranged in alphabetical order. Hover the cursor over the led node, and click the burger icon to
access context menu. There click “Place” then drag it to any slot.
Alternatively, you may drag the node from the Project Browser instead of using the context menu.
Yet another way to add a node is the Quick Search feature. Press “I” key or double-click anywhere on the
patch. Then type what you are looking for. It searches not only in nodes titles, but even in the nodes
description, like a small and dumb built-in Google.
Next lesson →
How-to #
1. Select a node you’d like to rename.
2. There is a field with a green flag in the Inspector; you can find it above the pins. Type any name for the
node into this field.
Next lesson →
The simplest source of output values is a constant node. Its output value never changes during the program
execution. Although, while programming you can set its value as usual, with the Inspector.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
1. Find the constant-number node under xod/core and add it to the patch.
2. Connect its VAL output pin with an input of another node. To do this, simply click on the VAL pin and
then on the destination pin. You will then see a green line connecting the two pins. This line is called
a link.
3. Set a desired constant value via Inspector.
Next lesson →
There is a special node pot to read values from a potentiometer. You will find it in the xod/common-
hardware library.
Test circuit #
↓ Download as a Fritzing project
How-to #
1. Add the pot node to your patch.
2. Set the PORT pin value on the pot node to A0 if you have connected the potentiometer to Arduino port
A0 as shown above.
3. Link the pot node VAL pin to input pins of nodes to control.
In our example, if you turn the potentiometer knob, it will affect the brightness of the LEDs. Depending on the
angle of the knob, the pot node returns a value from 0.0 to 1.0 to the VAL pin, and that value is transferred to
the LUM pins of both LED nodes.
Next lesson →
The pin’s color indicates the type of data that this pin is compatible with. Green pins can take and return
numerical values. Blue pins work with pulses, a special data type that we will return to later.
As you can guess, the multiply node transfers the result of the multiplication of the numbers from the input
pins (IN1 and IN2) to the output pin.
In xod/core, you will find nodes for different mathematical and trigonometric calculations. Along with
the multiply node, you will find add, subtract, and divide for very basic computations.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
1. Add a new multiply or another math node to the patch.
2. Link its left input to the first value provider.
3. Set the right input value with the Inspector or link it to an output too.
Turn the potentiometer knob. If you have followed the example. The LED on port 11 will reach the maximum
brightness with a half-turn of the knob. This happens because the multiply node multiplied the input values
and transferred them to the OUT pin. As IN2 was set to 2 in the Inspector, the value of the pot node doubles
before reaching the LUM pin of LED2.
Next lesson →
Its PORT pin specifies the digital port on the Arduino that the servo is connected to. The pin VALaccepts values
ranging from 0 to 1; it turns the servo shaft from 0 to 180°.
Test circuit #
NoteAlthough we don’t need the two LEDs used before in this particular lesson you can leave them as is on
your own breadboard. We’ll use them again in later lessons. The same is true for any “disappearing” parts in
next chapters.
↓ Download as a Fritzing project
How-to #
1. Add a servo node to the patch
2. Set its PORT pin value
3. Link the VAL input to an output which provides value in range 0–1.
Turn the potentiometer knob, and watch the servo turn, too!
Next lesson →
#12. Accessing Help
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning
experience we recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same
tutorial there.
There are many nodes in XOD. You can figure out which node does what by yourself; you just need to read the
help page. There you would also details about pin value ranges.
How-to #
There are several ways to access a node help page.
Select a node you’re interested in. Open the Helpbar either by clicking main menu item “View →
Toggle Helpbar” or pressing the “H” key.
Click the book icon in the Inspector or Project Browser to open the same help article in a web browser.
Next lesson →
The practical task is to make the servo rotate smoothly from 0 to 90°, reflecting a temperature change from
20°C to 50°C.
You can actually do this using few math nodes, but XOD has a special node for such cases. This node is called
the map node.
Setting them properly would map an input from one range to an output in another.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
1. Add the xod/math/map node to your patch.
2. Link the X input to a value to be mapped.
3. Set input (source) range bounds with Smin and Smax (e.g. 20 and 50).
4. Set output (target) range bounds with Tmin and Tmax (e.g. 0 and 0.5).
5. Use Xm as the resulting value in the new range.
If you followed the example try to heat the thermometer with a hot object (i.e. a paper knife heated with a
lighfire). At a temperature of 35°C (half the input range), the servo should rotate to 45°, which is half the
output range.
Next lesson →
After the previous lesson, the map node linearly maps the 20–50°C range to the 0–90° servo rotation. Let’s
raise the sensitivity. Say, we want to map 15–30°C to 0–90° rotation.
However, what will happen if the X pin of the map receives data that is outside the input range (10 or 42, for
example)? The output value which is a servo angle will fall outside the desired range too.
For such cases there is a sibling node called map-clip. It works the same way, but any input that is out of
range will be rounded to Smin or Smax. Thus, if X receives a value of 10, the map-clip node will accept it as 15,
and 42 will be accepted as 30.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
Just use the map-clip instead of the map if you want the output range to be guaranteed.
If you prefer °F, you can easily translate the data from the thermometer with the c-to-f node
from xod/units. The range will be 59–95°F.
Next lesson →
#15. Buttons
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning
experience we recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same
tutorial there.
So, buttons! They could be read with a button node from xod/common hardware. The node makes all the work
related to signal debouncing so that you have not to bother about it.
The button node has a purple output pin called the PRS. This pin returns a new type of data: boolean.
Boolean data can have either of two values: true or false. In our case, the button node returns a value
of false when idle and true while the button is being pressed.
Good news, in XOD boolean and number data types are compatible. Here are two rules of datacasting:
Boolean-to-number: if you send a boolean false to a numeric (green) input, it will be interpreted as a
numeric 0; if you send a boolean true, it will be interpreted as a numeric 1.
Number-to-boolean: if you send any numeric value except 0 to a boolean (purple) input; it will be
interpreted as true, and if you send 0, it will be interpreted as false.
Test circuit #
↓ Download as a Fritzing project
How-to #
Let’s bind a button with the LED.
Now, when you press the button the button node sets the PRS pin to true, the led node (LUM pin) interprets
it as 1, and the LED turns on at full brightness.
Next lesson →
and returns true if both inputs (IN1 and IN2) are true
or returns true if IN1, IN2, or both are true
xor returns true if only one of IN1 and IN2 is true
not inverts the input value
nand is an inverted and
nor is an inverted or
Test circuit #
↓ Download as a Fritzing project
In the example patch above the and node returns false until both buttons are pressed. The notnode inverts
the value from the and node, so the LUM pin receives its true value (1). Thus, the LED turns on.
Pressing one of the buttons changes nothing. The LED will turn off only when the LUM pin receives false (0).
This will happen only if the not node receives the true value, which is possible only if both buttons are pressed
at the same time.
Next lesson →
Let’s introduce a new sensor to measure an ambient light level. A photoresistor (aka light dependent resistor
or LDR) would do a great job of measuring the parameter. However, there is a small problem: we do not have
a photoresistor node in XOD.
Yet, we have basic nodes for working with the digital and analog ports of the Arduino. A photoresistor is a
pretty primitive device, and all we need to do is read its value from the analog port on the Arduino. To do so,
we will use an analog-sensor node.
It is a low-level node that reads an analog port of Arduino directly and outputs the value measured in 0–1
range where 0 corresponds to 0 volts (value of 0 in the Arduino native language) and 1 corresponds to the
power voltage (usually 5 or 3.3 volts; value of 1023 in C++).
Test circuit #
↓ Download as a Fritzing project
Try to create a device as shown above, cover the photoresistor with your hand, and watch how the brightness
of the LED changes.
Next lesson →
We will measure a lightness level, and if the values exceed or are below the threshold, we will turn an LED on
or off.
XOD has greater-than and less-than nodes to do simple mathematical comparisons. They are in xod/core.
The left IN1 and right IN2 pins receive numbers to compare, and the output OUT pin returns the comparison
result expressed as a boolean value (true or false).
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
How-to #
Place a xod/core/less (or greater) node to trigger an action when a measured parameter goes
under (or over) a threshold value.
Use the left pin to link the value measured.
Set the threshold as the right pin value.
In cases where figuring out the proper threshold is tricky use a value from a potentiometer to adjust it
dynamically.
In the example shown, if the analog-sensor node (our photoresistor) returns a value greater than the
threshold, the greater node will set the OUT pin to true, and the LED will turn on.
Next lesson →
#19. If-else branching
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning experience we
recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same tutorial there.
Let’s imagine that you need to turn the servo to a certain angle, for instance to 45° when you receive true, and
to 135° when you receive false. How can we make that work?
There is an if-else node in xod/core. The COND pin of this node checks the boolean input value.
If COND receives true, the node sets the value from the T pin to the R pin. When it receives false, it sets the
value from the F pin to the R pin.
Now simply set the T value to 0.25 and the F value to 0.75 to make things work.
Test circuit #
↓ Download as a Fritzing project
Now, if the comparison condition is true, the servo will turn to the angle from the T pin of the if-else node
or, otherwise, to the angle set in the F pin of the same node.
Next lesson →
Let’s improve our patch by making the servo move more smoothly. To achieve that, we’ll need to set
the VAL pin value along with a series of transitional values. There’s a node for that, and it’s called fade.
The fade node is in xod/core. This node returns a smooth series of transitional values, so it will smoothen our
servo motion.
The output pin returns 0 at the start of the program. Then, it starts to move toward the TARG value by
the RATE steps. The value of the output pin is saved, so if the TARG value changes, the output will start to move
to this value from the last one returned.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
Now, the servo will turn at a speed of 18° per second (0.1 = 18°).
Next lesson →
#21. Pulses
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning
experience we recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same
tutorial there.
In the tenth chapter, we briefly mentioned the blue UPD input pin and the pulse data type.
This type is very different from all the others. All values in the XOD are transferred to the links continuously,
even if the values haven’t changed. The pulse data type is different. Imagine something like a flash. It’s
basically a message to trigger something else. It does not transmit any data. However, it is useful when you
need to convey that an event has occurred or tell something else to work.
For example, say you only want an pot node to receive information from a board port at certain intervals, and
not all the time. This frequency can be set with the help of pulses.
Each time a pulse arrives on the UPD pin, the node reads the analog port and outputs the value to the VAL pin.
This value will be stored there until it changes to another value.
The same is for the servo. It will send the updated value to the hardware only when receives a pulse to UPD.
The behavior of the UPD pin can also be set in the Inspector. For a pot the choice means:
Never: Never produce pulses. That is, do not take readings or make updates at all.
On boot: Generate a pulse once at startup. Updates the state exactly once.
Continuously: Generate pulses constantly, i.e. take the readings or make updates with the highest
possible rate.
Test circuit #
↓ Download as a Fritzing project
How-to #
1. Open the Inspector for the pot node.
2. Change the UPD value to On boot.
3. Upload the patch to the Arduino.
Turn the potentiometer knob and press the reset button on the board itself. Note, the potentiometer updates
now only once when the Arduino is turned on.
Next lesson →
#22. Clock Node
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning experience we
recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same tutorial there.
Many tasks require you to set a specific frequency for the pulse generation.
For this, we need a new node clock. It can produce pulse signals at time intervals specified by the IVAL pin.
This way, we can control the frequency of data collection from our sensors.
Try to set the IVAL pin in the clock node to 2. This means that it will send a pulse every two seconds.
Test circuit #
NoteThe circuit is the same as for the previous lesson.
↓ Download as a Fritzing project
Slowly turn the potentiometer knob. You will see that the readings are being taken and the servo reacts to
them every two seconds.
Next lesson →
The clock will be the servo. Using the count node, we will change its rotation from 0° to 180° in one minute.
The count node works as a simple counter. Each time it receives a pulse, it increases the number that it gives
out, in increments of the STEP pin.
Test circuit #
↓ Download as a Fritzing project
How-to #
1. In the clock node, set the value of IVAL to 1 second.
2. In the count node, set STEP to 0.017. This means that every time the pulse arrives on the INC pin (in
our case, once per second), the node will increase the number on the output by 0.017. For the servo
node, this is approximately 3°.
3. Upload the patch to the Arduino.
You will see that the servo is “ticking” every second. In one minute, it will reach 180°. The count node works
as a simple counter. Each time it receives a pulse, it increases the number that it gives out, in increments of
the STEP pin
Next lesson →
#24. Flip-flop
NoteThis is a web-version of a tutorial chapter embedded right into the XOD IDE. To get a better learning
experience we recommend to install the desktop IDE or start the browser-based IDE, and you’ll see the same
tutorial there.
You can control the behavior of many nodes with pulses. A very useful node is flip-flop. It acts like a virtual
switch, whose states can be controlled by pulses.
Test circuit #
↓ Download as a Fritzing project
How-to #
1. Assemble the circuit with the LED. Do not forget to specify the desired port in the PORT pin.
2. Set the flashing frequency in seconds using IVAL.
3. Upload the patch to the Arduino.
The LED will turn on and off at the frequency you’ve chosen. Try to control the flashing speed of the LED with a
potentiometer. To do this, connect the output of a pot node to the IVAL pin. Each time a pulse arrives at
the TGL pin, the node toggles the boolean value on the MEM pin from false to trueand vice versa.
Next lesson →
By using multiple independent pulse signals, we can create complex programs to control our devices. Here, we
use two clock nodes to rotate the servo in one direction and then the other.
The patch for this chapter is little bigger than what we’ve seen so far. A good rule of thumb in XOD is to read
the patch from the bottom up. That way you can see the cause and effect relationship created by the flow of
the patch. First, you see the result and then what caused it!
Pay close attention to the map node. Instead of using it in the standard manner, we are simply using it to flip
the sign of the output value.
Test circuit #
↓ Download as a Fritzing project
The servo should tick in one direction for 30 seconds and then in the other direction for 30 seconds.
Next lesson →
Brace yourself, because we are about to learn about the text-lcd-16x2 node! If you haven’t already guessed,
this node is used to control 16x2 LCD screens.
Now, let’s concentrate on the two constant-string nodes. These nodes contain and transmit data of
type string. Yellow is used to indicate string type pins and links. A string is just another name for a line of
ordinary text. This sentence is a string!
Test circuit #
WarningBe careful, there are many connections so chances to make a mistake are high. If you see no text, double check
all connections and rotate the potentiometer to adjust contrast.
↓ Download as a Fritzing project
How-to #
You should now see “Hello world!” displayed on the screen. Cool? Try to display your own message on the
screen.
Next lesson →
Let’s display something useful. For this example, let’s show the time from the moment Arduino was started in
seconds and the reading from the thermometer we learned about earlier.
The number data type is compatible with the string data type. Sensor values can be transmitted without
additional conversions. They will be transmitted with an accuracy of two decimal places.
Test circuit #
↓ Download as a Fritzing project
Now you have a portable thermometer. Try to connect other sensors to reinforce the skills.
Next lesson →
Concat allows you to merge two strings into one. The new string will have the input to the left pin placed in
the beginning and the input to the right pin placed at the end.
Test circuit #
↓ Download as a Fritzing project
How-to #
1. Find the constant-string node in the library. Add one per string that never change. Alternatively,
bind the desired value directly to a concat pin via Inspector.
2. Assign string values to each node using the Inspector. Try something like “Temp: ” and “Light: ” to keep
things short. Put a space at the end so that when we combine it with another string they won’t bunch
up.
3. Link the VAL pins of the constant-string nodes to the left pins of the concat nodes. The IN1 is the
beginning of the line, it’s the first part.
4. Link the outputs of the thermometer and photoresistor to the right pins on the concat nodes. They
will be the second part of the generated string.
5. Upload the patch to the Arduino.
Now, the readings from your sensors are displayed on the screen with a convenient label!
Try it yourself #
Try to display the measurement label before the reading and the units of measurement afterward. Use two
more concat nodes for this. But remember, you only have 16 characters per line.
Try to convert degrees Celsius to degrees Fahrenheit and label them accordingly. You will find a clue for this
task in chapter #14.
Complex Projects
In the tutorial’s past chapters, you’ve used a bare minimum of nodes to build simple projects. But what if you
need to create something more complex?
The programming principles stay the same even if you create more patches and use more nodes.
Refer to the item’s documentation to understand how you can talk with the hardware.
See the implementation of analog-read, digital-write, and text-lcd-16x2 for examples of how to do
this.
User Guide
Concepts #
XOD language objects and processes described in detail.
Program structure
Data types
Linking rules
Execution model
Variadic nodes
Generic nodes
Buses
Case studies #
Temperature log example — logging to SD card and visualizing data
Simple traffic light example — doing things sequentially
Quick setup of W5500 Ethernet Shield for Internet and LAN communication
Advanced setup of W5500
Fetching data from web API’s with HTTP GET requests
Working on projects
Using libraries
Creating libraries
Program Structure
XOD programs are quite similar to electronic circuits. To build an electronic circuit, you use various electronic
components and connect them with wires. In a XOD program, you use nodes and connect them with links.
Nodes #
What a node does depends on its type. Just as there are ICs in the physical world to control motors, amplify
audio signals, and store data, in XOD there are many types of nodes available. You can also easily create your
own.
Some nodes represent physical devices like LEDs or digital thermometers. Others are used to transform and
filter data. Here are few examples:
thermometer-tmp36
console-log
add
to-percent
You place the nodes you’ve chosen for your program into slots to be later connected with links.
A pin can be either an input or an output. Once you feed a new value to an input, the node is evaluated. In
response, it may update the values on its output pins or interact with the real world in some way, e.g. change
a motor’s speed.
Some nodes send an output on their own as a reaction to some external event. For example, the clocknode
sends outputs at regular time intervals.
Pins are depicted as holes with short labels. Inputs are placed at the top of the node, and outputs are at the
bottom.
Values in XOD are quite similar to electric signals. However unlike their electric counterparts, they can carry
not only raw voltage values, but also more sensible data like arbitrary numbers and text strings. Learn more
about values in the Data Types article.
In analog electronic circuits voltage levels change continuously and simultaneously at all points. There is no
such thing as “this chip would think first, than another chip would think”. In digital electronics however many
updates are accompanied with discrete pulses which are sourced by a microcontroller and called clock signals.
Values behave very similarly in XOD. They change and propogate instantly. These cascading value updates are
called transactions. In XOD, the role of clock signals is played by pulses. The Execution Model article describes
how they work in detail.
There are a few rules that define which pins are allowed to be linked and which are not. They are intuitive
enough, but for a formal description see Linking Rules.
Patches #
Nodes linked together form a patch. Patches are like modules, documents, or files in other programming
systems.
You would have a single patch in a simple project, while you’d likely have many for complex projects.
What makes a patch interesting is that once you’ve created one you can use it as a new type of node in other
patches! That’s the main idea behind XOD extensibility.
You use special terminal nodes to denote input and output pins when a patch is used as a node.
Photo by cutwithflourish.
Note Perhaps you’ve heard of modular synthesizers - they are very similar to XOD programs. Nodes are
modules, links are CV cables with banana connectors, and patches are a rack chassis for modules.
Data Types
In XOD, every pin has a data type. Data values are transfered along links between nodes, allowing them to
work together to a perform a job.
This is very much like integrated circuits’ signals in electronics, though hardware signals are quite limited as to
what data they can carry. They are simply voltages with a value somewhere between zero volts and few volts.
Various tricks are used to express meaningful values like numbers. For example, you can map voltage to a
value on a logarithmic scale, or you can interpet the voltage as a series of 0’s and 1’s arriving at a predefined
rate, and then convert them into bytes by grouping them into sets of eight.
XOD has native support for various data types — no need to use any tricks. For example, there are data types
that hold arbitrary numbers, bytes, logic values, or text strings.
Pro Tip
You might know there are languages with static typing (C, C++, Java, Haskell) and languages with dynamic
typing (JS, Python, Ruby). A long flamewar has been waged as to which is better.
XOD is in the static-typing camp, that is a pin can’t have a number value now, and a text string value two
seconds later. This lets the IDE protect you from silly mistakes.
As mentioned above, a data type is a characteristic of a pin. You can say “Node foo has output pin OUT of
number type”. That means that the OUT pin carries a number value in every foo node. You can also say
“Node foo has input pin IN1 of boolean type”. That means the foo node always expects True or False value
connected to its IN1 pin.
Generally, you may link inputs and outputs of the same type only. However, some pairs of different types are
allowed to be linked too. A conversion rule is applied, which is known as casting. To learn which types may be
implicitly cast to which, see the Data types reference.
Number type #
Numbers are everywhere. The number data type is used to transfer sensor readings, set motor speeds,
perform arithmetic computations and comparisons, and so on.
Number values in XOD can be integer or fractional numbers, positive and negative infinity, or a special NaN
(not a number) value.
Pro Tip
The underlying format for number values is 32-bit IEEE 754 floating point.
Here are some nodes you’ll use to work with numbers:
add
subtract
multiply
divide
equal
less
greater
map
clip
Unit ranges #
Many nodes use numbers in the range from 0 to 1. This is convenient if the value denotes some kind of
percentage. For example, a potentiometer node uses 0.0 to denote the leftmost washer position, 0.5 to
denote the middle position, and 1.0 to denote the rightmost position.
Another example is an LED node. 0.0 is used to turn it off, 0.33 to emit 33% brightness and 1.0 to turn on it at
maximum brightness.
Some nodes use ranges from -1 to 1. For example, a motor node use -1 for full backward, -0.2 for 20%
backward, 0 to stop, and 1 to run full forward.
Unit ranges are convenient to use, but entirely conventional. It’s up to a node’s implementation to decide
what to do if an input value falls out of the range. A common behavior is to clip the input to the desired range.
Boolean type #
Boolean values can be either True or False. Alternatively, you can think of them as a choice between of
one/zero, yes/no, on/off, high/low, or enabled/disabled.
Logical values are ubiquitous. They are adequate to implement simple digital sensors (is a button pressed or
not?), control simple actuators (should a relay close?), and carry the results of logical operations (is the
temperature greater than 25°?).
Here are short list of nodes you’ll use a lot working with logical values:
and
or
not
if-else
String type #
Strings represent pieces of text like “Hello World!”.
Unlike some languages that give strings special treatment, XOD considers them to be just a list of bytes. Thus
it’s up to you to manage text encoding. You can choose ASCII, UTF-8, or old-school CP-1252 for storage. The
best choice depends on the hardware modules and data transfer formats you work with.
Computers don’t actually like text, but humans do. You’ll use text to parse high-level input like an SMS or
tweet, and display values to humans, or send them via some web-service.
Byte type #
Bytes are the fundamental building blocks of low-level computing. Many hardware peripherals send or
consume a sequence of bytes to interact with a controller. Essentially a byte is a group of eight bits which are
either 0 or 1.
In XOD, the byte is a distinct data type that is used to perform low-level operations. It can’t be directly
interchanged with numbers as it happens in C++. You have to use explicit conversion nodes from the
standard xod/bits library. It also provides other bitwise operation nodes.
Port type #
The port type is used to denote physical ports on a board. For hystorical reasons, the term “port” is used
rather than “pin” to clearly distinguish the pins of XOD nodes (software thing) and pins for wires (hardware
thing). You will see pins of the port type often when place nodes representing physical pieces of hardware like
LEDs and buttons.
Values of the port type look like A0, A3, D3, D13. For example, A3 describe the board port with the third analog
channel on it which is commonly printed on a board as is: “A3”. The D3 value denotes the third digital port
which is commonly printed on a board as “D3” or just “3”.
Values of the port type must not change their values at runtime: they should stay constant. In other words,
your button must not physically jump from D2 to D10 once the program started. Although the immutability is
not currently checked, it will be enforced future versions.
Pulse type #
The pulse type is special, because it doesn’t actually carry any data on its own. It is only used to indicate that
something has just happened or that something should happen right now.
Pulses are similar to clock or interrupt signals in digital electronics where all we’re interested in is
the moments when the signal rises to Vcc or falls to ground. They don’t carry any additional useful
information.
A pulse signal can tell us that we’ve got a new TCP packet from the network, an NFC card has been detected,
or some time interval has elapsed. We use a pulse signal to trigger an SMS send command or reset a counter.
Pulse signals are quite often accompanied by other value types on neighbor pins. The values describe the
“what”, while the pulse describes the “when”.
Here is a short list of nodes you’ll use a lot in conjunction with pulses:
flip-flop
clock
count
branch
any
Custom types #
When built-in types are not enough to express some domain, you can add new types to the XOD type system.
Custom types can be composites of other types or wrap C++ classes.
Consider custom type values like black boxes which cannot do anything on their own. The author of a custom
type will always put some nodes which operate on such values to perform meaningful actions, query their
data, and allow creating or updating the values.
Read Defining Custom Types to learn how to introduce your own types.
Generic types #
The generic types are not specific types on their own, but rather placeholders that resolve to specific types
when the program compiles. They have names t1, t2, and t3.
The generic types are used when a node performs an operation on values and it does not matter what the
actual types are. For example, if-else outputs either of input values depending on condition. The condition
is boolean, but the values and the output are generic t1 as the node work the same way regardless of the
actual type.
Linking Rules
To make XOD programs behave predictably, there are some rules on how pins can be linked.
If you want to mirror values, just create multiple links from an output pin.
An output can have an arbitrary number of links, but an input can have no more than one incoming link.
Type matching #
If an input and an output have the same data type, they may be linked as is.
However, if they have different types, they can only be linked if the output type can be cast into the input
type.
Once you start linking, pins that are suitable for the other end of the link are highlighted.
Color code #
Pulse
Boolean
Number
String
A signal causes the program to enter a new transaction. The updated values flow downstream along links and
cause the nodes they hit to update. The process of updating a node is called evaluation in XOD.
After all nodes affected by the update are evaluated the transaction is complete and the system returns to the
idle state.
Transaction rules #
No external signals while a transaction is in progress #
All transaction prevent any external update from occuring while the current transaction is in progress. Such a
signal would be postponed and trigger a new transaction after the current transaction is complete.
Evaluation order #
During a transaction, a node is evaluated only after all nodes it depends on via links have been evaluated.
The result node will only be evaluated after both branches are evaluated, despite the fact that they have node
chains of different length. You can’t know the order in which the branches will be evaluated. It could be M1-
M2-M3, M3-M1-M2, M1-M3-M2, or even M1-M2 and M3 in parallel. Furthermore, evaluation of the result
node might be postponed until its values are actually required (so-called “lazy evaluation”). The target
platform decides.
The only thing that does matter is that a node will be never evaluated with incomplete data.
That is the reason why inputs can’t have more than one incoming link. Otherwise, there would be ambiguity if
two or more links tried to deliver different values.
Buffering #
Nodes’ outputs are buffered when changed. In other words, the outputs keep their most recent value. The
data is persistent between transactions. So a node will “see” the buffered value from an old transaction via a
link if the node must be evaluated again due to a change in another input’s value.
Pro Tip If you’re familiar with conventional programming, think of pins and their buffered values as variables. They hold
the program state and evolve over time.
To solve the problem a special defer node exists. It breaks the deadlock and passes a received value through
the outgoing link on the next transaction. In other words, XOD supports the feedback loops, but the cycle path
must have at least one defer node in it to clarify the correct evaluation order.
Summary #
The program’s life cycle can be looked at as a infinite series of transactions that run whenever an external
impact occurs.
Transactions are protected from sudden effects that could change or make ambiguous the order of node
evaluation.
Variadic Nodes
There are operations which can be applied to an arbitrary number of input values. For example, consider the
addition operation. Sure, intuitively you know how it works for two values, three values, or 42 values:
1+6=7
1 + 6 + 3 = 10
1 + 6 + 3 + …more summands… = someNumber
Other examples of such functions include number multiplication, string concatenation or joining, booleans
AND’ing or OR’ing, n-th element choice, and so on.
To natively support such operations, XOD offers a mechanism called variadic nodes. The variadic nodes can
scale the number of their input pins to accept more or fewer values.
In XOD IDE the variadic nodes have a little gripper on the right, and the pins which can scale are marked with
the ellipsis (⋯) on mouse hover. Drag the right border of the node to add as many groups of variadic pins as
you need.
The variadic pins replication count is called arity level. By default, the arity level for a node is 1. When you add
a pin to, for example, the multiply node, the arity level becomes 2, etc.
Expansion #
A variadic node developer is responsible only for creating a node implementation for the first arity level. All
subsequent arity level implementations are induced automatically by XOD. To achieve it, when transpiling the
program each particular variadic node passes an expansion stage in which the system replaces it with a
cascade of primitive level-1 nodes. The replacement principle is better illustrated with an example.
ProDevelopers with functional programming experience could note the expansion is nothing more but a
reduce/fold operation. Indeed! XOD variadics work through input value list folding.
Expansion process for the nodes with an arity step greater than one looks similar.
Shared pins #
When a variadic node has more inputs than necessary to expand it, the leftmost extraneous pins are shared
between all nodes in the cascade.
For example, consider textual string join operation which concatenates input strings placing a specified
delimiter between them (e.g., space or comma). The delimiter will be shared between all expanded nodes, so
you’ll get the result you expect.
In the example above there was a single shared pin. However, there can be more if the author decided the
node to be so.
As a node user, you’ll rarely meditate on which pins are shared, and which are not. The usage pattern should
be pretty apparent from the node designation.
Arranging pins properly is a puzzle for the node creator. Read about all rules and nuances if you want to create
a new variadic node by yourself.
Generic Nodes
Sometimes logic behind a node does not depend on actual types of input values provided. Take, for example,
the if-else node:
It takes a boolean condition COND and outputs either T or F value to R depending on the condition. It should
not matter what the actual types of T, F, and R are. The only important thing is that they should be the same:
all numbers or all strings, for example.
If an input pin has type t1 that means it potentially can accept any data type. Once you link or bind, for
example, a number to it all other t1 pins on that node are considered to be numbers too. The same
for t2 and t3. Note, the generic types t1, t2, and t3 do not depend on each other. So t1 may be a number
while t2 is a string and so on.
Usually, you use generic nodes like regular ones and don’t think of logic behind type deduction, and resolution
process. Although to handle some edge-cases you need to understand principles described below.
A generic node can be a composition of other generic nodes, or it can be abstract. Abstract nodes can’t
translate to C++ because they contain no implementation and serve as placeholders for the transpiler (hence
called abstract). If XOD can’t find a required specialization for an abstract node, it shows an error.
When dealing with a generic composite node, the system searches for a matching specialization, and if not
found, it expands the composition and reruns resolution. The process repeats recursively until all
specializations are found or only unresolved abstract nodes left, which is an error.
Specializations #
A specialization is a regular patch having a distinctive name like:
if-else(number)
if-else(string)
The name is made up of the abstraction patch name (if-else in this case) and type specialization
for t1 enclosed in parentheses.
If a generic node has two or more generic types, the types in parens should be comma-separated,
e.g., foo(string,number,pulse).
In most cases, you should not bother on the specialization patches and nodes as you’re interfacing with the
base abstraction (if-else) and that’s enough. The specializations don’t even appear in the quick-search
suggester by default.
However, sometimes you will want to be specific and use a specialization directly, like a regular node. That’s
called manual resolution. To access a particular specialization, use one of the following methods:
1. Find the specialization in the Project Browser and drag-n-drop it on your patch as you would do with
any regular node.
2. Double-click your patch, type a part of the node name and add a left parenthesis to see the
specializations (e.g., type if-el().
3. Select a generic node to resolve manually, then in the inspector choose the desired specialization in
the drop-down below the node name.
Type deduction rules #
To be successfully resolved later a generic node should match a specific type to each of t1, t2, and t3. It is
called type deduction.
The deduction is done based on actual types of links and values bound to the generic pins. XOD will show an
error if types can’t be deduced unambiguously, for example when one pin of type t1 pretend to be number
and another t1 pin wants to be a string. In such cases you can place cast nodes likeformat-number before the
inputs explicitly.
A slightly more complicated process takes place when multiple generic nodes link in a chain with their generic
pins. In such cases two subsequent passes of type deduction are performed:
1. weak: a bottom-up pass in which generic inputs infer their types from corresponding outputs;
2. strong: a top-down pass while which generic outputs infer types from corresponding inputs.
The strong pass overrides any results produced by the weak pass.
In IDE you’ll see the deduction results in real time. The pins deduced are zebra-colored with gray and the color
which corresponds to the inferred type.
The weak resolution process exists only to deliver better developer experience in IDE when you’re embedding
generic nodes into your patches.
The final program is guided only by the results of the strong pass.
Node resolution #
On the last stage of transpilation, when abstract nodes have to be replaced with particular specializations, the
specializations are chosen based on the types deduced previously.
All matches for t1, t2, and t3 are known at this point, so the remaining task is to find the proper specialization
patch in the project. XOD looks for a patch with name <basename>(<t1>,<t2>,<t3>) in the project and all
libraries installed locally. For example, if the system is about to resolve an abstract if-else node
with t1 deduced to number, the following patches will be found:
xod/core/if-else(number)
bob/stuff/if-else(number)
Now, if no specialization patches found XOD will show an error about unresolved abstract node. You have to
create the specialization by yourself or install a library which includes proper specialization.
If two or more specializations were found, that’s an error too because the system cannot choose one of them
unambiguously. In that case, you have to resolve the node manually using Inspector.
Buses
When you have a complex patch, drawing all links as visible straight lines may produce much of visual noise.
Buses are an alternative way to link nodes’ pins. They allow creating “invisible” links. There are two node types
in xod/patch-nodes that work in tandem:
Bus nodes with the same label are considered to be implicitly interconnected by XOD.
Note
Buses are used in electronics extensively. You’ll rarely see many wires on schematics leading toward a single
GND (Ground) point or Vcc (power source). Instead, the wires are terminated with special symbols of GND and
Vcc buses, and anyone understands that all the symbols are effectively connected together.
The bus nodes do not affect performance or other characteristics of the compiled program anyhow. When
XOD transpiles a program, it replaces all matching bus node pairs with a straight link.
Buses are local to the patch where they are defined. That is, two different patches may have a bus with the
same label, and they will not be related anyhow. There is no way to teleport a link from one patch to another,
use the patch nodes mechanism to achieve it.
IDE shortcuts #
It might be annoying to place a to-bus and from-bus, then giving both a label manually for each bus link. XOD
IDE provides a few keyboard shortcuts to assist you when dealing with buses.
1. You can start linking and when you see the rubber link which follows the cursor press the B key. It will
create a bus node under the cursor with a label matching the pin name which started the link.
2. You can select an existing link or several links at once and press the B key to convert the selected links
into buses: the links are broken, and a matching bus pair labeled after output pin is created.
When you feedback an output back to an input of some upstream node, the reverse link might seem
awkward. Replacing it with a bus is a good idea.
Delivering a common constant or an input like RST, UPD, or ADDR to multiple places may introduce bulky webs.
Replacing them with a bus will make a patch much lighter.
On the other hand excessive use if buses might make a patch harder to follow visually. So, if you’ve made
three or more buses on a patch, ask yourself whether it will be better to extract some parts of it into separate
patches.
Validity rules #
To be successfully compiled the bus nodes should follow several pretty intuitive rules:
A from-bus node should have a corresponding to-bus node with the same label. Otherwise, it will
mean a floating undefined value.
There should be no more than a single to-bus node with a particular label on a patch. Otherwise, it
would be possible to link an input to multiple outputs which make no sense in XOD.
The data type of an input linked to from-bus should be castable from a type of the matching to-
bus node.
If a bus violates some rules, it will be rendered red in XOD IDE. Hover the node to see the error details.
Because of the dual nature of the patches, nodes implemented this way are called patch nodes in XOD. They
are patches and nodes at the same time.
NoteIf you’re familiar with object-oriented programming, think of patches as classes, and nodes as their
instances.
The task #
Let’s create a simple but handy node between which takes a number value, min/max limits, and outputs
whether the value is between limits or not. I.e., it returns true if and only if the following is satisfied:
Make it work #
Let’s start with a test implementation on a single patch. Create a new project (File → New Project, or
Ctrl+Shift+N), name it something like my-utils.
We’ll use a potentiometer as the data source, and a LED to observe the result. Say, we want to test if the value
of potentiometer falls between 0.4 and 0.7 and enable the LED only if the test passes. Combination
of xod/core/less, xod/core/greater, and xod/core/nor would do the job:
Upload the program, rotate the knob to verify all works as expected.
Now move the less, greater, nor nodes from the main patch to the new patch. Use cut/paste (Ctrl+X/Ctrl+V)
to done it.
Add terminals #
Now, we need a way for the between node to get values in and put values out. In XOD patch nodes interact
with the outside world using terminal nodes. You can find the terminal nodes in xod/patch-nodes, they
are input-number, input-pulse, output-boolean, etc.
We are interested in an input-number and an output-boolean since we take an arbitrary number for
comparison and output a true/false value. Add and link them like any other node. Note terminals are rendered
as circles because they’re very special.
Use it #
Switch back to the main. Drag and drop the between node there. Link it to the pot and led so that it acts as a
medium.
That’s all! The node is ready and works. Upload the modified version of the main patch to your board and
verify our brand new node between really works.
Expose parameters #
We compare to hard-coded limits 0.4 and 0.7. Of course, a node user would desire to adjust the limit values
depending on his task. Let’s make it possible. It is as easy as adding two more input terminals.
Look at the main patch now. Whoa! The between node has got two extra pins.
But which one corresponds to which terminal? In XOD nodes show their pins in the same order as their
corresponding terminals are arranged along the X-axis. So here we have the value, min limit, max limit.
Add labels #
In most cases, it is a good idea to specify pin labels explicitly so no one would be confused. Pins get their labels
from labels of their terminal nodes.
Open the between patch, select input terminals one after another and set their labels via Inspector.
NoteConventionally XOD uses pin labels that are similar to IC leg labels. The labels can contain at most four
characters, and usually, they are mnemonics or abbreviations. The restriction allows rendering patches quite
densely.
How did assigning the terminal labels reflected in the main patch? Let’s see. Pin labels became much more
clear and explicit.
If it would make you happier, move the X terminal between MIN and MAX and see how the order of pins on the
node changes.
Conclusion #
Composing new nodes in XOD is not a big deal. Use it to make programs more clear, share functionality, and
reuse your own past work.
The provided example is pretty basic. If you want to learn more, follow a guide to make an analog sensor
driver node.
This article guides you through a process of adding support for such sensor. To do this, we’re going to create a
new patch node. It is implied that you already know how to create patch nodes.
Start with creating a new project, or open the project you worked on while learning to develop patch nodes.
The task #
To demonstrate the process, let’s create a new node to read a popular GP2Y0A02 (yep, not a very elegant
name) infrared range meter by Sharp. This guy:
Our purpose is a node which provides distance to an obstacle in meters. Actually, the xod/common-
hardware library already contains the node, but for the sake of example, let’s imagine there is no such node
yet.
NoteAlthough the last item is optional, it is a good practice. Operating in SI units space removes many
ambiguities, simplifies node replacement, and data interchange.
So, in XOD we need to read analog values from the sensor, do the math, and we’ll get desired distance value in
meters. While testing, use the watch nodes to observe the results and verify correctness. Here is our patch:
Bind the PORT value of analog-sensor to the board pin number you’ve connected the sensor. Upload with
debugger enabled, slowly move a book or sheet of paper ahead of the sensor and observe value change. Do
measurements look realistic? Cool! We have a “body” for our new node.