Robohub.org
 

Configuring multiple USB devices: An alternative to udev


by
16 December 2015



share this:

USB_iconsEvery time I need to add multiple USB devices to a computer I get nervous and dread the architecture. The problem is that when a computer boots it automatically brings up USB devices in whatever order it sees fit (think crazy race conditions). So if you have a motor controller, a camera, and a LIDAR that all use USB, it can be difficult to know which device on the computer is which. You could check and manually change these every time you run your programs, but it’s better to have your programs auto-detect which device to connect to.

There are some specialty cases that can make this problem easier. Most USB devices (in Linux) show up as /dev/ttyUSBX, where X is the number in which that device was initialized (ex. /dev/ttyUSB0). Some devices will come up differently. For example Hokuyo LIDAR’s show up as /dev/ttyACMX. And USB joysticks show up as a joystick device in /dev/input/jsX. So if you have one each of a joystick, a Hokuyo, and a motor controller, you might get lucky and have them all map to different devices. But for the many times you are not lucky, how should you deal with it?

(Random note: ACM refers to a USB modem. Most devices that we use are not really modems and just ‘lie’ and claim to be an ACM device (often when they do the USB “stuff” on the main processor). Many USB-to-serial converter chips (such as FTDI) do not lie and show up as /dev/ttyUSB.)

The traditional answer is to use udev rules. The basic idea is to make a file in /etc/udev/rules.d/ that will control how a device gets mapped and started. This allows you to change the links, change permissions, or run a script when a device is detected. A basic udev rule can follow the format of:

SUBSYSTEMS==”usb”, KERNEL==”ttyACM[0-9]*”, ACTION==”add”, ATTRS{idVendor}==”15d1″, ATTRS{idProduct}==”0000″, MODE=”666″, PROGRAM=”/opt/ros/hydro/lib/urg_node/getID /dev/%k q”, SYMLINK+=”sensors/hokuyo_%c”, GROUP=”dialout”

A great tutorial on udev (and also where I got the rule above) is the “Do more with udev” tutorial from Clearpath Robotics.

In my experience using udev rules work well to set startup permissions (to allow non-root access to the device) or to run a script when a device is connected. However the symlink that maps a device to a specific name will sometimes create a link that you cannot open (ie. when open(/dev/newSymLink) fails). There are also cases where you cannot use udev in certain embedded systems or where you do not want to “install” udev rules.

There are several ways to avoid using udev. For example you could run the dmesg command to find where the USB device was connected. Another way is to have a script run whenever a device is plugged in that updates a text file that stores the device name.

Another solution (presented below) is ugly but it has tested well in cases where udev was giving me a hard time. The solution below is easier than parsing dmesg and does not require a udev rule to create a symlink that needs to be installed.

The first step, which I got from here, gets the mapping of all your devices and the associated port numbers.

#!/bin/bash
for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do
(
syspath=”${sysdevpath%/dev}”
devname=”$(udevadm info -q name -p $syspath)”
[[ “$devname” == “bus/”* ]] && continue
eval “$(udevadm info -q property –export -p $syspath)”
[[ -z “$ID_SERIAL” ]] && continue
echo “/dev/$devname – $ID_SERIAL”
)
done

Running the script above will give you a list of all the attached USB devices. You can save the script above into a file called list_usb_devices.sh.

The next step is to run that script from your program. To do that I found some code that allows you to run a system call and get the output into a string.

#include <string>
#include <iostream>
#include <cstdio>
#include <memory>

std::string system_exec(char* cmd)
{
std::shared_ptr pipe(popen(cmd, “r”), pclose);
if (!pipe) return “ERROR”;
char buffer[128];
std::string result = “”;
while (!feof(pipe.get())) {
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
return result;
}

Adding the above to the driver for the USB device, you can now use the following to get the port that you need to open:

// get the names, grep to search for the device we want, cut the name of the port from the full line of text
std::string port = system_exec(“//list_usb_devices.sh |grep -m 1 |cut -c 1-12″);

// Get rid of any newlines (n) in the string
port.erase(std::remove(port.begin(), port.end(), ‘n’), port.end());

// switch to string to c style for using in the open command
const char * device = port.c_str();

// Finally we can now open our device
fd = open(device, O_RDWR | O_NOCTTY);

This approach is ugly, but it works. By simply using the bash script and the system call from the c++ portion you can easily adapt this to any programming environment.

The above approach is often the wrong approach (since it is ugly), but it can help when udev is not working as expected or it can not be used.

I still avoid using USB devices when possible since they are a pain and are often not reliable. However if you must use them, then the information above **might** make your life a little better. I hope it helps! Please leave comments below if this helped you or with other ways to handle USB devices.

 

 



tags:


Robots for Roboticists David Kohanbash is a Robotics Engineer in Pittsburgh, PA in the United States. He loves building, playing and working with Robots.
Robots for Roboticists David Kohanbash is a Robotics Engineer in Pittsburgh, PA in the United States. He loves building, playing and working with Robots.


Subscribe to Robohub newsletter on substack



Related posts :

Robot Talk Episode 148 – Ethical robot behaviour, with Alan Winfield

  13 Mar 2026
In the latest episode of the Robot Talk podcast, Claire chatted to Alan Winfield from the University of the West of England about developing new standards for ethics and transparency in robotics.

Coding for underwater robotics

  12 Mar 2026
Lincoln Laboratory intern Ivy Mahncke developed and tested algorithms to help human divers and robots navigate underwater.

Restoring surgeons’ sense of touch with robotic fingertips

  10 Mar 2026
Researchers are developing robotic “fingertips” that could give surgeons back their sense of touch during minimally invasive and robotic operations.

Robot Talk Episode 147 – Miniature living robots, with Maria Guix

  06 Mar 2026
In the latest episode of the Robot Talk podcast, Claire chatted to Maria Guix from the University of Barcelona about combining electronics and biology to create biohybrid robots with emergent properties.

Developing an optical tactile sensor for tracking head motion during radiotherapy: an interview with Bhoomika Gandhi

  05 Mar 2026
Bhoomika Gandhi discusses her work on an optical sensor for medical robotics applications.

Humanoid home robots are on the market – but do we really want them?

  03 Mar 2026
Last year, Norwegian-US tech company 1X announced “the world’s first consumer-ready humanoid robot designed to transform life at home”.

Robot Talk Episode 146 – Embodied AI on the ISS, with Jamie Palmer

  27 Feb 2026
In the latest episode of the Robot Talk podcast, Claire chatted to Jamie Palmer from Icarus Robotics about building a robotic labour force to perform routine and risky tasks in orbit.

I developed an app that uses drone footage to track plastic litter on beaches

  26 Feb 2026
Plastic pollution is one of those problems everyone can see, yet few know how to tackle it effectively.



Robohub is supported by:


Subscribe to Robohub newsletter on substack




 















©2026.02 - Association for the Understanding of Artificial Intelligence