Connect multiple micro-controllers to one Raspberry Pi over USB (serial) with a reliable identification of them.
I’m working on a escape box with a central Raspberry Pi acting as the brain of the machine. Each puzzle works with an ESP32 connected to the Pi over a serial connection (via a FTDI device).
On Linux, every device is identified by a file descriptor in the /dev directory. When I go in /dev and launch an ls command, I can see all the ESP32 as USB devices, named ttyUSB0, ttyUSB1, and so on. Great.
In my code (Node-RED in my case), I can create a serial connection to each device with its path (for example: /dev/ttyUSB0).
But there is one big problem...
After a restart of the Pi, the devices may not been linked to the same file descriptors as before… In other words, the ESP32 connected on the first physical USB socket of the Pi may now be linked to /dev/ttyUSB1 (instead of /dev/ttyUSB0 as before). So the configuration of the serial connections is erroneous.
The solution is to use the udev kernel module that handles all the devices in /dev. We can write rules to tell udev how to link physical devices to file descriptors. This can be done in the following file:
nano /etc/udev/rules.d/10-usb-serial.rules
Add the following line and save:
ACTION=="add", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", DRIVERS=="usb", SYMLINK+="tty.usb-$attr{devpath}"
Then reload the rules:
sudo udevadm trigger
Now in the /dev directory, there are new symlinks named tty.usb-a.b[.c[.d]]. And these links are consistent after each restart!
So /dev/tty.usb-1.1 is (and will always be) the device connected on the first physical USB socket of the Pi!
Working with USB hubs?
No problem.
Say you have a USB hub on the first physical USB socket. The device connected on the first socket of this hub will be linked to /dev/tty.usb-1.1.1. And so on…
Summary
Here is some steps to follow:
- Add the above udev rule and reload the rules with the above command.
- Connect one device and identify it in /dev, named /dev/tty.usb-a.b.c…
This path will never change, so you can add it in the config of your app. - Connect a second device, ls /dev, see the new one, update your the config of your app… And so on for all your devices.
I hope you will find this article useful!
Here are some links that helped me:
- https://raspberrypi.stackexchange.com/questions/139402/how-to-define-usb-port-as-a-stable-name-on-raspberry-pi-3b
- https://www.domoticz.com/wiki/PersistentUSBDevices
- https://www.freva.com/fr/attribuer-des-noms-de-port-usb-fixes-a-votre-raspberry-pi/?unapproved=8255&moderation-hash=3c4a820449a8fe2767d1e59919d4ef53#comment-8255