This post is a brief recap of the major design decisions that were made during the Stockholm Summit (Oct 2nd-3rd, 2018) and during the preceding discussions on Github. The objective of the summit was to discuss the main goals related to the transition from the current pre-release version of the specification (termed “UAVCAN v0”) to the first major stable release (termed “UAVCAN v1.0”). The experience accumulated in the three years since the release of v0 showed that certain major breaking changes have to be introduced in order to eliminate early design mistakes (which are too serious to ignore).
For future reference, here is the list of the most relevant conversations that contain virtually the entirety of the context:
- https://github.com/UAVCAN/specification/issues/2
- https://groups.google.com/forum/#!topic/uavcan/guUjFsHk2Lo (the Google Group is closed; now we’re using this forum instead)
- https://github.com/UAVCAN/dsdl/issues/35
- https://github.com/UAVCAN/uavcan.github.io/issues/36
- https://github.com/UAVCAN/specification/issues
(Side note: technical discussions used to be spread out thinly over the Google Group, several Github repos, and the Gitter chat room. From now on, high-level technical discussions should be conducted only on this forum for the sake of ease of tracking and searchability.)
Here is an abridged list of the changes in v1 compared to v0, loosely ordered from most significant to least significant:
- The concept of Data Type ID (and its special cases: Message Type ID and Service Type ID) will be removed from the specification. Identification and separation of data streams will be managed by two new concepts instead: Subject ID (for publish/subscribe links) and Service ID (for RPC). This change alone will have a profound effect on UAVCAN applications and its usage patterns. It will be reviewed later in this post in more detail.
- Added support for CAN FD alongside CAN 2.0B.
- Semantic versioning for data type definitions. In UAVCAN v0, there was no clear method of updating data type definitions. Once a data type was released, its definition had to be frozen forever in order to not break the compatibility with other nodes. Now, there is a well-defined process of data type advancement and maintenance. The full context is available in this megathread on Github: https://github.com/UAVCAN/dsdl/issues/35
- The concept of Data Type Signature (and the related concept of DSDL Signature) will be removed from the specification. The compatibility guarantees will be enforced statically using optional static analysis tooling for DSDL definitions.
- Data integrity checking will be decoupled from data type compatibility checking: multi-frame transfer CRC will no longer be pre-seeded with the data type signature (this is a consequence of the above).
- New CAN ID format. Brand new.
- Tail Array Optimization (TAO) will be removed from the specification. The new approach is to apply same serialization principles uniformly, regardless of the context.
- Some rewording and restructuring of the specification to make the protocol compatible with other transports (not only CAN). Seeing as the protocol is now focused neither on UAV nor on CAN, the name “UAVCAN” is a misnomer. Are there any interpretations that do not involve Unmanned Aerial Vehicles and Controller Area Networks?
A major current discussion topic is whether there is a need to enforce code compatibility under the same major DSDL version. The discussion can be found here: https://github.com/UAVCAN/specification/issues/9. Basically, there are two options on the table:
- Require that the code generated from any DSDL definition be API-compatible with the code generated from any other DSDL definition under the same major version. Meaning that an application can switch from v1.2 to v1.3 keeping its source code unchanged.
- Make DSDL completely unaware of generated code. That means that an application might end up being broken if a DSDL definition v1.2 were to be replaced with v1.3. The implication is that it may no longer be possible to switch between different minor DSDL versions without releasing a new major release of the application. (my personal take on the matter is that the question boils down to whether it is acceptable to version applications and the protocol differently)
Now I would like to briefly recap the major effects of the transition from Data Type ID to Subject ID, mentioned earlier. This is not intended to be an in-depth explanation (that will be published in the spec draft in a few days hopefully); rather, this is a hands-on overview.
The decision was guided by our perception that the protocol v0 was generally well-designed from the physical layer up to the transport layer. The upper layers consisting of DSDL were largely a collection of poorly defined overspecified schemas that forced one to design their applications in a very particular way. Any attempt to step out of the bounds outlined by the protocol specification would make its use challenging if not impossible. This was considered (at least by me personally) a major problem, the most severe issue that had to be resolved lest the protocol would never find its way outside of the domain of small drones.
Now, here is the example. Consider that we have to integrate two motor controllers that accept their inputs using the message uavcan.equipment.esc.RawCommand
and report their status information using the message uavcan.equipment.esc.Status
. The data flow diagram for both of them would look as follows:
uavcan.equipment.esc.RawCommand +--------------------+ uavcan.equipment.esc.Status
--------------------------------->| ESC |----------------------------->
data type ID: 1030 | (esc_index) | data type ID: 1034
+--------------------+
Each ESC is identified by its ESC index. A command message contains an array of setpoints; each ESC extracts the setpoint intended for it using the pre-configured index parameter. A status message identifies the source ESC by its index, while also carrying the node ID information which in this specific setting is redundant and not used by the application.
This (current) approach has several major issues, the most important of them being that the protocol merges data flows distributed across different nodes into the same logical channel referenced by the Data Type ID. The Data Type ID is used at the same time to also convey the data type information, thus fusing together two completely different levels of abstraction and creating severe usability issues. The resulting unified data flow is then to be parsed and split by each node separately, which creates scalability and latency issues. The problem becomes even more severe in certain other application scenarios. For example, the standard message uavcan.equipment.gnss.Fix2
(notice the versioning kludge added out of necessity) requires that there be no more than one GNSS receiver per node. A benign-looking definition uavcan.equipment.device.Temperature
fuses together completely different data streams: an outside air temperature would end up on the same logical data channel with a CPU temperature, requiring each subscriber to carefully sift through the message stream to pick up what’s needed and to ignore the rest. The go-to approach to that problem was to create more narrowly-specialized types to avoid unnecessary data flow unification.
As I said above, that was identified to be the worst problem with the protocol v0. The solution that we are introducing in v1 is to add an additional abstraction layer which untangles message types from physical processes they describe. With the new framework, the ESC data flow problem could be approached as follows:
uavcan.si.angular_velocity.Raw +--------------------+ uavcan.si.angular_velocity.Timestamped
-------------------------------->| ESC 0 |-------------------------------->
subject ID: 100 | | subject ID: 201
| |
| | uavcan.si.voltage.Timestamped
| |-------------------------------->
| | subject ID: 301
| |
| | uavcan.si.current.Timestamped
| |-------------------------------->
| | subject ID: 401
| |
| | uavcan.si.temperature.Raw
| |-------------------------------->
| | subject ID: 501
+--------------------+
uavcan.si.angular_velocity.Raw +--------------------+ uavcan.si.angular_velocity.Timestamped
-------------------------------->| ESC 1 |-------------------------------->
subject ID: 102 | | subject ID: 203
| |
| | uavcan.si.voltage.Timestamped
| |-------------------------------->
| | subject ID: 303
| |
| | uavcan.si.current.Timestamped
| |-------------------------------->
| | subject ID: 403
| |
| | uavcan.si.temperature.Raw
| |-------------------------------->
| | subject ID: 503
+--------------------+
The new framework avoids the problem of data flow unification completely, thus obviating the need for esc_index
and related instance identifiers (such as sensor_id
and so on). Each ESC has its own separate Subject ID for each incoming and outcoming data stream. The subject ID values are not standardized, and each application is free to choose them arbitrarily. Cross-vendor and cross-application compatibility for COTS hardware will be achieved through manual or automatic pre-configuration of Subject Identifiers.
The new specification will likely introduce an optional recommendation (convention) to assign even values of Subject ID for data streams carrying commands, and odd values of Subject ID for data streams carrying state estimates (such as sensor measurements and other actionable data).
The implications of the change are major, and it is recognized that the transition to v1 will make the life of early adopters hard. Further, it is also understood that the new protocol does not have the same level of support for common applications, and truly plug-and-play nodes will be harder to implement, at least until there are additional higher-level provisions for that (could be added in v1.1 perhaps?). The move also reflects our commitment to provide better support for vendor-specific and application-specific closed ecosystems.
I hope the above was a satisfactory description of the upcoming changes and I also hope that I didn’t forget anything important. My fine colleagues @kjetilkjeka and @scottdixon might add corrections or amendments later in this thread.