Hi Tom,
In general, it seems like UAVCAN might work for you, but it may not be able to satisfy all of your requirements. I presume you have read the Guide and studied the demos in C and Python already; if not, consider doing so as it should add clarity.
UAVCAN is, essentially, three things: 1. several transport layers (UAVCAN/CAN, UAVCAN/serial, etc.); 2. data serialization format with a custom interface definition language (DSDL); 3. a simple standard application layer to suit most applications. Practically this translates to shipping serialized data structures around the network in a very low-level manner compared to more sophisticated frameworks like DDS you referenced. UAVCAN consciously trades off features for simplicity on the assumption that proper design provided, one can attain the same high-level architectural goals with UAVCAN by bending the design of the resulting decentralized data distribution system slightly.
One issue I see in your list of desired features is that you seem to be assuming that UAVCAN provides a shared object abstraction similar to what DDS does, but this is not so. In UAVCAN, your application is responsible for commencing data transactions through the network, and as such, there is no abstraction like “object” or “data ownership”. There are only topics (we call them “subjects” usually) that you can publish to (manually) and subscribe to. Topics are segregated using arbitrary numerical identifiers (subject-IDs) instead of names that you might be used to. On each node that may publish/subscribe to a topic there is a name associated with that topic; say, sensors.temperature
, sensors.pressure
, etc, but different nodes may name the same topic differently (e.g., two nodes may refer to the same temperature as sensor.temperature
and sensor_readout
; this is not a problem as long as they agree on the numerical subject-ID).
DSDL is also a rather pedestrian format designed for simplicity and time-predictable handling in high-integrity systems. It supports extensibility and structural subtyping but does so in a rather minimalist way – the Guide provides some examples. You can add/remove fields without breaking wire compatibility as long as you follow a set of simple rules, but there is at the moment no finished solution for runtime type compatibility checking. There was a proposal from @VadimZ that was kind of abandoned but I would very much welcome any effort towards its resurrection:
https://forum.opencyphal.org/t/type-safety-enhancement-proposal/1416
The proposal relies on querying each node’s data type information at runtime in order to determine if it is compatible with the topics it is interacting with. There is a related issue intended to bring the type information to the transport layer in order to make the protocol fully resilient to type mismatch errors:
Decoding data exchanges without any prior knowledge as you requested is possible but not out-of-the-box. Nodes may publish the optional type introspection message called uavcan.node.port.List
that contains information on the topics and services the node is configured to interact with at the moment. It allows the Yakut CLI tool to render the connectivity matrix like this (at the bottom):
Having the list of topics and services, one can read the type information for each topic/service from the standard port type registers like uavcan.pub.sensor.temperature.type
:
Having the type information, your Python node can automatically deserialize the data. This can be easily implemented in a few dozen lines of Python code with PyUAVCAN.
In general, if you compare it against DDS, UAVCAN comes without many batteries included, but in the kinds of systems it is designed for this is often a very desirable property. You can implement higher-level abstractions by layering additional logic atop the bare bones offered by UAVCAN.