Reset USB on Failures

Because USB connectors were not made for vibration and being reset continuously, like people usually do during robot development, there can be many errors which happen.

  • Multiple ways to see the details of USB settings and errors
  • A simple script to hard-reset the whole USB stack and all devices cleanly

How to Debug Broken USB

Debug with dmesg

You can check for errors by searching dmesg and grepping for usb, such as dmesg | grep -i USB. If you see errors you may need to reset the usb bus and have the system find everything again. You will see groupings like the below output. If you see error anywhere,

...
[  950.080459] usb 1-1.4: new high-speed USB device number 8 using xhci_hcd
[  950.387494] usb 1-1.4: New USB device found, idVendor=046d, idProduct=082c
[  950.387501] usb 1-1.4: New USB device strings: Mfr=0, Product=2, SerialNumber=1
[  950.387505] usb 1-1.4: Product: HD Webcam C615
[  950.387509] usb 1-1.4: SerialNumber: 7E6298D0
[  950.679920] input: HD Webcam C615 as /devices/pci0000:00/0000:00:15.0/usb1/1-1/1-1.4/1-1.4:1.2/input/input28

Debug with lsusb

This will output the list of currently visible (and working) USB devices. You can use this and unplug/replug to figure out which virtual serial port or other device has the specific details you need to debug it.

Bus 002 Device 002: ID 2109:0813 VIA Labs, Inc. 
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 007: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)
Bus 001 Device 005: ID 8087:0aa7 Intel Corp. 
Bus 001 Device 003: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
Bus 001 Device 008: ID 046d:082c Logitech, Inc. 
Bus 001 Device 006: ID 046d:0892 Logitech, Inc. OrbiCam
Bus 001 Device 004: ID 04d9:8009 Holtek Semiconductor, Inc. 
Bus 001 Device 002: ID 2109:2813 VIA Labs, Inc. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Debug with usb-devices

This is a more in-depth view of the drivers, serial numbers, etc for every device and useful for creating udev rules based on its values.

T:  Bus=01 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  6 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=046d ProdID=0892 Rev=00.19
S:  Product=HD Pro Webcam C920
S:  SerialNumber=91863D1F
C:  #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=500mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=0e(video) Sub=01 Prot=00 Driver=uvcvideo
I:  If#= 1 Alt= 0 #EPs= 0 Cls=0e(video) Sub=02 Prot=00 Driver=uvcvideo
I:  If#= 2 Alt= 0 #EPs= 0 Cls=01(audio) Sub=01 Prot=00 Driver=snd-usb-audio
I:  If#= 3 Alt= 0 #EPs= 0 Cls=01(audio) Sub=02 Prot=00 Driver=snd-usb-audio

Script to Reset the USB Stack

We recommend copying this script into reset_usb.sh and executing it as sudo with sudo sh reset_usb.sh on your robot if you have USB errors or have updated udev rules.

#!/bin/sh

if [ "$(id -u)" -ne 0 ]; then
        echo 'This script must be run by root with `sudo sh reset_usb.sh`' >&2
        exit 1
fi

echo 'Reloading UDEV rules to find any changes in naming, simlinks, etc'

udevadm control --reload-rules && udevadm trigger

sudo service udev restart

echo 'Re-binding all USB ports'

for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do
  echo "    Resetting ${i%/*}"
  echo "${i##*/}" > "${i%/*}/unbind"
  sleep 3
  echo "${i##*/}" > "${i%/*}/bind"
done

echo 'Waiting for 5 seconds to allow USB devices to be re-found'

sleep 5

echo 'Reset complete'

echo 'USB Devices which currently exist:'

lsusb

Once you have saved this, run sudo sh reset_usb.sh to reload the UDEV rules and trigger this.

Make sure your devices don't power down

Many USB buses power down devices over a period of time based on their own rules. You can set a udev rule for all USB devices to no allow the USB to lower their power. This can lead to intermittent failures, especially on virtual serial ports and other "generic" devices which the computer doesn't understand.

Create a new file in /etc/udev/rules.d/99-usb-power.rules with these contents, which will turn off the autosuspend of devices.

ACTION=="add", SUBSYSTEM=="usb", TEST=="power/control", ATTR{power/control}:="on"
ACTION=="add", SUBSYSTEM=="usb", TEST=="power/autosuspend", ATTR{power/autosuspend}:="-1"
ACTION=="add", SUBSYSTEM=="usb", TEST=="power/autosuspend_delay_ms", ATTR{power/autosuspend_delay_ms}:="-1"

If nothing else... Unplug, replug, repeat...

If this doesn't work, the actual USB device may have crashed and you will need to power it down to get it working. As many devices are remembered based on the specific port they were on, you should always try swapping to a different open USB port.

And, if all else fails, reset the computer and try again...