Linux treats serial ports and devices in general as files. When uploading to the MKR WiFi 1010 Arduino board, you are writing to the file /dev/ttyACM0. As with any file, you can only write to it if your Linux user has write permissions.
Just like with any other file, you can see how the permissions of this device are configured by using the You can see the permissions by using the ls -l command:
$ ls -l /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0 Jun 11 07:31 /dev/ttyACM0
Here we can see that only the owner and users in the file's group have write permissions. Other users do not have write permissions.
Your user not having those permissions is one of the possible causes of uploads to this board failing with the "No device found on ttyACM0" error. Since a user account doesn't have those permissions by default, this is the likely explanation for why you might experience the failure after setting up a new Linux machine.
So the solution will be to configure the system to give your Linux user the necessary write permissions. As is usually the case with Linux, there are a couple of possible ways to do this. I'll provide instructions for both. You can pick whichever one you prefer:
User Group
The traditional approach (which has already been mentioned by @Delta_G) is to add your user to the dialout system group. Users who are a member of this group have full access to all serial ports (remember we saw from the ls -l command that the /dev/ttyACM0 file's group is `dialout). You can do that by running this command:
sudo usermod --append --groups dialout "$USER"
After running the command, log out of your Linux account and then log back in so that the added group will take effect.
udev rules file
TL;DR
The subject of udev rules files is extremely convoluted and boring. If you don't want to learn about it, just run this command from the terminal:
printf \
'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0054", MODE="0660", TAG+="uaccess"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8054", MODE="0660", TAG+="uaccess"
' | \
sudo \
tee \
"/etc/udev/rules.d/60-Arduino-MKR-WiFi-1010.rules" \
&& \
sudo \
udevadm \
control \
--reload-rules \
&& \
sudo \
udevadm \
trigger
The rest of this post is only boring details about udev rules. If you aren't interested, you can skip reading the rest of the post.
However, this is a very important skill for any Linux user engaged in Arduino/embedded systems development so I do think it is worth discussing the subject further. You can get by, as I did for years, with tearing out your hair every time you want to use a new board/programmer/debug probe until you stumble across the random Stack Exchange answer that magically makes it work after you cursorily copy and paste the command without any understanding of what it does, hoping it isn't going to break your system or get you hacked. Having an understanding of the subject and the ability to write and install your own rules is a much better feeling.
Details
udev rules files are a more precise and flexible way to configure device permissions.
The primary reason I have moved to this approach is because the dialout group approach is not sufficient to configure permissions for the newer Arduino boards that don't upload via a serial port. I prefer to have a single consistent approach to configure device permissions rather than using one approach for certain boards and a completely different approach for other boards. There is no way to avoid using udev rules files so I might as well use them for all my devices.
In order to use udev to configure permissions for a device, we need to complete the following operations:
A. Write the rules.
B. Put the rules in a rules file.
C. Load the new rules.
D. Apply the new rules.
A. Write Rules
A udev rules file contains one or more rules. A rule is applied to devices that have the specified attributes. For Arduino boards, most often we use the USB VID and PID attributes to target a rule to a specific board. You can learn the VID and PID of a board by running the lsusb command:
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 010: ID 2341:8054 Arduino SA Arduino MKR WiFi 1010
Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
From this, I can see that the VID of my MKR WiFi 1010 is 2341 and the PID is 8054. However, there is a tricky thing about most of the Arduino boards like the MKR WiFi 1010 that have a native USB interface: the VID/PID pair changes when the board is put into the special mode where it can accept an upload. We must create a udev rule for both the VID/PID pairs. You can put the board into that upload mode manually by pressing and releasing the reset button twice quickly. When I do that and then run lsusb again, I see this:
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 010: ID 2341:0054 Arduino SA Arduino MKR WiFi 1010
Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Note that the PID is now 0054 instead of 8054.
So now we have all the information that is needed to write the udev rules for this board.
Since this post is already very long and boring, I won't go into the details of writing udev rule. For most microcontroller development boards and tools you can simply use this format:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="<VID>", ATTRS{idProduct}=="<PID>", MODE="0660", TAG+="uaccess"
(where <VID> is the device's USB VID and <PID> is the device's USB PID)
There is a nice explanation of udev rules here:
The information in that guide will allow you to understand each part of the rule (note especially this section) as well as how to create rules using attributes other than VID/PID when needed.
The rules for my MKR WiFi 1010 board will look like this:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0054", MODE="0660", TAG+="uaccess"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8054", MODE="0660", TAG+="uaccess"
B. Create Rules File
udev reads the rules from a special file. Rules files have a .rules suffix and are stored under the /etc/udev/rules.d/ folder.
We can create a rules file by running a command with this format from the terminal:
printf \
'<rules content>
' | \
sudo tee "/etc/udev/rules.d/<filename>"
(where <rules content> is the rules we want to add to the file and <filename>) is the filename we choose for the file)
We have already written the rules content.
As for the filename, it should have the standardized format:
<load order>-<name>.rules
<load order> is a number that determines the order in which the rules in this file are loaded relative to the other rules files (files are loaded in lexicographical order). For this application, the exact load order is not important. I haven't found any canonical guidelines for best practices so I have somewhat arbitrarily chosen to use 60 for my device rules (per this recommendation).
<name> can be anything, but as with any filename is a good idea to make it somewhat descriptive.
So I will name my rules file: 60-Arduino-MKR-WiFi-1010.rules
Putting it all together, the command to create the rules file for the MKR WiFi 1010 is:
printf \
'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0054", MODE="0660", TAG+="uaccess"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8054", MODE="0660", TAG+="uaccess"
' | \
sudo tee "/etc/udev/rules.d/60-Arduino-MKR-WiFi-1010.rules"
C. Load Rules
udev loads rules from the rules files when you log in. Although we could cause the new rules to be loaded by logging out and the logging back in, this is inconvenient (especially when you are experimenting or developing rules). The better way is to run this command from the terminal to tell udev to reload the rules:
sudo udevadm control --reload-rules
D. Apply Rules
Normally udev only applies rules to devices when you log in or when a device is attached. This means that the above steps will not have resulted in the permissions having been correctly configured for any boards that are already plugged into your computer. You could unplug and replug the boards, but since you are already working from the terminal you might find it more convenient to run a command to tell udev to apply the rules to all the currently attached devices:
sudo udevadm trigger
The command I provided in the "TL;DR" section of this post runs all the commands I mentioned in these sections in a single command line of chained commands.