A collection of MADS plugins for working with Arduino Uno Q devices.
See the official guide.
Required MADS version: 2.1.0.
The Uno Q is a new addition to the Arduino Uno family, featuring a powerful microcontroller and enhanced connectivity options. What sets it apart from its predecessors are the two onboard controllers: a CPU running Linux Debian, and a microcontroller (MCU) that can run Arduino code. This dual-controller architecture allows for more complex applications and seamless integration with various sensors and peripherals.
The communication between the Linux CPU and the Arduino MCU is facilitated through Linux service called Arduino Router, which tunnels Remote Procedure Calls (RPC) from the Linux side to the Arduino side and vice-versa. Via RPC, a function implemented on the MCU side (which has access to all physical pins and peripherals) can be called from the Linux side, and a function implemented on the Linux side (which has access to the network and more powerful processing capabilities) can be called from the MCU side.
These plugins provide an interface for calling RPC functions on the Arduino Uno Q, allowing MADS users to easily integrate the capabilities of the Uno Q into their MADS applications.
The supported platforms for compiling the project are:
- Linux (Ubuntu for testing, Arduino Uno Q only for deployment)
- MacOS (testing only)
Windows is not supported, for the communication with the Uno Q relies on Unix domain sockets, which are not natively supported on Windows.
Building on the Arduino Uno Q can be troublesome, for the device has a limited amount of memory and storage. For this reason, we suggest to download the release binaries and extract the content in the MADS prefix (see next).
To compile the binaries, follow the usual CMake build process:
cmake -Bbuild -DCMAKE_INSTALL_PREFIX="$(mads -p)"
cmake --build build -j4
sudo cmake --build build -t packagewhich produces a .tar.gz file in the build directory. Extract the content of the archive in the MADS prefix (e.g. /usr/local/mads):
sudo tar xzf path/to/arduinoq*.tar.gz -C "$(mads -p)" --strip-components=1The project provides the following binaries:
qrpc_client: A command-line tool for sending RPC calls to the Arduino Uno Q and receiving responses (useful for testing)qrpc_throughput: A command-line tool that benchmarks the throughput of msgpack RPC calls from the CPU (Linux) side to the MCU side. It reads a JSON description of which RPC methods to exercise and how many times, runs each method one at a time, and reports per-method latency and throughput statistics (see Throughput benchmarking)qrpc_dummy: A dummy RPC router/server that simulates the behavior of the Arduino Uno Q for testing purposes (useful for development without the actual hardware). It implements the RPC functionsping()(which returnspong),add(v1, v2)(which takes two integers and returns their sum),echo(arg1, arg2, arg3, ...)(which echoes all received arguments), andemit_notify(method, args...)(which emits a local test notification to a registered method).unoq_source: A MADS source plugin that either routinely executes a given RPC call and publishes its output on a MADS topic, or registers a CPU-side RPC method and publishes MCU-to-CPU notifications received through the Arduino Router.unoq_sink: A MADS sink plugin that executes a given RPC call every time a message is received on a given MADS topic. RPC function name and arguments are encoded in the received message (see next section)unoq_filter: A MADS filter plugin that executes a given RPC call every time a message is received on a given MADS topic, and forwards the output of the RPC call to the output topic. RPC function name and arguments are encoded in the received message (see next section)
The arduino directory contains example Arduino sketches that illustrate the usage of the RPC mechanism on the Arduino side. Look at the documentation for more in-depth explanations.
Once uploaded the sketch, you can test it on the Linux side of the Uno Q with the command:
qrpc_client <function_name> [arg1 arg2 arg3 ...]The sketch rcp_server.ino implements a few RPC functions:
set_led_state: Accepts a boolean and togles the onboard LEDget_digital_pin: Accepts a pin number and returns its digital valueget_analog_pin: Accepts a pin number and returns its analog valueget_json: Returns a JSON objectget_three_arrays: Returns three arrays of different types
The sketch rpc_server_modulino.ino needs a Modulino Movement IMU board, and reads its acceleration values, accumulate into a buffer, and when the get_fft RPC function is invoked it returns the FFT of the acceleration values in the buffer.
The sketch rpc_notify.ino shows the opposite direction: the MCU calls
Bridge.notify("mads_notify", ...), and unoq_source can publish those
notifications as MADS messages when configured in notify mode.
The qrpc_throughput tool measures how fast msgpack RPC calls can be issued
from the CPU side of the Uno Q to the MCU side. It expects a JSON description
of the methods to test (read from a file argument or from stdin), runs each
method one at a time over a single shared connection, and reports statistics.
# from a file
qrpc_throughput throughput_example.json
# from stdin
qrpc_throughput < throughput_example.json
# machine-readable JSON results on stdout
qrpc_throughput --json throughput_example.json
# override the socket path declared in the JSON
qrpc_throughput --socket /tmp/mads-rpc.sock throughput_example.jsonThe input JSON has the following shape:
{
"socket": "/var/run/arduino-router.sock",
"warmup": 50,
"iterations": 2000,
"tests": [
{ "rpc_func": "ping", "rpc_args": [] },
{ "rpc_func": "add", "rpc_args": [3, 4], "iterations": 5000 },
{ "rpc_func": "echo", "rpc_args": ["hello", 42, 3.14, true], "label": "echo-4" }
]
}socket(optional): path to the Arduino Router socket. Defaults to/var/run/arduino-router.sock; overridden by--socket.warmup(optional, default0): number of unmeasured calls performed before timing each test, to prime the connection.iterations(optional, default1000): default number of timed calls per test; can be overridden per test.tests: array of test specifications. Each entry needsrpc_func(the MCU method name) and may includerpc_args(same argument types as the other plugins),iterations, and a human-readablelabel.
For each test the tool reports the number of successful and failed calls, the
overall throughput (successful calls per second), and the latency distribution
(min, mean, median, p90, p95, p99, max, and standard deviation, in
microseconds). Failed calls are counted but excluded from the latency
statistics. By default a human-readable table is printed; with --json the
full statistics are emitted as JSON on stdout (progress is kept on stderr).
You can try it locally without hardware against the qrpc_dummy server, which
implements ping, add, echo, and array:
build/qrpc_dummy /tmp/mads-rpc.sock &
qrpc_throughput --socket /tmp/mads-rpc.sock throughput_example.jsonThe director.toml and the mads.ini file contain example configurations for testing the plugins on a local, development machine (Linux or macOS). The director.toml also runs the qrpc_dummy server, which simulates the behavior of the Arduino Uno Q for testing purposes.
The unoq_sink and unoq_filter plugins expect the input message to be a JSON object with the following format:
{
"rpc_func": "function_name",
"rpc_args": [arg1, arg2, arg3, ...]
}where function_name is the name of the RPC function to call on the Arduino Uno Q, and rpc_args is an array of arguments to pass to the function (if any). Supported types are:
stringint64_tdoublebool- an array of any of the above types
When unoq_source runs in notify mode, it registers one or more CPU-side
methods with the Arduino Router. Incoming MCU notifications are accumulated in
a queue. Each get_output() call drains the current queue, clears it, and
publishes one top-level key per configured RPC method:
{
"mads_notify": [
[arg1, arg2, arg3],
[arg1, arg2, arg3]
]
}With multiple registered methods, the output is grouped by method name:
{
"rpc_1": [
[arg1, arg2]
],
"rpc_2": [
[arg3, arg4]
]
}On the MCU side, emit this message with:
Bridge.notify("mads_notify", arg1, arg2, arg3);Notifications are fire-and-forget. If the source queue is full, the plugin
applies the configured overflow policy and the MCU does not receive a delivery
confirmation. If confirmation is required, use Bridge.call() on the MCU side;
the source plugin acknowledges request frames after enqueueing them.
The plugin supports the following settings in the INI file:
[unoq_source]
pub_topic = "unoq_source" # The topic on which the plugin will publish the output of the RPC call
mode = "call" # Optional; "call" is the default
rpc_call = "ping" # The RPC call to execute (the function name on MCU)
rpc_args = [] # the list of its arguments, if any
period = 1000 # The period (in milliseconds) at which the RPC call will be executed
[unoq_source_notify]
pub_topic = "unoq_notify" # The topic on which received MCU notifications are published
mode = "notify"
provided_rpc = "mads_notify" # Or an array of method names
max_queue = 256
overflow = "drop_oldest" # Or "drop_newest"
[unoq_sink]
sub_topic = ["unoq_sink"] # The topic on which the plugin will publish the output of the RPC call
verbose = false # Whether to print verbose output
[unoq_filter]
sub_topic = ["unoq_filter_in"] # The topic on which the plugin will subscribe to receive the input message
pub_topic = "unoq_filter_out" # The topic on which the plugin will publish the output of the RPC call
verbose = false # Whether to print verbose outputMost settings are optional; if omitted, defaults are used. In call mode,
rpc_call or rpc_func must name the MCU function to call. In notify mode,
provided_rpc or rpc_call must name the CPU-side method to register.
For local notification testing without hardware:
build/qrpc_dummy /tmp/mads-rpc.sock
build/unoq_source.plugin notify mads_notify /tmp/mads-rpc.sock
build/qrpc_call /tmp/mads-rpc.sock emit_notify mads_notify 42 hello