The definitive place to put the setting is described as “it depends” :P
If your ttyACM0 device special file exists at the time “/etc/rc.local” runs, then this would be easy.
If you have your own programs where the programs themselves can run the command, or do the configuration themselves, then that would probably be even better.
The modern way, if you want this to automate modifying the nature of a “/dev” file, is perhaps to create a udev rule. For example, many hardware providers install a udev rule to rename the device special file when it is detected as being their hardware (I have two different JTAG debuggers which both use FTDI chipsets, but udev renames them if they belong specifically to those debuggers). Or to set up permissions, so on. A serial UART could have its setup considered eligible for setup via udev.
udev can be kind of a big topic, but parts of it are basic. If you go to “/etc/udev/” you will notice a theme that rules which are in “rules.d/” subdirectory override any rules of the same name which are part of the operating system. The same is true of “/etc/systemd/” which uses the same udev rules. Rules you get with the operating system are in “/lib/systemd/” and might be a “unit”, a “service” or a “target”. You’ll find this of particular interest:
find /lib/system -name '*serial*'
…perhaps ttyACM has something in there, I dont’ know since I don’t have any ttyACM devices.
But lets say you find “/lib/systemd/system/setserial.service” is something you want to change. To start with, if you place a rule in one of the relevant “/etc” locations, then the “/etc” version will take precedence. The file you start with could be a copy of one from “/lib/systemd/”, and then edited…remove your version, and it reverts back to the system version. If you place a symbolic link from the right place in “/etc” to a file in “/lib/system/”, then you are essentially declaring to do nothing…and do what it does anyway. This latter might not exactly be true because sometimes there are boot options and the way to pick the default is by putting a sym link from “/etc” into “/lib/systemd/” to the right file using an alternate name…one isn’t editing files that way, but editing instead a file name for “defaults”.
A good example I can think of, but which does not actually work on a Jetson (that is yet another story…there is some breakage in transitioning from older init style scripts and newer systemd init), is that on a PC you set whether to boot to text mode or graphical mode via naming the systemd target as either “multi-user.target” (text mode) or “graphical.target” (GUI mode). The system has the choice made by placing a symbolic link into “/etc” which points into the “/lib/systemd/” version of multi-user.target or graphical.target. systemd is programmed to look for “default.target”, and so the final symbolic link in “/etc” would actually be named “default.target”. Example from a Fedora desktop:
# Real files:
/lib/systemd/system/multi-user.target
/lib/systemd/system/graphical.target
# Symbolic link in "/etc/systemd/system/":
lrwxrwxrwx. 1 root root 36 Jan 1 2018 default.target -> /lib/systemd/system/graphical.target
When I boot a system with default.target pointing at “graphical.target” it is the same as running “sudo systemctl isolate graphical.target”. Not specifying uses “default.target”…which is exactly the same as graphical.target in my case due to the symbolic link.
EXAMPLE via UDEV:
In your case you would be putting a file in “/etc/udev/rules.d/”, and give it a name something like “99-custom-ACM-arduino.rules” (you can give a later number for things initialized later, or an earlier number for things needing initializing before other before other udev rules…some udev rules depend on other rules). A skeleton of this file would look like this…but I have to warn you my idVendor and other details are custom to the hardware…you can’t just copy this verbatim, you’ll need to adjust for your hardware:
# /etc/udev/rules.d/10-lauterbach.rules
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="0897", SYMLINK+="lauterbach/trace32/%k", MODE:="0666"
…as a result, when I boot up and the trace32 debugger is visible, I get this (the “9” is USB bus 9, the “1” is USB device number on that bus…these change depending on the slot the debugger is connected to and how many other devices are enumerating):
/dev/lauterbach/trace32/9-1
# ls -l /dev/lauterbach/trace32/9-1
lrwxrwxrwx. 1 root root 21 Jul 5 11:50 /dev/lauterbach/trace32/9-1 -> ../../bus/usb/009/002
FYI, if you run “lsusb” and the device is “NVIDIA” vendor, then ID will start with “ID 0955:”. After the 0955: you will see a specific device number. 0955 is an example of NVIDIA’s “idVendor”. It happens that the example debugger show is “idVendor” of “0897” when listed under lsusb. Whether or not just an idVendor is enough depends on your device and whether there are other USB devices using the same lsusb idVendor.
If you really want to set up your platform to formally handle this you’d use a udev rule. If your application is a script or easy to edit config for, then you’d set it up in the application. If you don’t need the setup until the system is up and running, and you know the device is always going to be there during boot, you could use “/etc/rc.local”.