So, this is an idea I’ve had in my mind for some time that I’ve been trying to bring to fruition but have hit a brick wall on.
Basically: a single USB to CAN interface in an external klipper host box running multiple instances of klipper via KIAUH, with a connection that heads off to multiple printers (for instance, daisy chaining), each with potentially multiple MCUs of their own.
I’ve been running a single printer on a CAN link for quite a while now and it’s been working well, with the motherboard as one CAN device, and a display module in front with an RP2040 as a second device. Probably have run that setup and similar for ~150 hours of print time so far (until recently on literally a hand-twisted bit of wire with termination resistors on only one side, which also worked fine somehow)
But the problems started when I finally actually tried to test having multiple klipper instances, each with their own device, but on the same can0 interface. Which, for some reason, I didn’t think to test before going 75% of the way down this route…?
And the problem: commands like FIRMWARE_RESTART
target the whole bus, regardless if the MCU is actually of the UUID listed in the config. I guess it just does a broadcast, or whatever the CAN equivalent is. When issuing a restart command for one klipper instance, it kills the other one in the process. [EDIT: This is overthinking it, see a few posts down] In general the two can’t seem to coexist. Sensible for 99.95% of use cases, but then I came along.
Drat.
I don’t really expect a solution – I mostly wanted to talk about my weird use case that didn’t work.
Interesting - I would have expected things to work the same way as having multiple printers connected to a single host via USB. I suspect that the issues are largely due to a configuration like this never been tested.
I know there are people who run toolheads with USB rather than CAN, I don’t know of anybody who runs multiple printers with this configuration (ie multiple USB devices used for each of several printers - which should be the same situation here, multiple CAN devices used for each of several printers).
CAN is a very robust communications standard, I’m not surprised that your hand wound, improperly terminated bus works (with a master and single slave) if the distance was a metre or two.
Yeah… that’s what I had hoped. But I guess the CAN handling is such that it expects the whole bus to be confined within one machine. I am poking through the source code to see if I can determine some sort of tweak that could be made but it’s probably not worth pursuing too far alas.
Keep us posted as to what you find.
Unfortunately I’m not super familiar with the structure of Klipper’s source and it’s pretty dense to read so I’m a bit clueless in here.
I am realizing some more trouble this is having as part of some knock-on effects - I intended to have a display module on each printer, identical to one another, just connecting to the same bus over CAN. But if I can’t put them on the same bus, and instead need multiple USB to CAN interfaces, then I end up having to define multiple network devices on the linux side. Doable, but a bit annoying to scale compared to what I was hoping.
I do really like the ability to have multiple MCUs per printer, and multiple instances of klipper on the same host, but I have had a habit of flying a bit too close to the sun here.
Actually, I’m not sure how to even tie a specific interface to a specific device. Like, one of them forms the adapter to can0
, the other to can1
etc…
I’ve been thinking about this some more as I dig through the code and realized that the answer here is simple, and staring me in the face. Klipper has absolutely no way to comprehend that two instances of itself would be trying to communicate over the same CAN connection, so I assume it’s just not able to handle any sort of message scheduling or what have you and completely collapses. It’s not the reset command, it’s the fundamental nature of the thing here.
Checking klippy.log, immediately after I bring a second instance+CAN device online, it goes crazy - the bytes_invalid counter skyrockets before it can’t sustain a connection anymore and shuts down.
Again: drat. Double drat even.
Just thinking about it, I think I understand why: it’s due to the need to support the CAN bridge in the main controller board.
Can @koconnor or any of the developers comment?
I have something of a workaround, at least on the grounds of having multiple USB to CAN interfaces present at once with their own IDs. I wrote a systemd network file /etc/systemd/network/10-usb-canbus.link
with the following content:
[Match]
Property=ID_VENDOR=Klipper ID_SERIAL_SHORT=E6614C309316842A
[Link]
Name=can_e6614c30931
It picks out the USB device based on the Klipper vendor ID and its serial listing and assigns it a unique ID specified below. The problem is this is fully manual so would have to be updated for any change in adapter. Doable, it just would be nice to autoname it. The NamePolicy
option is built entirely around assuming it’s an ethernet adapter unfortunately so I couldn’t get it to auto-generate a name for it. The one above is also specifically an RP2040 in USB to CAN mode, I don’t know if other ones have the same serial identifier. It might need to be set up case-by-case anyway depending on that.
Regardless of that then I put the defined interface name in the canbus_interface
option under the [mcu]
config block:
[mcu]
canbus_uuid: c96b2bea26b2
canbus_interface: can_e6614c30931
So, if I can’t have my single unified CAN network, I can still have multiple interfaces coexisting, hopefully.
edit - Something I forgot to mention I gleaned from the source/docs is that there are a number of “admin” messages that get sent out on the bus, which ALL nodes will intercept and respond to. They don’t normally get sent out except during initialization I think, so if one randomly shows up to a running node in a different instance it’s going to be a mess.
1 Like
It’s not currently possible to run multiple separate printers that use the same canbus. Doing so would require code changes, and for what it is worth, implementing that seems like it adds long-term maintenance costs for too small a niche use case. (If you’re interested in playing with the code, you’ll need to look at how Klipper assigns a unique canbus_nodeid
to each node ( CANBUS protocol - Klipper documentation ) ).
In contrast, it should be possible to bring up multiple canbus interfaces - one per printer. One needs to make sure the Linux can interface names are stable and supply those interface names in each printer.cfg file (as it seems you have figured out).
Cheers,
-Kevin
2 Likes
I appreciate the response. That’s what I had been figuring from my digging and poking. I guess it would require a fundamental change in how the “admin” messages are handled on the bus among other things. Part of me wants to try it, but I know the sensible thing is to just bow out gracefully and return to a more traditional setup.
On the other hand, maybe the bit about giving each CAN adapter a unique name in the OS will prove useful to someone. By default it seems that it tries to interpret it as a USB ethernet adapter, so one of the preexisting systemd link files catches it, tries to name it based on MAC address, then can’t do so and rejects it, leaving it named as can0
.
I was hoping to try and get them to automatically be named without needing an entry for each individual one, but I can’t quite figure that out. The NamePolicy
setting only has a few choices, and none of them seem to work with the adapter.
But it’s something that could easily be done as a script, so I might give that a try later as well.