Setting Up udev rules for multiple canbus interfaces

Apologies for posting in General Discussion, but I don’t seem to be able to put this in the “Knowledge Base” category with my account privs…

A multiple-instance Klipper install is when a single host is configured to serve more than one printer at once. Each instance will have one or more associated mcus. These mcus may be connected in any of the normal ways—serial, usb, or canbus. Multi-mcu instances may have a combination of any of the above connection methods, or may have multiple mcus connected via either a single or multiple canbusses. (Oh my!)

One of the least hardware intensive methods to connect multiple multi-mcu instances is probably to place an mcu into “canbus bridge mode.” This would result in each instance having its own usb-canbus adapter connected to the host. (Note, connecting an mcu via canbus bridge mode without at least one additional mcu on its canbus will be unstable and is not advisable. A single mcu should be connected via either serial or usb and addressed using its /dev/serial/by-id/ path.)

Mosts hosts will automatically name the first canbus bridge “can0,” and additional bridges as “can1,” “can2,” etc, using a system called udev. For a general introduction to the udev system, you might want to scan Writing udev Rules. However, without additional configuration, these names can change depending on the order in which the usb-can bridges are connected, making them inconsistent and unreliable for addressing by different instances.

I couldn’t find any straightforward documentation on configuring Canbus with udev for multi-instance Klipper installs, so I cobbled together the following and wanted to share in the hope it may be useful to others. In multi-instance installs, where each instance has its own canbus (aka bridge mode mcu), consistent names become necessary to ensure each instance is connected to the appropriate printer.

These instructions were written on Debian running on x86_64, but should be applicable to Armbian systems as well. For rpios, you may need to use an ifconfig command in step 6’s up directive in lieu of the ip command :man_shrugging:t2:.

Setting Up Canbus with Udev

  1. Plug your canbus device (probably an mcu in canbus bridge mode or a u2c) into an available usb port. It’s easiest to start with a single usb-can device plugged in. The system will most likely autoname this device “can0”—you can check by running ip link show.

  2. Run udevadm info -a -p $(udevadm info -q path -p /sys/class/net/can0)| grep serial| head -n 1

  3. The above command should print something like ATTRS{serial}=="490033000F50475532323820". We’ll refer to this value as YOUR_SERIAL in subsequent steps.

  4. Open /etc/udev/rules.d/z21_persistent-local.rules in your editor of choice

  5. Subtitiuting the serial number you found in step 3, add the following line. (Since your system likely automatically assigns names such as “can0,” “can1,” “can2” etc to canbus devices, use a string such as “canalpha,” “canbeta,” or “cangamma” for YOUR_CHOSEN_CANBUS_NAME):

SUBSYSTEM=="net", ACTION=="add", ATTRS{serial}=="YOUR_SERIAL", NAME="YOUR_CHOSEN_CANBUS_NAME"
  1. Open /etc/network/interfaces.d/YOUR_CHOSEN_CANBUS_NAME in your editor of choice, and insert the following text, substituting the canbus name you created in step 5:
allow-hotplug YOUR_CHOSEN_CANBUS_NAME
iface YOUR_CHOSEN_CANBUS_NAME can static
    bitrate 1000000
    up ip link set $IFACE txqueuelen 128
  1. Run sudo udevadm control --reload-rules && sudo udevadm trigger --attr-match=subsystem=net and then unplug and replug your can device

  2. Run ip -details link show YOUR_CHOSEN_CANBUS_NAME and you should see your device listed under the appropriate interface name, with the correctly configured queue length (qlen) and bitrate.

  3. You may repeat the steps 1-8 to add additional busses. It seems to work fine to have multiple lines in the udev rules file created in step 4, or if you prefer, you may split the udev rules into multiple files (all in /etc/udev/rules.d/). A reboot isn’t strictly necessary, but if you like to by all means do!

Klipper/ Katapult Config

Once the interface is properly configured as above, you can simply add a canbus_interface: YOUR_CHOSEN_CANBUS_NAME line to your [mcu] object in your printer.cfg that lists the named interface you just created.

If you use katapult, you’ll also need to use the -i YOUR_CHOSEN_CANBUS_NAME option when your run flash_can.py to set the appropriate interface.

Cheers!

Before it goes up on the Knowledge Base, could I request the following clarifications? I believe I understand what you are doing here but there are some things that I don’t find clear.

  1. Is this for multiple CAN adapters/buses or for multiple CAN devices on a single bus? I believe it’s for the former but it would help if it was explicitly spelled out.
  2. I believe “{YOUR_CHOSEN_CANBUS_NAME}” is “can0”, “can1”, etc. This goes back to the previous point.
  3. If you are doing multiple CAN adapters/buses do all 8 steps you’ve listed have to be run? Should there be a reboot on your host in between them (Actually, rereading the list, you note that in step 7. - Can I suggest you make that into a separate step so it’s more clear)?
  4. What is {serial}? On the same note, I believe “{YOUR_SERIAL}” is the value shown from the ip link show command - correct?

Sorry, I just want to make sure I’m clear on what you’re doing.

Thanks so much for the feedback as always! I made a few edits that hopefully clarify things a bit, and included a link to a good introduction to the udev system for folks as unfamiliar with it as I was.

2 Likes

That looks much better - great job!

2 Likes

Thanks for writing up this information.

Just to be clear, a Klipper mcu configured in “usb to canbus bridge mode” must be attached to a functional canbus with at least one real canbus device on it. If one were to configure Klipper in “usb to canbus bridge mode” solely to communicate with that mcu, then the connection will be unstable - it may work for a few hours, but it will be prone to sporadic (hard to debug) failures.

Cheers,
-Kevin

1 Like

Good to know… I added it as a note for clarity.

Thanks for this write up. A nice explanation on using udev for this purpose. :+1:

I was always hoping someone takes the effort to write up something on CAN in general and its different usage scenarios, e.g. when to use “usb to canbus bridge mode”, its differences, how it ties in with Katapult etc.

I do not have much experience with CAN as I do not use it, so I’m not a good source.

I’ll gladly add it to the KB. FWIW, it might seem a bit lost as the only CAN related topic there, but still good information.

Thanks Sineos!

I’ll try and write an article or two over the next few days that provide more context for the KB. MCU updates do become a little more complex with multi-mcu so I’ll try and cover that as well.

1 Like