Short Answer
Serial devices are listed deterministically by path in /dev/serial/by-path with a verbose naming scheme that represents the physical device connection. This name will always be the same as long as the device is plugged into the same USB port. These are symlinks to the dynamic naming of devices in /dev/ttyUSB*
As long as you always have your arduino plugged into the same port on your machine or USB hub it will always result in the same path name in the by-path directory. You could then just symlink to the appropriate by-path filename to make sure your script always works and has a memorable name. This solution works even if you have several arduinos connected to your system.
If I plugged an arduino into the second USB2.0 port (4.2) on my system I could always access it at /dev/arduino using this symlink definition:
ln -s /dev/serial/by-path/pci-0000:00:14.0-usb-0:4.2:1.0-port0 /dev/arduino
Background Info
The ttyUSB0, ttyUSB1 naming scheme depends on the time order of connecting devices and the next available index. The same device may show up with a new index if the system was unable to free all handles to it from a previous connection of the device or even if an error caused the device to renumerate and the previous file handle was unavailable still. The by-path directory symlinks always point the constant physical port name to the latest ttyUSB# instance of a device connection.
$ ls -la /dev/serial/by-path/
total 0
drwxr-xr-x. 2 root root 200 Feb 8 21:46 .
drwxr-xr-x. 4 root root 80 Feb 7 22:17 ..
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:1:1.0-port0 -> ../../ttyUSB4
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.1:1.0-port0 -> ../../ttyUSB0
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.1:1.1-port0 -> ../../ttyUSB1
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.1:1.2-port0 -> ../../ttyUSB2
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.1:1.3-port0 -> ../../ttyUSB3
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.2:1.0-port0 -> ../../ttyUSB6
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.3.3.1.2.4:1.0-port0 -> ../../ttyUSB7
lrwxrwxrwx. 1 root root 13 Feb 8 21:46 pci-0000:00:14.0-usb-0:4.3.3.3:1.0-port0 -> ../../ttyUSB8
As long as you alwaysIn this example I have yourfive USB-serial device plugged intodevices connected as well as several hubs. The "pci-0000:00:14.0-usb-" prefix is always the same portbecause all of my USB chips are on your machine orthe same PCI bus. If you had a thunderbolt connected USB hub this number would probably change. The subsequent numbering scheme represents the path to the device on a specific USB port. For the symlink beginning 0:1 I'm not sure what the 0 is, 1 is the address of the USB3 chip on my motherboard, 4.1, 4.2, 4.3 are the three builtin USB2 ports on my system. The device connected to port 4.1 is a USB-serial adapter with four serial ports on a single device, therefore it will always result inhas final values of 1.0, 1.1, 1.2, and 1.3 to signify all of the ttys on the single device.
ttyUSB7 is a USB-Serial adapter plugged into a long string of USB hubs. ttyUSB8 is plugged into the same path namestring of hubs but only part way along the string. The ttyUSB* naming shows you what order I plugged the devices in. You can see that /dev/ttyUSB5 is missing. That is because I unplugged a device that regularly fails to get all of its file handles released so when I plugged it in again that number wasn't reused. Despite that I can still reach the device under it's new filename because I have the by-path symlink.
Alternative Naming Scheme
On my CentOS system these by-path directory. On my CentOS system these symlinks are being created with UDEV rules from the default system ruleset in /usr/lib/udev/rules.d/60-serial.rules.
Since my system doesn't have the ability to extend the PCI bus the pci-0000:00:14.0-usb- prefix never changes and is just more typing to point to a specific port. For the sake of convenience in having a shorter naming scheme, the UDEV rule below uses a variation of the 60-serial.rules to create a symlink in /dev/ which strips pci-0000:00:14.0-usb- off the beginning of the link name and -port0 off the end.
ThisMy new rule relies on the ID_PATH environment variable having been defined (ID_PATH contains the long version device path - "pci-0000:00:14.0-usb-0:4.3.3.1.2.4:1.0-port0"). RulesYou don't have to care about how ID_PATH gets created, you just need to run your rule after it exists in order to use/manipulate it. UDEV rules are executed in numerical naming order so I just named my rule with a 90 prefix, /etc/udev/rules.d/90-usbtty.rules, rather than trying to find out when ID_PATH got defined and then it was available to modify.
This rule creates shorter names and puts them in a convenientthe /dev/ directory for my convenience.
More Involved Naming Code
It is nice that this rule all fits into have a single line of theone-liner UDEV filerule,
but if it were any more complex (and arguably now) it would need its owna separate script file to be intelligible and functional.
You If you did want to create such a script the example below could be a starting point. You can substitute /bin/sh for any other executable file.
UDEV
UDEV environment variables are available in the called program
and standard output (frome.g. echo/print statements)
of the form ENV_VAR='VALUE'
cause new environment variables to become available.
One last gotcha I ran into that might force a separte script rather than the one-liner is quote escaping. You can see in the script version of the rule that the more standard -d '-' is passed to cut, whereas in the oneliner --delimiter=- was required. As far as I can tell UDEV doesn't allow quote escaping, so specifying the delimiter without a quote is necessary.
For the examples shown I have five USB-serial devices connected as well as several hubs. The "ttyUSB." prefix is just a string in the rule. The subsequent numbering scheme represents the path to the device. For the symlink beginning 0:1 I'm not sure what the 0 is, 1 is the address of my builtin USB3 chip, 4.1, 4.2, If you try 4.3-d - arethen the three builtin USB2 ports on my system. The device connected to port 4.1dash is a USB-serial adapter with four serial ports oninterpreted as a single device, therefore it has final values of 1.0, 1.1, 1.2, and 1.3flag to signify all of the ttys on the single device.
ttyUSB7 is a USB-Serial adapter plugged into a long string of USB hubs. ttyUSB8cut is plugged into the same string of hubs but only part way along the stringrather than a delimeter character.