Skip to content

PX4 Docker容器

提供了适用于完整的PX4开发工具链的Docker容器,其中包括基于NuttX和Linux的硬件、Gazebo Classic仿真环境以及ROS

本主题将展示如何使用可用的Docker容器,在本地Linux计算机上访问构建环境。

INFO

Dockerfile文件和README文件可在Github上的此处找到。 它们会在Docker Hub上自动构建。

系统必备组件

INFO

目前,PX4容器仅在Linux系统上受支持(如果您没有Linux系统,可以在虚拟机中运行容器)。 请勿将boot2docker与默认的Linux镜像一起使用,因为它不包含X服务器。

为您的Linux计算机安装Docker,最好使用Docker维护的软件包存储库之一,以获取最新的稳定版本。您可以使用_企业版_或(免费的)社区版

对于在_Ubuntu_上本地安装非生产环境的设置,安装Docker最快且最简单的方法是使用便捷脚本,如下所示(在同一页面上可以找到其他安装方法):

sh
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh

默认安装要求您以root用户身份调用_Docker_(即使用sudo)。但是,为了构建PX4固件,我们建议以非root用户身份使用docker。这样,在使用docker之后,您的构建文件夹不会归root所有。

sh
# 创建docker用户组(可能不需要)
sudo groupadd docker
# 将您的用户添加到docker用户组中。
sudo usermod -aG docker $USER
# 在使用docker之前,请重新登录/注销!

本地编辑层次结构

可用的容器可在Github上的此处找到。

使用容器的最简单方法是通过 docker_run.sh 帮助程序脚本。 容器是分层的,因此容器具有其父容器的功能。 例如,下面的部分层次结构显示,带有NuttX构建工具的docker容器(px4-dev-nuttx-focal)不包含ROS 2,而仿真容器则包含:

plain
- px4io/px4-dev-base-focal
  - px4io/px4-dev-nuttx-focal
  - px4io/px4-dev-simulation-focal
    - px4io/px4-dev-ros-noetic
      - px4io/px4-dev-ros2-foxy
  - px4io/px4-dev-ros2-rolling
- px4io/px4-dev-base-jammy
  - px4io/px4-dev-nuttx-jammy

可以使用latest标签访问最新版本:px4io/px4-dev-nuttx-focal:latest (在_hub.docker.com_上为每个容器列出了可用的标签。 例如,px4io/px4-dev-nuttx-focal的标签可以在此处找到)。

TIP

通常,您应该使用较新的容器,但不一定非要使用latest(因为它更新过于频繁)。

使用Docker容器

典型命令的语法如下所示。 假设您已将PX4源代码下载到 src/PX4-Autopilot 目录,如下所示:

sh
mkdir src
cd src
git clone https://github.com/PX4/Firmware.git
cd Firmware

助手脚本(docker_run.sh)

使用容器的最简单方法是通过 docker_run.sh 帮助程序脚本。 该脚本将PX4构建命令作为参数(例如make tests)。它会使用适当容器的最新版本(硬编码)和合理的环境设置来启动docker。

例如,要构建软件在环仿真(SITL),您可以调用(在 /PX4-Autopilot 目录内):

sh
sudo ./Tools/docker_run.sh 'make px4_sitl_default'

或者,要使用NuttX工具链启动一个bash会话:

sh
sudo ./Tools/docker_run.sh 'bash'

TIP

这个脚本很方便,因为您无需过多了解_Docker_,也无需考虑使用哪个容器。 要重新进入此容器(将保留您的更改),只需执行以下操作: 如果脚本存在任何问题,下面部分中讨论的手动方法更加灵活,应在这种情况下使用。

手动调用Docker

典型命令的语法如下所示。 这将运行一个支持X转发的Docker容器(使容器内部的仿真图形用户界面可用)。 它将您计算机上的目录<host_src>映射到容器内部的<container_src>,并转发连接 QGroundControl 所需的UDP端口。 使用–privileged选项,它将自动获得对主机上设备(例如操纵杆和GPU)的访问权限。如果您连接/断开设备,则必须重新启动容器。

sh
# 启用从容器访问xhost
xhost +

# 运行docker
docker run -it --privileged \
    --env=LOCAL_USER_ID="$(id -u)" \
    -v <host_src>:<container_src>:rw \
    -v /tmp/.X11-unix:/tmp/.X11-unix:ro \
    -e DISPLAY=:0 \
    -p 14570:14570/udp \
    --name=<local_container_name> <container>:<tag> <build_command>

其中:

  • <host_src>:要映射到容器中<container_src>的主机计算机目录。通常,这应该是 PX4-Autopilot 目录。
  • <container_src>:在容器内部时共享(源)目录的位置。
  • <local_container_name>:正在创建的Docker容器的名称。如果以后我们需要再次引用该容器,可以使用此名称。
  • <container>:<tag>:要启动的带版本标签的容器,例如:px4io/px4-dev-ros:2017-10-23
  • <build_command>:要在新容器上调用的命令。例如,bash用于在容器中打开一个bash shell。

