Port Shifts Solution with udev
Using udev to Create Persistent Device Paths
1. Problem Statement: USB Port Shifting
In Linux, kernel-level device enumeration (e.g., for USB-to-Serial devices) is non-deterministic. A device like a Pixhawk may be assigned /dev/ttyACM0 on one boot and /dev/ttyACM1 on another, especially when other serial devices (like a RealSense camera) are present. This breaks static configurations in applications like ROS.
2. Solution: Persistent udev Symlinks
The udev subsystem manages the /dev directory. We can create a custom rule to identify a device by its unique, permanent hardware attributes (like idVendor and idProduct) and create a stable, persistent symbolic link (symlink) to it (e.g., /dev/pixhawk).
3. Prerequisites
- Root/
sudoaccess on an Ubuntu system. - The physical device (e.g., Pixhawk).
- A terminal.
Step-by-Step Guide
Step 1: Identify Device Hardware Attributes
- Connect the device to your computer.
- Identify its current kernel-assigned path.
ls /dev/ttyACM*(This might also be
ttyUSB*for other devices. Note the path, e.g.,/dev/ttyACM0). - Use
udevadmto query the device’s attributes. Replace/dev/ttyACM0with your device’s path.udevadm info -a -n /dev/ttyACM0 | grep -E "idVendor|idProduct|serial" -
Analyze the output. Find the attribute block for the main TTY device. Record the
ATTRS{idVendor}andATTRS{idProduct}values.# Example Output ATTRS{idVendor}=="26ac" ATTRS{idProduct}=="0032" ATTRS{serial}=="00000000001A"You must use the values from your command output.
Step 2: Create udev Rule File
- Create a new rules file in
/etc/udev/rules.d/. The99-prefix ensures it runs after system defaults.sudo nano /etc/udev/rules.d/99-pixhawk.rules
Step 3: Define the Rule
-
Paste the following line into the file, replacing
<VENDOR_ID>and<PRODUCT_ID>with the values you found in Step 1.KERNEL=="ttyACM*", ATTRS{idVendor}=="<VENDOR_ID>", ATTRS{idProduct}=="<PRODUCT_ID>", MODE:="0666", GROUP:="dialout", SYMLINK+="pixhawk"- Example Rule:
KERNEL=="ttyACM*", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0032", MODE:="0666", GROUP:="dialout", SYMLINK+="pixhawk"
- Example Rule:
- Rule Breakdown:
KERNEL=="ttyACM*": Match any device the kernel namesttyACM....ATTRS{...}: Filter to match only the device with this specific Vendor and Product ID.MODE:="0666": Set file permissions to read/write for all users.GROUP:="dialout": Assign group ownership todialout. ROS/Mavros users are typically in this group for serial port access.SYMLINK+="pixhawk": Create the persistent symlink at/dev/pixhawk.
- Save and exit the editor (in
nano:Ctrl+O,Enter,Ctrl+X).
Step 4: Apply and Verify the New Rule
- Reload the
udevrules:sudo udevadm control --reload-rules - Trigger the new rules to apply them to currently connected devices:
sudo udevadm trigger - Test by hotplugging: Unplug your device, wait a few seconds, and plug it back in. This is the most reliable way to verify the rule.
- Check if the symlink was created:
ls -l /dev/pixhawk- Success:
lrwxrwxrwx 1 root root ... /dev/pixhawk -> ttyACM0(or-> ttyACM1) - Failure:
ls: cannot access '/dev/pixhawk': No such file or directory(See Troubleshooting).
- Success:
Step 5: (Optional) Configure User Permissions
If your user (running ROS) does not have permission, ensure it is in the dialout group.
- Add your user to the group:
sudo usermod -a -G dialout $USER - IMPORTANT: Group changes only apply after you log out and log back in or reboot.
Step 6: Update Application Configuration (ROS Example)
Modify your ROS launch file (e.g., mavros/px4.launch) to use the persistent path.
- Before:
<param name="fcu_url" type="string" value="serial:///dev/ttyACM0:57600" /> - After:
<param name="fcu_url" type="string" value="serial:///dev/pixhawk:57600" />This ensures your application reliably connects to the Pixhawk, regardless of its kernel-assigned
ttyACMxpath.
Troubleshooting & Advanced Cases
- Rule Not Working:
- Double-check
idVendor/idProductfor typos in your.rulesfile. - Ensure you reloaded rules (
udevadm control --reload-rules) and re-plugged the device. - Check permissions. Ensure your user is in the
dialoutgroup (and you’ve logged out/in).
- Double-check
-
Multiple Identical Devices: If you have two identical Pixhawks,
idVendorandidProductare not unique. In this case, use theATTRS{serial}value (from Step 1) to differentiate them. ``` # Rule for device A KERNEL==”ttyACM*”, ATTRS{idVendor}==”26ac”, ATTRS{idProduct}==”0032”, ATTRS{serial}==”00000000001A”, MODE:=”0666”, GROUP:=”dialout”, SYMLINK+=”pixhawk_A”# Rule for device B KERNEL==”ttyACM*”, ATTRS{idVendor}==”26ac”, ATTRS{idProduct}==”0032”, ATTRS{serial}==”00000000001B”, MODE:=”0666”, GROUP:=”dialout”, SY