Balluff - BVS CA-SF Technical Documentation
Using USB3 Vision™ Devices In A Docker Container

When developing machine vision applications using Docker containers, it might be required to access USB3 Vision™ devices inside the container. With the Impact Acquire framework stack this can be achieved fairly easily and this chapter will demonstrate how to build a basic Docker container where USB3 Vision™ devices can be used.

Host Preparation

Linux

Since Docker uses the kernel of the Linux host machine, it is important to Increasing Kernel memory of the USB file system first to make sure that there will be enough temporary buffer for image data transmission at USB3 speed.

Windows

Host system requirements

  • Windows 11 64-bit: Home or Pro version 21H2 or higher, or Enterprise or Education version 21H2 or higher (Build 22000 or later)
  • Windows 10 64-bit: Home or Pro 21H1 (build 19043) or higher, or Enterprise or Education 20H2 (build 19042) or higher
  • WSL2 backend (For installation please follow: Docker Window Install)
  • Impact Acquire framework >= 2.48.0

Attach USB3 Vision™ devices to the WSL2 Linux distro via USB/IP

USB devices physically connected to the host system are not automatically accessible in the WSL2 Linux distro. They need to be first attached from the Windows host to the default Linux distro via USB/IP. Please follow Connect USB devices WSL2 for implementation guidance.

Start udev manually

udev is needed to identify attached USB devices and to access USB3 Vision™ devices as non-root users with the help of the udev-rules shipped by the Impact Acquire framework. However, systemd, which starts udev automatically, is by default not supported in WSL2 distros. Besides, udev doesn't support containers. Since WSL2 distros themselves are technically containers, they are not supported by udev. In order for udev to work in WSL2 distros, the following lines need to be commented out in /etc/init.d/udev before manually starting udev, as shown below:

#if [ ! -w /sys ]; then
#    log_warning_msg "udev does not support containers, not started"
#    exit 0
#fi

Then start udev in the WSL2 default Linux distro:

$ sudo /etc/init.d/udev start

Optimize the USB3 performance

The default usbfs buffer in the Linux kernel is 16MB which is usually too small for reliable USB3 Vision™ data transfer. A value of 256MB is recommended. Please refer to Increasing Kernel memory to learn about how to calculate a suitable value for your application.

The easiest way to increase the value automatically when starting the WSL2 distro is to add this kernel parameter in the WSL2 global config file .wslconfig which is usually located under C:\Users\<UserName> on the Windows host system:

# Settings apply across all Linux distros running on WSL 2
[wsl2]
kernelCommandLine = usbcore.usbfs_memory_mb=256
Note
If .wslconfig doesn't exit under C:\Users\<UserName>, create one on your own.
After editing the .wslconfig file, the WSL2 distro needs to be restarted by calling "wsl --shutdown" in Windows PowerShell for changes to take effect.

Building A Docker Image

The following demo Dockerfile builds a basic Docker image based on the latest stable release version of Debian, where the Impact Acquire GenTL framework including its sample programs are installed. This Dockerfile can be used in many ways:

  • Use it directly to test your device in a Docker container.
  • Use it as a base image for your device applications.
  • Use it as an inspiration for building your own Dockerfile.

Before building the Dockerfile, please download the Balluff Impact Acquire framework installer (https://www.balluff.com/en-de/downloads/software):

  • The installation script: ImpactAcquire-x86_64-linux-*.sh (* should be replaced by the version number)
Note
In case of ARM architectures, all occurrences of "x86_64" in this documentation have to be replaced by the correct platform e.g. "arm64" or "armhf".

Create a directory called ImpactAcquire (as used in this demo Dockerfile) and move both installation files into this directory. In this example, both files are downloaded into the Downloads directory and the ImpactAcquire directory is created inside the Downloads directory:

  • $ cd ~/Downloads
  • $ mkdir ImpactAcquire
  • $ mv ImpactAcquire-x86_64-linux-*.sh ImpactAcquire/

Make the installation script ImpactAcquire-x86_64-linux-*.sh executable:

  • $ cd ImpactAcquire
  • $ chmod a+x ImpactAcquire-x86_64-linux-*.sh

Navigate back into the directory where ImpactAcquire resides (e.g. Downloads) and create your Dockerfile:

  • $ cd ~/Downloads
  • $ touch Dockerfile

Create the content of your Dockerfile. Our demo Dockerfile (for Linux x86_64) looks as follows:

# start with the latest stable release version of Debian
FROM debian:latest

ENV LC_ALL C
ENV DEBIAN_FRONTEND noninteractive

# entrypoint of Docker
CMD ["/bin/bash"]

# set environment variables
ENV TERM linux
ENV MVIMPACT_ACQUIRE_DIR /opt/ImpactAcquire
ENV MVIMPACT_ACQUIRE_DATA_DIR /opt/ImpactAcquire/data
ENV GENICAM_GENTL64_PATH /opt/ImpactAcquire/lib/x86_64
ENV GENICAM_ROOT /opt/ImpactAcquire/runtime
ENV container docker

# update packets and install minimal requirements
# after installation it will clean apt packet cache
RUN apt-get update && apt-get -y install build-essential && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# move the directory ImpactAcquire with *.sh file to the container
COPY ImpactAcquire /var/lib/ImpactAcquire

# execute the setup script in an unattended mode
RUN cd /var/lib/ImpactAcquire && \
    ./ImpactAcquire-x86_64-linux-3.2.0.sh -u -u3v && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
Note
In case of ARMhf architectures, the environment variable GENICAM_GENTL64_PATH defined in this demo Dockerfile should be relaced by GENICAM_GENTL32_PATH instead.

Finally, build a Docker image using this Dockerfile:

$ sudo docker build -t [image_name] .
Note
Please make sure to call docker build from within the directory where the Dockerfile resides. Note that Internet access is required for the docker build.

If built successfully, the newly built [image_name] will be listed when calling:

$ sudo docker images

Starting The Docker Container

Since the Docker container is isolated from the host system, it needs to be started with certain volume mounts and cgroup permissions for it to access USB3 Vision™ devices. In order to avoid running the container in privileged mode, which is not secure, it can be started like this:

$ sudo docker run -ti -v /dev:/dev -v /run/udev:/run/udev:ro --device-cgroup-rule 'a 189:* rwm'
 [image_name] /bin/bash

Where:

  • -v /dev:/dev: use volume mount to map the host /dev directory to the container, so the container will be able to always detect devices also when they get unplugged and re-plugged at any time.
  • -v /run/udev:/run/udev:ro: volume mount the udev database with read-only permission, so the USB3 Vision™ interfaces can be enumerated correctly in the container.
  • –device-cgroup-rule 'a 189:* rwm': with the --device-cgroup-rule flag, specific permission rules can be added to a device list that is allowed by the container's cgroup. Here in this example, 189 is the major number of the USB bus, * means all minor numbers, and rwm are respectively read, write, mknod accesses. By doing so, all USB devices will get read, write, mknod access. USB3 Vision™ devices can thus be enumerated successfully.

Validation

After starting the container, the correct operation of USB3 Vision™ devices can be validated by running one of the sample programs provided by the Impact Acquire (e.g. SingleCapture):

  • $ cd /opt/ImpactAcquire/apps/SingleCapture/x86_64
  • $ ./SingleCapture

If the attached USB3 Vision™ device appears in the device list of the program's output, access to it in the container by using the Impact Acquire has been established. Now the USB3 Vision™ device can be used inside the Docker container for your machine vision applications.