下面的具体示例展示了如何打开一个bash shell,并共享主机计算机上的目录 ~/src/PX4-Autopilot

sh
# 启用从容器访问xhost
xhost +

# 运行docker并打开bash shell
docker run -it --privileged \
--env=LOCAL_USER_ID="$(id -u)" \
-v ~/src/PX4-Autopilot:/src/PX4-Autopilot/:rw \
-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
-e DISPLAY=:0 \
--network host \
--name=px4-ros px4io/px4-dev-ros2-foxy:2022-07-31 bash

INFO

我们使用主机网络模式,以避免在与docker容器相同的系统上使用QGroundControl时,UDP端口访问控制之间发生冲突。

INFO

如果您遇到错误“无法打开显示::0”,可能需要将DISPLAY设置为不同的值。 在Linux(XWindow)主机上,您可以将-e DISPLAY=:0更改为-e DISPLAY=$DISPLAY。 在其他主机上,您可能需要迭代-e DISPLAY=:0中的0值,直到“无法打开显示::0”错误消失。

运行模拟实例时,例如在docker容器内的SITL并通过 QGroundControl 从主机控制它,必须手动设置通信链接。 QGroundControl 的自动连接功能在此处不起作用。

sh
cd src/PX4-Autopilot    #这是<container_src>
make px4_sitl_default gazebo-classic

重新进入容器

docker run命令只能用于创建新容器。要重新进入此容器(该容器将保留您的更改),只需执行以下操作:

sh
# 启动容器
sudo docker start container_name
# 在这个容器中打开一个新的bash shell
sudo docker exec -it container_name bash

如果您需要多个连接到该容器的shell,只需打开一个新的shell并再次执行最后一条命令即可。

清理容器

有时您可能需要完全清除一个容器。您可以使用其名称来执行此操作:

sh
docker rm mycontainer

如果您不记得名称,那么可以列出非活动容器的ID,然后删除它们,如下所示:

sh
docker ps -a -q
45eeb98f1dd9
docker rm 45eeb98f1dd9

QGroundControl

当在docker容器内运行模拟实例(例如SITL)并通过主机上的_QGroundControl_对其进行控制时,必须手动设置通信链接。_QGroundControl_的自动连接功能在此处不起作用。

在_QGroundControl_中,导航至设置并选择“通信链接”。创建一个使用UDP协议的新链接。端口取决于所使用的配置,例如,对于SITL配置,端口为14570。IP地址是您的docker容器的IP地址,使用默认网络时通常是172.17.0.1/16。可以使用以下命令找到docker容器的IP地址(假设容器名称为mycontainer):

sh
$ docker inspect -f '{ {range .NetworkSettings.Networks}}{ {.IPAddress}}{ {end}}' mycontainer

INFO

上面双大括号之间的空格不应存在(它们是为了避免gitbook中出现用户界面渲染问题而需要的)。

故障处理

权限错误

容器会根据需要使用默认用户(通常是“root”)创建文件。这可能会导致权限错误,即主机计算机上的用户无法访问容器创建的文件。

上面的示例使用--env=LOCAL_USER_ID="$(id -u)"这一行,在容器中创建一个与主机上用户具有相同用户ID(UID)的用户。这可确保容器内创建的所有文件在主机上都可访问。

图形驱动问题

运行Gazebo Classic时,可能会出现类似以下的错误消息:

sh
libGL error: failed to load driver: swrast

在这种情况下,必须安装主机系统的本地图形驱动程序。下载合适的驱动程序,并在容器内部安装它。对于Nvidia驱动程序,应使用以下命令(否则安装程序会检测到主机上已加载的模块并拒绝继续):

sh
./NVIDIA-DRIVER.run -a -N --ui=none --no-kernel-module

有关此内容的更多信息,可以在此处找到。

虚拟机支持

尝试禁用并行构建。

以下配置已通过测试:

  • 运行OS X系统,搭配VMWare Fusion和Ubuntu 14.04(在Parallels上具有图形用户界面支持的Docker容器会导致X服务器崩溃)。

内存

为虚拟机至少使用4GB内存。

编译问题

如果编译失败并出现类似以下的错误:

sh
The bug is not reproducible, so it is likely a hardware or OS problem.
c++: internal compiler error: Killed (program cc1plus)

尝试禁用并行构建。

允许从虚拟机主机控制Docker

编辑/etc/defaults/docker并添加以下行:

sh
DOCKER_OPTS="${DOCKER_OPTS} -H unix:///var/run/docker.sock -H 0.0.0.0:2375"

然后,您可以从主机操作系统控制docker:

sh
export DOCKER_HOST=tcp://<ip of your VM>:2375
# 运行一些docker命令,查看是否有效,例如ps
docker ps