Hybrid architecture: Cyphal/UDP for management + raw UDP on MCU

Hi all,

We’re designing comms for a few embedded sensor modules (Cortex-M, FreeRTOS, lwIP) that stream sensor data at ~5 Mbps per node to a Linux host. The modules also need device management (config, status, firmware update). We have separate CAN FD nodes doing similar things (with smaller payloads) in the same system.

We’re considering using Cyphal in a hybrid approach:

  • Raw UDP for high-bandwidth sensor streaming (simple binary frames, low overhead)
  • Cyphal/UDP for device management (heartbeat, registers, firmware update via file transfer)
  • Cyphal/CAN on the CAN FD nodes, sharing the same DSDL definitions

However, we don’t have experience with Cyphal and have a few integration/real use questions:

  1. Is libudpard on a Cortex-M + FreeRTOS + lwIP target a common pattern? How mature is it compared to libcanard?
  2. Will we have issues running Cyphal/UDP alongside raw UDP sockets on the same lwIP instance?
  3. What’s the realistic RAM/flash footprint for Cyphal/UDP with a small set of services (node info, registers, file transfer)?
  4. How reliable is the file transfer service over UDP in practice? Any gotchas with dual-bank firmware update flows?
  5. Is the “Cyphal for management, raw UDP for bulk data” split a pattern anyone has used, or does it create unexpected pain?
  6. How seamless is sharing DSDL definitions across CAN and UDP transports in practice?

Any experience or pointers to reference implementations appreciated. Thanks!

Hi @fathom!

In the absence of details I can’t be certain but you might want to consider using Cyphal for your high-bandwidth sensor streaming as well. Chances are that you will have to implement at least some kind of protocol for your data feed, such as managing duplicates and/or reordering, perhaps some stream configuration, and Cyphal provides that at effectively zero cost. Here, zero cost means that if you were to craft a solution from scratch, it is unlikely to be significantly more efficient than Cyphal. Of course I could be wrong here since I don’t know the details but generally this holds.

Ignoring the above, you can of course use Cyphal concurrently with other protocols. It uses a single UDP port number of 9382; as long as the other protocols don’t need it, you will be fine.

If you are considering a new application and you are comfortable trying a newer, more interesting solution that is not yet stable, I would invite you to give this work a try instead of building on the existing libudpard:

Check out the README, it is very simple. The idea is that we’re building the next version of Cyphal called v1.1 that is backward-compatible with the stable parts of v1.0; this new version adds named topics with tunable reliability and service discovery. I presume you will be especially interested in the reliability part since you mentioned this in your post – this is not something that comes out of the box with Cyphal v1.0. Overall I would say that v1.1 brings a much, much better developer/integrator experience compared to v1.0, which makes sense since it’s based on years of experience of deploying and maintaining Cyphal systems in production.

The “stable parts” of Cyphal v1.0 include Cyphal/CAN, but notably not Cyphal/UDP – in v1.0 it is marked as experimental. There is at least one large adopter leveraging the experimental Cyphal/UDP and we are yet to discuss how we want to go ahead with that; we have basically two main options:

  1. Deprecate the experimental Cyphal/UDP completely in favor of the new UDP transport that is already implemented in Cy (the library linked above), libudpard v3, and PyCyphal v2.

  2. Keep the experimental transport, stabilize it under a different name. This will be done if someone is willing to support this work. Both transports will continue to exist but by default we will push new adopters to the new one.

Regarding the memory footprint, most applications tend to use under 32K of both ROM and RAM, but of course it heavily depends on your use. Maybe the best way to find out is to grab a demoboard and ask a coding agent to adapt one of the Cy examples for it, and then see how it goes.

DSDL is very cleanly separated from the protocol, to the point that it will no longer be part of the Cyphal Specification starting with v1.1 – from that release onwards, DSDL will become a standalone spec, while Cyphal will focus on communication only. This is to say that you shouldn’t expect any issues with sharing the same definitions across different transports. Another consequence is that DSDL is no longer the only data serialization format you can use with Cyphal. You can just as well pick nanopb or XDR or whatever you might be using in other parts of your system. Depending on your architecture, this can be significant.

Cyphal v1.1 is also not going to endorse any particular way of building applications; the standard data types will be removed from the core Spec. We might still maintain them as a separate standard; this hasn’t been discussed in depth yet; at any rate that will no longer be the core focus.

There’s reason to suspect that you might find this example useful:

You can run it locally over UDP or CAN to feel how it works.