Telling USB Serial Ports Apart with udev Rules

Old school serial bus is great for robot hacking. It’s easy and widespread in the world of simple microcontrollers, and it’s easy for a computer to join in the fun with a USB to serial adapter. In my robot adventures so far, it’s been used to talk to Roboclaw motor controllers, to serial bus servos, and now to laser distance scanners. But so far I’ve only dealt with one of them at any given time. If I want to build a sophisticated robot with more than one of these devices attached, how do I tell them apart?

When dealing with one device at a time, there is no ambiguity. We just point our code to  /dev/ttyUSB0 and get on with our experiments. But when we have multiple devices, we’ll start picking up /dev/ttyUSB1, /dev/ttyUSB2, etc. And even worse, there is no guarantee on their relative order. We might have the laser scanner on /dev/ttyUSB2, and upon computer reboot, the serial port associated with laser scanner may become /dev/ttyUSB0.

I had vague idea that a Linux mechanism called ‘udev rules‘ can help with this problem, but most of the documentation I found were written for USB device manufacturers. They can create their own rules corresponding to their particular vendor and product identification, and create nice-sounding device names. But I’m not a device manufacturer – I’m just a user of USB to serial adapters, most of which use chips from a company called FTDI and will all have the same vendor and product ID.

The key insight came in as a footnote of the XV-11 ROS node instructions page: it is possible to create udev rules that create a new name incorporating a FTDI chip’s unique serial number.

echo 'SUBSYSTEMS=="usb", KERNEL=="ttyUSB[0-9]*", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="sensors/ftdi_%s{serial}"' > /etc/udev/rules.d/52-ftdi.rules

Such a rule results in a symbolic link that differentiates individual serial devices not by an arbitrary and changing order, but a distinct and unchanging serial number.

In the screenshot, my serial port is visible as /dev/ttyUSB0… but it is also accessible as /dev/sensors/ftdi_AO002W1A. By targeting my code to the latter, I can be sure they’ll be talking on the correct port. No matter which USB port it was plugged into, or what order the operating system enumerated those devices. I just need to put in the one-time upfront work to write down which serial number corresponds to which devices, code that into my robot configuration, and all should be well from there.

This mechanism solves the problem if I use exclusively USB-to-serial adapters built from FTDI chips with unique serial numbers. Unfortunately, sometimes I have to use something else… like the LewanSoul serial bus servo interface board (*). It uses the CH341 chip for communication, and this chip does not have a unique serial number.

This isn’t a problem in the immediate future. One LewanSoul serial servo control board on can talk to all LewanSoul serial servos on the network. So as long as we don’t need anything else using the same CH341 chip (basically use FTDI adapters for everything else) we should be fine… or at least not worry about it until we have to cross that bridge.

(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s