CNC machine control

Hi UAVCAN community!

I really like your protocol, design and philosophy.

I intend to use UAVCAN for my latest machine controller and am seeking community input into the protocol design, potentially co-conspirators and ideally (I am assuming this work is applicable to others as well) standardisation within a SIG!

The high-level project goals are:

  • Develop a machine controller focussed on pre-planned tightly-synchronised multi-axis motion
  • Focus on high-power servo motors suited for CNC machines, but also applicable to high-performance 3D printers (and perhaps the next generation of super-light direct-drive extruders)
  • Create a control and driver board providing a similar level of “plug-n-play” functionality as a smoothieboard or duet do for 3D printers
  • Make the system expandable and future-proof, while maintaining a low barrier to entry for other developers to launch into

In more tangible terms and for illustration’s sake, I intend to slap 6 (5 axes + spindle) servo controllers and a raspberry pi onto a board, glue it all together with CAN and use it as a CNC machine controller and keep the cost below what you’d normally pay for two “low-cost” servo drivers, without all the added fuss, looming and know-how required to string a normal control cabinet together.

Intended control scheme

A big key to this project is to remove the central real-time controller. I was partially inspired into this thought by the Klipper project around the start of 2019. I have not yet decided whether I will recycle some of it’s main components.

  • Path planning using a more powerful machine and high-level language (python) and not in real-time, which means it can be done under linux
  • These paths (represented as polynomials) will be transmitted to the CAN network using UAVCAN
  • Each axes controller collects it’s instructions from the bus and follows them closely as possible with it’s motor.
  • Time will be synchronised across devices using UAVCAN’s existing scheme
  • Devices are assigned a node ID based on their position on the board; for example by using a divider on an analog pin which acts as startup configuration. This means the same software can be deployed to all axes
  • Other functions (GPIO, temperature etc…) is all transmitted to the same CAN bus.
    • Configuration describes what each function (“stop”) should be bound to (“limit switch x+”).
    • There’s no limit to how many functions can be bound to a piece of data; a probe input should be bound to “stop” on all motion axes.
    • There’s only a practical limit (e.g. array size) to how many data bindings can be made for a given function; “limit switch x+”, “probe” and “control panel stop” can all be bound to each servo’s “stop” function
    • These bindings are interpereted by a pre-processor, using intelligble names for the data bindings and functions, but boiled down to discrete bounded configuration along the lines of “axis 1, stop when: limit switch x is high, probe is high or stop input is high. axis 1, reset position to 0 when: limit switch x+ is high” ect…
    • The above node assignment means that devices can listen for the configuration relevant to them

Message types

So far, my approximate message types list I intend to create and perhaps standardise (pending community enthusiasm) is:

  • Path: x, v, a, j + end time
  • Input state: input ID + state
  • Function bindings: node ID (and perhaps “all”/wildcard), function ID (ideally standard enumeration), data bindings (array, input IDs + state)

I’m looking forward to your feedback.

Thank you for such a beautiful design

1 Like

Hi @mawildoer! I am not that well-versed in CNC but UAVCAN might be a good fit here, indeed, seeing as it is a real-time distributed system implementing potentially complex behaviors.

It might be related to the automatic generation of application-layer interfaces from DSDL definitions. The issue was first raised in High level node descriptor. One unnamed company that launches batches of micro-satellites into LEO implemented something of that variety internally, although they decided to keep their developments private. My point is that this question comes up regularly and it might be possible to find contributors to this feature in other domains outside CNC.

Your mentioning of function identifiers and instance identifiers looks a little concerning in this context. Maybe you should have a look at The UAVCAN Guide (if you haven’t already), where our vision of an optimal UAVCAN-based service-oriented design is explained in detail.

We have forwarded a link to this discussion to our local friends from, who may or may not be interested in a collaboration. (tagging @j3qq4hch)


@pavel.kirienko, you have hit the nail on the head with the GPIO issue. I have read the UAVCAN Guide, but haven’t yet come up with a decent way to implement this type of GPIO as “as a service” per-say. This is certainly a section of design I am seeking advice and perhaps some workshopping on.

Currently, I’m working on a CAN-FD implementation for the STM32 HAL, but simultaneously, it’d be great to spitball some ideas of how to better implement the messaging structures.

The main issue I’ve had is that the nodes do not know what their data will be used for (ie they don’t know they’re attached to a limit switch for the x-axis).
Perhaps we can still define some kind of data -> function configuration message, but in another more UAVCANian format?

A driver for STM32’s FDCAN would be highly welcome at, if you can share it and if you are open to ditching the HAL (due to its low quality and a large number of software defects).

Segregate functions by subject-ID. Say, you have three axes, one switch on either side, six total. Suppose you define a message that models the limit switch states on a given axis like this:

int2 limit
@extent 64 * 8

Then, say, the X-axis limit switch states would be published at subject-ID 5000, Y at 5001, Z at 5002. I’m not sure if the example makes sense from the business logic perspective but it should communicate the main idea: treat subject-IDs as variable names.

Oh my god, and the documentation! The whole thing is a pile of garbage [bangs head on desk]. I am aware of the repo and certainly planned on uploading my work as soon as I had anything functional to save the next person in line the trouble.

So I considered this as the go-to first port of call. The issue I hit was expandability. I want to be able to add a switch to the bus without having to include a USB port on it to configure it as “limit switch X”. I have seen an example where during configuration you were asked to spin the motor of the relevant ESC, so it could be identified. Perhaps something more along these lines of “flick the switch” would suit better.

1 Like

Maybe, but you can always use UAVCAN itself to configure the device. It is sufficiently self-reliant to avoid the need for a secondary configuration interface.