Here is the demo that I promised last Thursday for @PetervdPerk @dagar and @tsc21. The demo shows how to configure a subject-ID via uavcan.register.Access.1
.
Building the demo
We are going to need libcanard and a SocketCAN facade for it. It is assumed that the host system is GNU/Linux. The build is trivial:
cmake_minimum_required(VERSION 3.16)
project(demo C)
set(CMAKE_C_STANDARD 11)
include_directories(libcanard socketcan)
add_executable(demo demo.c libcanard/canard.c socketcan/socketcan.c)
Or just:
gcc demo.c libcanard/canard.c socketcan/socketcan.c -I socketcan -I libcanard
demo.c is attached. Its logic should be self-explanatory.
Evaluating the demo
To evaluate the demo, we are going to need the PyUAVCAN CLI tool: pip install pyuavcan[cli]
Set up a virtual CAN bus:
sudo modprobe can && sudo modprobe can_raw && sudo modprobe vcan # Load the kernel modules
sudo ip link add dev vcan0 type vcan # Register a new virtual CAN interface named "vcan0"
sudo ip link set vcan0 mtu 72 # This is to enable CAN FD (optional)
sudo ip link set up vcan0
You can listen to the traffic on the bus using candump -decaxta any
. Arch-based users will find it in AUR under the name can-utils
; Debian-based distros ship it under the same name.
Prepare the PyUAVCAN CLI tool:
cd ~/test
pyuavcan dsdl-gen-pkg path/to/public_regulated_data_types/uavcan
export PYTHONPATH=~/test # To make generated packages importable
Launch the compiled demo on vcan0
using node-ID 42: ./demo vcan0 42
Open a new terminal to listen for its heartbeats:
$ pyuavcan sub uavcan.node.Heartbeat.1.0 --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 64), None)'
---
32085:
uptime: 824
health: 0
mode: 0
vendor_specific_status_code: 0
...
Open another terminal and read the current register value by calling uavcan.register.Access.1.0
on the node-ID 42:
$ pyuavcan call 42 uavcan.register.Access.1.0 '{name: {name: uavcan.pub.measurement}}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 8), 125)'
---
384:
timestamp:
microsecond: 0
mutable: true
persistent: false
value:
natural16:
value:
- 65535
You may also briefly see another heartbeat emitted by the above command. If you read a non-existent register, you get an empty response back as prescribed by the register protocol spec:
$ pyuavcan call 42 uavcan.register.Access.1.0 '{name: {name: no.such.register}}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 8), 125)'
---
384:
timestamp:
microsecond: 0
mutable: false
persistent: false
value:
empty: {}
Okay, now let’s suppose that we’re going to use a subject-ID of 5555 for our measurement messages. Open a new terminal and launch a subscriber on subject-ID 5555 of type String:
pyuavcan sub 5555.uavcan.primitive.String.1.0 --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 64), None)'
You will see nothing because the node doesn’t know the subject-ID yet. So we configure it:
$ pyuavcan call 42 uavcan.register.Access.1.0 '{name: {name: uavcan.pub.measurement}, value: {natural16: {value: [5555]}}}' --tr='CAN(can.media.socketcan.SocketCANMedia("vcan0", 8), 125)'
---
384:
timestamp:
microsecond: 0
mutable: true
persistent: false
value:
natural16:
value:
- 5555
We received a response that contains the same value that we’ve just written which means that everything went well. Now we can see the published messages in the subscriber tool:
---
5555:
value: So it goes.
---
5555:
value: So it goes.
...
The invocation of uavcan.register.Access.1
can be done manually by the integrator who is configuring the node for use with a particular end system, although it is inconvenient and requires special tools, not to mention dealing with the awkward YAML syntax of the PyUAVCAN CLI tool. Despite the inconvenience, it works as a first step. We will be building a better user experience on top of this without affecting the end-nodes in any way: the improvements will be focused on the so-called “master node” (UAVCAN is masterless so this is to be understood as the application-level master, like the FMU on a UAV). PX4 can expose the register API via QGC as a first step (this will be needed anyway regardless of the logic discussed here). Later we can extend the functionality to implement true plug-and-play automatic subject-ID configuration as described in the OP post.
Please note that even though the subject-ID is configured at runtime, it would be a mistake to call it “dynamic”, because it is not changing while the system is running. Instead, it is to be configured once at the system definition time, and hence we call it static runtime-assigned.