I propose adding control channel data reception to the DroneCAN protocol. This post is a collaboration between Hydra and myself.
This is a common use case, and would be a good fit for various vehicle types that use DroneCAN. I’m also interested in Cyphal support, but will focus on DroneCAN for now. I have concerns about Cyphal’s complexity that may delay or preclude using it.
Requirements:
The device transmits control channel data with low latency. The canonical use case is a radio transmitter connected to a manual controller, with 4 high-resolution channels for pitch, roll, yaw, and throttle, and several more lower-resolution "aux" channels assoc. The aux channels are intended for buttons, and switches that have fixed positions. They might be used for changing flight mode, cycling steer points, activating payloads, arming motors etc. This is an example use and is common, but a more general solution is desired.
The device sends link statistics, such as RSSI, portion of packets received recently, transmitter nominal power level etc. Note on a general solution applies here as well.
The device sends metadata, including an immediate message if the link is lost. (Note: This could also be handled by the receiver, but I think a backup from the RF node itself would be nice) It may also send a periodic heartbeat containing system status.
I'm unclear on the exact capabilities of DroneCAN and Cyphal (especially the latter), and use cases that may arise. Below are two starting example implementations, that represent different ends of a flexibility spectrum. They would both be sufficient for the canonical use case described above, but different in applications beyond it:
#1: A simple, partially hard-coded standard, analogous to the CRSF protocol. I imagine this will integrate in a straightforward way with DroneCAN. I’ve put this together by following examples on the DroneCAN List of standard data types. Of note, it sends all control channel data in the same packet, without distinguishing priority.
uint16 [<=10] channel_high_precision # High precision channel data. For example, throttle or pitch
uint8 [<=10] channel_low_precision # Low precision channel data. For example, arm status or flight mode
Of note, I’m not sure how to make precision flexible using the example standard data types; in this example, I’ve hard-coded 2 precision levels. Compared to existing standards that use 11-13 bits of data for control channel data, this is higher precision, so uses more bandwidth/larger packet size than required. How would you handle this, using the DroneCAN spec?
Example link stats packet, sent at a slower rate, hard-coded values and precision; this is what CRSF uses. I am not proposing it specifically, but it’s an example of hard-coding, using a current standard. Of note, it is inflexible:
If the link is lost at any point, the node immediately broadcasts a terse message of high priority.
#2: An ideal, flexible standard. I would prefer something like this, but am not sure if it fits the model of DroneCAN and/or Cyphal:
By default, the node is silent. The entity receiving data (eg flight controller) submits a discovery request. The Rx responds with a list of information it can supply, including channel indices, available resolutions, and available data rates for each channel. Given this info, the FC can choose which info it wants to receive based on the Rx’s capabilities, which it knows due to the response to discovery. The subscribe request will always succeed, since the flight controller has the information it needs to make it.
Example of available information: #1: The channel number (to be interpreted by the Rx node). #2: Data rate. #3: resolution. The node responds with a success or error message, per its ability to serve this request. If success, the node broadcasts the data as requested until it receives a cancellation request. Example subscription request:
[
Subscription index/reference = 1,
<12 bits of data for channel 1>,
<12 bits of data for channel 2>,
]
[
Subscription index/reference = 2,
<2 bits of data for channel 5>,
]
[
Subscription index/reference = 3,
<2 bits of data for channel 6>,
<1 bits of data for channel 17>,
<1 bits of data for channel 18>,
]
The sequence of packets will be:
1,1,1,1…,2,1,1,1…,2,1,1,1… eventually 3,1,1,1…, 2,1,1,1…
The flexible approach would be robust to changing requirements for different use cases, and allow the subscriber (eg flight controller) to only receive the data it needs, at the rate it's capable of receiving. It would minimize the amount of data sent, saving bandwidth. Of note, the FC could make multiple subscriptions, each with a reference that is included in the subscribe request; the same reference is returned when the Rx sends data, so the FC knows what data, and the format of it for decoding purposes.
I think some combination of the approaches may be viable. For example, a flexible subscription setup, but restricting the number of data rates to 2.
Of note, I think for many cases of channel data, 2+ frames may be required on FDCAN. If this addition is made available for basic CAN, multi-frame packets would be required in all cases. This begs the question: Should this be backwards compatible with basic CAN, or should it be FDCAN only? Suggested approach: A discovery agreement between the Rx and FC, allowing either to be used. The subscribe can choose the frame format (CAN/FDCAN) too.
Would appreciate any and all input on establishing a standard that’s simple and flexible. Of note, I already have a working CAN receiver, using an ExpressLRS circuit integrated with an STM32 MCU that acts as the FDCAN node, and a CAN transceiver. Using this for specific hardware where both Rx and flight controller are cooperative is easy; my intent here is establishing a common API that will allow CAN Rxes to be swapped arbitrarily, with no change to flight-controller code.
I propose adding control channel data reception to the DroneCAN protocol. This post is a collaboration between Hydra and myself.
This is a common use case, and would be a good fit for various vehicle types that use DroneCAN. I’m also interested in Cyphal support, but will focus on DroneCAN for now. I have concerns about Cyphal’s complexity that may delay or preclude using it.
Requirements:
The device transmits control channel data with low latency. The canonical use case is a radio transmitter connected to a manual controller, with 4 high-resolution channels for pitch, roll, yaw, and throttle, and several more lower-resolution "aux" channels assoc. The aux channels are intended for buttons, and switches that have fixed positions. They might be used for changing flight mode, cycling steer points, activating payloads, arming motors etc. This is an example use and is common, but a more general solution is desired.
The device sends link statistics, such as RSSI, portion of packets received recently, transmitter nominal power level etc. Note on a general solution applies here as well.
The device sends metadata, including an immediate message if the link is lost. (Note: This could also be handled by the receiver, but I think a backup from the RF node itself would be nice) It may also send a periodic heartbeat containing system status.
I'm unclear on the exact capabilities of DroneCAN and Cyphal (especially the latter), and use cases that may arise. Below are two starting example implementations, that represent different ends of a flexibility spectrum. They would both be sufficient for the canonical use case described above, but different in applications beyond it:
#1: A simple, partially hard-coded standard, analogous to the CRSF protocol. I imagine this will integrate in a straightforward way with DroneCAN. I’ve put this together by following examples on the DroneCAN List of standard data types. Of note, it sends all control channel data in the same packet, without distinguishing priority.
Example packet, using the DroneCAN List of standard data types:
Of note, I’m not sure how to make precision flexible using the example standard data types; in this example, I’ve hard-coded 2 precision levels. Compared to existing standards that use 11-13 bits of data for control channel data, this is higher precision, so uses more bandwidth/larger packet size than required. How would you handle this, using the DroneCAN spec?
Example link stats packet, sent at a slower rate, hard-coded values and precision; this is what CRSF uses. I am not proposing it specifically, but it’s an example of hard-coding, using a current standard. Of note, it is inflexible:
#2: An ideal, flexible standard. I would prefer something like this, but am not sure if it fits the model of DroneCAN and/or Cyphal:
By default, the node is silent. The entity receiving data (eg flight controller) submits a discovery request. The Rx responds with a list of information it can supply, including channel indices, available resolutions, and available data rates for each channel. Given this info, the FC can choose which info it wants to receive based on the Rx’s capabilities, which it knows due to the response to discovery. The subscribe request will always succeed, since the flight controller has the information it needs to make it.
Example of available information: #1: The channel number (to be interpreted by the Rx node). #2: Data rate. #3: resolution. The node responds with a success or error message, per its ability to serve this request. If success, the node broadcasts the data as requested until it receives a cancellation request. Example subscription request:
Example responses here. E.g.
The sequence of packets will be: 1,1,1,1…,2,1,1,1…,2,1,1,1… eventually 3,1,1,1…, 2,1,1,1…
The flexible approach would be robust to changing requirements for different use cases, and allow the subscriber (eg flight controller) to only receive the data it needs, at the rate it's capable of receiving. It would minimize the amount of data sent, saving bandwidth. Of note, the FC could make multiple subscriptions, each with a reference that is included in the subscribe request; the same reference is returned when the Rx sends data, so the FC knows what data, and the format of it for decoding purposes.
I think some combination of the approaches may be viable. For example, a flexible subscription setup, but restricting the number of data rates to 2.
Of note, I think for many cases of channel data, 2+ frames may be required on FDCAN. If this addition is made available for basic CAN, multi-frame packets would be required in all cases. This begs the question: Should this be backwards compatible with basic CAN, or should it be FDCAN only? Suggested approach: A discovery agreement between the Rx and FC, allowing either to be used. The subscribe can choose the frame format (CAN/FDCAN) too.
Relevant discussion on the TBS github; about improving the CRSF spec, but is immediately applicable here: https://github.com/tbs-fpv/freedomtx/issues/26#issuecomment-1435738854
Would appreciate any and all input on establishing a standard that’s simple and flexible. Of note, I already have a working CAN receiver, using an ExpressLRS circuit integrated with an STM32 MCU that acts as the FDCAN node, and a CAN transceiver. Using this for specific hardware where both Rx and flight controller are cooperative is easy; my intent here is establishing a common API that will allow CAN Rxes to be swapped arbitrarily, with no change to flight-controller code.