使用 X11 从远程 docker 运行 Rviz

don*_*s20 5 opengl nvidia x11-forwarding ros docker

我计划在远程服务器上的 docker 中运行 ROS Rviz,期望 Rviz GUI 显示在我的本地计算机上。但我无法完成。任何帮助,将不胜感激。

我在远程服务器上的 ROS docker 镜像基于 ros-melodic-desktop-full 镜像(根据ROS Using Hardware Acceleration with Docker,ros-melodic-desktop-full 已经包含 nvidia-docker2)。下面列出的是我的 Dockerfile:

FROM osrf/ros:melodic-desktop-full

# strace, xterm, mesa-utils are all for debugging X display. Especially, mesa-utils has glxinfo and glxgear
RUN apt-get update && apt-get install -y xauth strace xterm mesa-utils

# nvidia-container-runtime
ENV NVIDIA_VISIBLE_DEVICES \
    ${NVIDIA_VISIBLE_DEVICES:-all}
ENV NVIDIA_DRIVER_CAPABILITIES \
    ${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}graphics

# QT_X11_NO_MITSHM is for running X server and X client on different machines.
ENV QT_X11_NO_MITSHM 1

ENTRYPOINT ["/bin/bash"]
Run Code Online (Sandbox Code Playgroud)

我的工作流程来自此博客:在远程服务器上的 Docker 容器中运行图形应用程序。基本上,我使用 socat 作为管道来连接 Unix 域 sockat 和 TCP 端口 60xx(xx 是当前的 $DISPLAY 值)。下面是我的工作流程。我首先使用ssh -X user@address. 然后在服务器上,我执行这些命令(docker镜像名称是ros-nvidia-gui:1.0):

DISPLAY_NUMBER=$(echo $DISPLAY | cut -d. -f1 | cut -d: -f2)

socat TCP4:localhost:60${DISPLAY_NUMBER} UNIX-LISTEN:/tmp/.X11-unix/X${DISPLAY_NUMBER} &

export DISPLAY=:$(echo $DISPLAY | cut -d. -f1 | cut -d: -f2)

docker run -it --rm \
    -e DISPLAY=${DISPLAY} \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v /home/deq/.Xauthority:/root/.Xauthority \
    --hostname $(hostname) \
    -e QT_X11_NO_MITSHM=1 \
    -e QT_QPA_PLATFORM='offscreen' \
    --runtime=nvidia \
    --gpus all \
    ros-nvidia-gui:1.0
Run Code Online (Sandbox Code Playgroud)

然后我进入 docker 容器。当我roscore & rviz在容器中运行时,抛出以下异常

root@node3:/# rviz
[ INFO] [1587175060.603895335]: rviz version 1.13.7
[ INFO] [1587175060.603985593]: compiled against Qt version 5.9.5
[ INFO] [1587175060.604014712]: compiled against OGRE version 1.9.0 (Ghadamon)
[ INFO] [1587175060.620394536]: Forcing OpenGl version 0.
[ WARN] [1587175068.907551767]: OGRE EXCEPTION(3:RenderingAPIException): Couldn`t open X display :11 in GLXGLSupport::getXDisplay at /build/ogre-1.9-B6QkmW/ogre-1.9-1.9.0+dfsg1/RenderSystems/GL/src/GLX/OgreGLXGLSupport.cpp (line 832)
terminate called after throwing an instance of 'Ogre::RenderingAPIException'
  what():  OGRE EXCEPTION(3:RenderingAPIException): Couldn`t open X display :11 in GLXGLSupport::getXDisplay at /build/ogre-1.9-B6QkmW/ogre-1.9-1.9.0+dfsg1/RenderSystems/GL/src/GLX/OgreGLXGLSupport.cpp (line 832)
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

OpenGL 库似乎有问题。

所以我检查了docker中的OpenGL库。当我运行时glxgears,三个齿轮在我的本地计算机上弹出。这表明整个 X11-forwarding-in-docker-on-a-remote-server 工作正常,并且 docker 中的 OpenGL 也很好。

然后我检查了glxinfo,它输出以下(我只列出了与渲染、OpenGL、mesa 相关的行并省略了其他行):

name of display: :11
display: :11  screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.4

client glx vendor string: Mesa Project and SGI
client glx version string: 1.4

GLX version: 1.4

Extended renderer info (GLX_MESA_query_renderer):
    Vendor: VMware, Inc. (0xffffffff)
    Device: llvmpipe (LLVM 9.0, 256 bits) (0xffffffff)
    Version: 19.2.8
    Accelerated: no
    Video memory: 257669MB
    Unified memory: no
    Preferred profile: core (0x1)
    Max core profile version: 3.3
    Max compat profile version: 3.1
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.0
OpenGL vendor string: VMware, Inc.
OpenGL renderer string: llvmpipe (LLVM 9.0, 256 bits)
OpenGL core profile version string: 3.3 (Core Profile) Mesa 19.2.8
OpenGL core profile shading language version string: 3.30
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile

OpenGL version string: 3.1 Mesa 19.2.8
OpenGL shading language version string: 1.40
OpenGL context flags: (none)

OpenGL ES profile version string: OpenGL ES 3.0 Mesa 19.2.8
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.00
Run Code Online (Sandbox Code Playgroud)

简而言之,整个工作流程似乎都很好,除了 Rviz。最令人困惑的是为什么 Rviz 是“强制 OpenGl 版本 0”。我知道 mesa 的 OpenGL 与 nvidia 的 OpenGL 不一致,所以我也尝试清除 docker 容器中的 mesa,但 Rviz 会自动删除。这表明 Rviz 只使用台面的 OpenGL?所以,我也试着只用台面,即删除运行的码头工人--runtime=nvidia,并--gpus alldocker run指挥,但同样会抛出异常。

请给我一些帮助!我的最终目标是在远程服务器上的 docker 中运行 Rviz,并在我的本地计算机上显示 GUI。我需要使用远程服务器上的 GPU 来加速 Rviz,Mesa OpenGL 或 Nvidia OpenGL 都可以。谢谢!


编辑:

我将问题缩小到食人魔。我遵循 Rviz 对GLXGLSupport::getXDisplay源代码的例外。好像mXDisplay = XOpenDisplay(displayString);是错的。然后我搜索了 XOpenDisplay 的手册, “:11”显示值似乎没问题。现在我真的很困惑。