Calibrating the compass wirelessly with USB/IP

With the switch to the XSens IMU last year came a new challenge. To calibrate the magnetometer on the XSens, we use the graphical ‘magnetic field mapper’ program supplied with it. This is compiled for Intel processor architectures, so we need to run it on a laptop, not the Raspberry Pi that controls the boat.

Our first approach was to place the XSens in the boat with a long USB cable coming out to a nearby laptop, carry out the calibration process, and then unplug it from the laptop and plug it into the Rasberry Pi. But with a narrow access hatch, it’s difficult to swap the plugs without moving things around. What we wanted was a way to do the calibration while the XSens was connected to the Raspberry Pi. And what we found was USB/IP.

USB/IP is a Linux technology which sends USB data over the network, so a USB device plugged into one computer can act like it’s plugged into another one. In our case, the Raspberry Pi acts as a USB/IP server, exposing the XSens over the network, and the laptop running the calibration is a USB/IP client. Getting this working took some experimentation; if you’re trying to do something similar, here are some notes on what we found:

  • On Ubuntu 16.04, the usbip package doesn’t work. USB/IP is now part of the linux-tools-common package instead. It looks like it was packaged when it was a separate utility, and it later became part of Linux.
  • On the Raspberry Pi, we ended up compiling usbip ourselves. This might not be necessary, but if you do have to do it, make sure you get the Linux source code for the version matching your kernel. You can run uname -r to find your kernel version.
  • The server (the one the USB device is plugged into) needs the usbip-host kernel module loaded, and the usbipd daemon running.
  • On the server, run usbip list -l to see available USB devices. A device has a fixed USB ID (e.g. 2639:0300 for our XSens). Find the bus ID (e.g. 1-1.3), which can change. The --parseable (or -p) flag helps if you want to automate finding this.
  • Using the bus ID, usbip bind -b 1-1.3 exposes the device to the network. Local programs can’t use it while it’s exposed, to unbind it when you’ve finished with usbip unbind -b 1-1.3.
  • The client needs the vhci-hcd kernel module loaded.
  • On the client, you need the bus ID and the IP address of the server. To connect the device, run usbip attach -r 192.168.0.1 -b 1-1.3. Now programs on this system should be able to use the USB device as if it were plugged in.
  • The device gets a ‘port number’ on the client, which starts from 0. You use this to detach it again when you’re finished with it: usbip detach -p 0.

Our scripts to connect and disconnect the XSens over USB/IP are in our GitHub repository, in the piaccess folder.