CARLA远程显示实战:从X11转发到VNC与无头渲染方案解析

发布时间:2026/10/4 2:17:00
CARLA远程显示实战:从X11转发到VNC与无头渲染方案解析 很多做自动驾驶仿真的朋友买了台带 GPU 的服务器想正经跑 CARLA结果装完后远程一执行./CarlaUE4.sh屏幕上一个窗口都没弹出来。这不是你环境装坏了而是 CARLA 的渲染链路和普通服务器程序完全不同。CARLA 本身是一个基于 Unreal Engine 的实时仿真程序启动后需要一个图形上下文来创建窗口和渲染画面而服务器通常既没有物理显示器也没有可用的图形环境。我在折腾“服务器跑 CARLA、本地看窗口”这件事时把 X11 转发、Xvfb、VNC、无头渲染都走了一遍这篇笔记就把我的真实踩坑过程和最终落地方案完整写出来。这篇文章适合正在跑 CARLA 学习、想把远程服务器当成主力仿真机但又不想放弃可视化界面的同学。读完你能理解 CARLA 远程显示的本质逻辑并直接拿到一套照着做就能用的配置方案。1. 远程跑 CARLA首先要理解“画面从哪来”1.1 CARLA 不是传统意义上的客户端/服务器应用很多不熟悉游戏引擎渲染逻辑的开发者第一次接触 CARLA 时会把它当成一个 Web 服务来理解觉得服务器上启动了 CARLA就应该有个网页或端口可以直接看画面。实际上不是这样的。CARLA 的仿真流程分成两个独立部分一部分是CarlaUE4这个 Unreal Engine 进程负责运行物理模拟、传感器模拟、渲染生成画面另一部分是 Python API 服务默认监听在 2000 端口负责接收外部脚本的控制指令。这里的 2000 端口只是指令通道不是画面通道它传递的是大量结构化的传感器数据而不是一帧一帧的渲染图像。所以想在本地看到 CARLA 窗口本质上要解决的不是“如何连上 2000 端口”而是“如何把CarlaUE4进程的渲染画面从服务器搬到本地屏幕”。这个理解很关键后面所有方案都是围绕这一点展开的。我打个比方。CARLA 进程就像是在服务器机房里运行的一台游戏主机但它所连接的显示器不在你身边。你现在有两种办法看到画面一是把显示器连接头延长到你的本地电脑屏幕这是 X11 转发思路的雏形二是在机房里装一个“摄像头”对着显示器再把摄像头画面通过网络传给你这是 VNC 的思路。后者通常更靠谱。1.2 三条技术路线怎么选X11、VNC、无头渲染我实操下来远程显示 CARLA 窗口的方案可以归为三类方案原理优点缺点适合场景X11 转发通过 SSH 把图形绘制指令转发到本地 X Server配置简单无需额外服务对 Vulkan/OpenGL 重度应用支持差容易白屏或卡死轻量验证临时看个现象Xvfb VNC服务器创建虚拟屏幕VNC 截取屏幕画面传回本地稳定通用交互流畅度可控需要安装额外组件有网络带宽占用绝大多数日常学习实验无头渲染 Python API直接关闭窗口渲染通过 Python 拉取相机图像服务器负载低适合跑批数据看不到完整 CARLA UI无法手动操作场景传感器数据采集、批量回放、自动驾驶算法调试看到这个对比你可能会问为什么 X11 转发是常规远程图形方案但用在 CARLA 上不灵原因是 CARLA 的渲染依赖 Vulkan 底层 API。X11 协议设计之初面向的是 2D 绘制命令和轻量级窗口管理虽然也能传输 OpenGL/Vulkan 的绘制指令但面对 CARLA 这种每帧包含大量纹理、光照、深度计算的实时渲染场景时数据量会变得非常大而且很多图形库在 X11 转发的环境下会直接退化到软件渲染帧率惨不忍睹甚至一张白屏。我在 4K 分辨率下试过一次 X11 转发启动花了几秒窗口显示出来后基本是“幻灯片”拖动场景时画面完全撕裂。所以它只能作为最轻量的应急方案不建议作为长期主力。VNC 之所以稳定是因为它绕开了图形 API 的远程传输问题。CARLA 在服务器上的虚拟屏幕里正常渲染x11vnc 直接采集这块屏幕的帧缓冲数据通过 VNC 协议发送给本地客户端。本地客户端的角色就是一个远程显示器不管你服务器用 OpenGL 还是 Vulkan反正传到本地的都是已经渲染好的图像。这样对 CARLA 的图形兼容性最好交互也流畅得多。2. 服务器端环境准备把基础打牢再开车2.1 GPU 驱动、Vulkan 支持与 CARLA 版本匹配在开始配置显示方案之前必须先确认服务器上的 GPU 环境是完善的。CARLA 0.9.x 系列在 Linux 上主要是基于 NVIDIA GPU Vulkan 渲染所以驱动和 Vulkan 运行时缺一不可。打开终端先跑一条命令nvidia-smi如果命令正常输出 GPU 信息说明 NVIDIA 驱动没问题。如果提示command not found说明驱动没有安装或者没在 PATH 里需要先装驱动。这里我强烈建议直接用官方推荐的方式桌面环境用ubuntu-drivers autoinstall纯服务器环境用官方的.run包安装装完重启。驱动装好后确认 Vulkan 支持vulkaninfo --summary 2/dev/null | grep -i deviceName如果能看到类似NVIDIA GeForce RTX 3090的输出说明 Vulkan 链路正常。如果没有任何输出说明系统缺少 Vulkan runtime执行sudo apt install mesa-vulkan-drivers sudo apt install libvulkan1还有一个被很多人忽略的点是版本匹配问题。CARLA 对 Unreal Engine 的版本要求很严格不同 CARLA 版本对操作系统、驱动等级和 Python 版本的兼容性也不一样。拿我常用的 CARLA 0.9.15 举例在 Ubuntu 20.04 和 22.04 上都跑得很顺但必须要用 Python 3.8 或以上版本。服务器系统如果用 Ubuntu 18.04很多新版本 CARLA 直接编译可能缺依赖。建议下载官方预编译包前先去对应文档页确认支持的平台不要盲目下最新版。2.2 安装虚拟显示器与 VNC 组件因为服务器通常没有物理显示器我们要先装一个“虚拟显示器”软件让显卡有地方输出画面。Ubuntu/Debian 系统下命令如下sudo apt update sudo apt install xvfb x11vnc x11-utils mesa-utils net-tools这几个工具的各自用途是什么xvfb创建一个真正意义上的虚拟显示设备不需要物理显示器也能让 X Window 程序运行CARLA 就会认为系统里有屏幕正常创建窗口并渲染。x11vnc把某个 X display 的内容实时转换成 VNC 协议流。x11-utils提供xwininfo、xrandr等 X11 调试工具排查窗口是否创建时非常有用。mesa-utils提供glxinfo等 OpenGL 信息查询工具可以帮助判断渲染上下文是否正常。装上之后不需要立刻启动服务后面第三步里我会给出完整启动顺序。2.3 本地客户端需要准备的软件本地端实际上不需要安装庞大的 CARLA 环境只需要装一个能够接收远程画面的客户端。Windows 本地如果要试 X11 转发装一个 VcXsrv轻量 X Server 软件更推荐直接装 VNC Viewer官方免费版就够用。mac 本地系统自带“屏幕共享”支持 VNC 协议直接可以连接X11 转发则用 XQuartz。我不太推荐本地再装一整套 CARLA 客户端因为那样你等于维护了两份环境还要处理版本一致性问题。服务器跑一份本地只看画面这是最干净的架构。3. 方案一SSH X11 转发轻量但更容易踩坑3.1 X11 转发的真实体验X11 转发作为一个 SSH 自带的图形传输协议在转发终端类、轻量级 GUI 工具时表现还不错。比如远程连一个xclock、gedit之类的小工具画面响应还凑合。但用在 CARLA 这种大型实时渲染应用上我只能用一个字形容痛苦。我第一次尝试时用了这条命令ssh -X carla_user服务器IP cd ~/carla ./CarlaUE4.sh结果有两种典型情况一种是什么都不显示终端里直接报错退出了另一种是窗口能弹出来但整个画面像卡死一样拖动地图视角的时候延迟高到完全无法操作。原因前面说过Vulkan 应用在 X11 转发链路中的表现非常差。但为什么我仍然把这个方案放在第一个讲因为它的配置成本最低能帮你快速确认 SSH 链路、X Server、DISPLAY 环境变量这些基础项是否正常。如果连 X11 转发都能看到 CARLA 窗口哪怕很卡那说明服务器端的图形环境本身是通的后面换 VNC 就能顺理成章。3.2 具体操作步骤第一步本地 Windows 安装并启动 VcXsrv。安装完成后运行 XLaunch选择多窗口模式Display number 设置成 0最后一步记得勾选 Disable access control否则远程连接时可能因权限问题被拒绝。第二步在本地打开终端连接服务器启用压缩转发ssh -X -C carla_user服务器IP第三步在服务器上确认 DISPLAY 变量是否正确。SSH 登录后系统通常会自动设置DISPLAYlocalhost:10.0这样的值执行echo $DISPLAY如果为空手动设置export DISPLAYlocalhost:10.0第四步启动 CARLAcd /opt/carla ./CarlaUE4.sh -quality-levelLow这里我把画质降到了 Low目的是缩短纹理上传时间降低网络传输负担。实际操作中即便是 Low 画质X11 转发依然很吃力所以看到画面卡到不能动不要惊讶这是方案本身的天花板。3.3 什么时候该放弃 X11 转发我的判断标准是如果你只想确认一下 CARLA 能不能在服务器上正常启动并且加载过程不需要交互操作那 X11 转发可以用一用如果后面要长期做仿真调试、逐帧观察场景、拖动视角、添加车辆和传感器我建议直接切到 X11 转发之外更稳定的 VNC 方案。另外提醒一句CARLA 启动时如果加上了-RenderOffScreen参数窗口会被彻底隐藏任何远程显示方案都看不到 UI 界面。这个参数是给纯无头渲染使用的后面第 5 章会讲。单独的“显示窗口”场景千万不要加这个参数。4. 方案二Xvfb x11vnc当前最稳的远程显示组合4.1 这套方案的工作原理这套方案的核心思路可以概括为“虚拟屏幕屏幕采集”。在服务器上我们用 Xvfb 创建一块内存中的虚拟屏幕它完全模拟一个物理显示器的行为但不需要真实显示设备。CARLA 启动时会被 Xvfb 提供的 X Display 接受认为系统里有屏幕于是正常创建渲染窗口。随后x11vnc开始实时抓取这个虚拟屏幕上的画面数据封装成 VNC 协议通过指定的 5900 端口发送出去。本地电脑只要用任意一款 VNC Viewer 连接到服务器 IP 和端口就能看到和本地操作几乎一致的 CARLA 窗口了。打个比方Xvfb 相当于给服务器接了一个“假显示器”x11vnc 相当于在这个假显示器前架了一台摄像头你本地 VNC Viewer 就是看直播的屏幕。这套方案绕开了 X11 转发对渲染指令的高要求因为网络上传送的是已经渲染好的彩色画面而不是底层绘制指令。4.2 步骤一启动 Xvfb 虚拟显示器为了不让终端占用影响后续操作我建议用 tmux 开会话在后台保持这些服务常驻。tmux new -s carla_display会话里启动 XvfbXvfb :99 -screen 0 1600x900x24 -ac 这段命令的参数含义是:99指定 X display 编号为 99。之所以不选 0是因为很多真实服务器或远程登录进程已经在使用 0 编号避免冲突。1600x900x24虚拟屏幕分辨率是 1600x90024 位色深。这是 CARLA 窗口显示比较舒服的尺寸也是 VNC 传输时带宽和画质的折中点。-ac禁用 X Server 的访问控制方便本地 x11vnc 直接读取。这个参数要在可信环境中使用如果你担心安全问题可以不用但后续连接 VNC 时就需要处理 X authority 授权。启动后可以用xvfb-run验证一下虚拟屏幕是否正常工作DISPLAY:99 xdpyinfo | grep dimensions如果能输出dimensions: 1600x900 pixels说明 Xvfb 已经正常服务。4.3 步骤二启动 x11vnc 屏幕采集虚拟屏幕就绪后启动 x11vnc 把屏幕内容流出去export DISPLAY:99 x11vnc -display :99 -forever -shared -repeat -rfbport 5900 -passwd carla_display_123 逐个解释参数-display :99告诉 x11vnc 去采集编号为 99 的 X display。-forever保持 x11vnc 进程不退出即使某个 VNC 客户端断开连接。-shared允许多个客户端同时连接便于本地多台电脑同时观察。-repeat重复发送相同按键事件保证键盘交互的连贯性。-rfbport 5900VNC 服务监听端口。-passwd carla_display_123设置连接密码至少 6 位防止随意连接。启动后用ss或netstat确认端口在监听ss -tlnp | grep 5900如果服务器有防火墙需要放行 5900 端口sudo ufw allow 5900/tcp如果你用的是云厂商服务器还要在云控制台的安全组规则里把入方向 TCP 5900 端口加上否则外面连不进来。这个点很容易漏我远程连不上的情况有七成都是因为安全组没放行端口。4.4 步骤三在虚拟显示器上启动 CARLA现在启动 CARLA并让它把窗口绘制到编号为 99 的虚拟显示器上cd /opt/carla export DISPLAY:99 ./CarlaUE4.sh -quality-levelLowCARLA 启动需要一些时间第一次启动还会做 shader 编译可能比平时慢很多。不要着急等出现 CARLA 主界面后回到 tmux 会话里再用xwininfo确认窗口DISPLAY:99 xwininfo -root -tree | grep -i carla如果能看到类似CARLAUE4的窗口记录那画面传输链路就已经打通了。这时本地 VNC Viewer 连接服务器 IP:5900输入密码后你应该能在本地看到 CARLA 的完整界面并且能够用鼠标键盘操作场景。这一步是我长期使用的主力方案。实测下来在局域网环境下1600x900 分辨率、Low 画质、24 位色深画面刷新率能稳定在 30 fps 左右操作车辆和拖动视角都比较流畅。如果是跨公网使用受带宽和延迟影响会明显卡顿建议把分辨率降到 1280x720并且在 VNC Viewer 里关闭全屏抗锯齿和 JPEG 压缩质量调低。4.5 浏览器观看用 noVNC 免装客户端有时候本地电脑没有现成的 VNC 客户端或者你只想临时看一眼服务器上的仿真状态我推荐直接启用 noVNC把 VNC 数据转成 WebSocket然后通过浏览器访问。安装 noVNC 并把 5900 的 VNC 端口映射到 6080sudo apt install novnc websockify websockify --web/usr/share/novnc 6080 localhost:5900 然后本地浏览器访问http://服务器IP:6080/vnc.html页面里会自动加载 noVNC 客户端输入密码就能看到 CARLA。浏览器方案的好处是零客户端依赖手机、平板都能看缺点是交互延迟比原生 VNC Viewer 略高一点适合观察不适合精细操作。4.6 核心经验虚拟显示器分辨率与 CARLA 窗口的参数匹配这里有个容易被忽视的细节CARLA 窗口默认的启动分辨率并不一定和 Xvfb 虚拟屏幕分辨率完全一致。如果 CARLA 创建了一个比虚拟屏幕更大的窗口画面就会被截断如果窗口比虚拟屏幕小很多VNC 看到的是一个很小的窗口操作体验很差。最稳妥的办法是让 CARLA 以窗口化方式启动并显式指定分辨率。CARLA 0.9.x 的启动参数里支持-windowed -ResX1600 -ResY900这种写法./CarlaUE4.sh -windowed -ResX1600 -ResY900 -quality-levelLow这样 CARLA 创建的窗口大小就和 Xvfb 的虚拟屏幕一致了VNC 里看到的画面是完整且比例的。5. 方案三无头渲染 Python API只要数据不要窗口5.1 什么场景下选择无头渲染如果你跑的仿真任务是批量生成数据、循环测试感知算法或者只是通过 Python API 控制车辆移动并读取传感器返回的数据那其实没必要打开 UI 窗口。CARLA 专门提供了-RenderOffScreen渲染模式让 GPU 仍然执行渲染计算但不创建可见窗口传感器输出依然完整。这个模式特别适合放到服务器上长期跑自动化任务因为不需要 X Display 环境也不占用 VNC 带宽。做法就是启动 CARLA 时加上参数./CarlaUE4.sh -RenderOffScreen注意-RenderOffScreen和方案二不冲突。如果你既想通过 VNC 观察又想让某些实验进程跑得更快就可以在同一台服务器上同时起两个 CARLA 分片一个带窗口供观察一个完全无头跑数据采集。我经常这么干。5.2 通过 Python API 把相机画面带回本地无头渲染后画面并不是消失了而是通过传感器数据的形式输出。CARLA 的 RGB 相机传感器可以捕获仿真的图像然后通过 Python 脚本传给本地端。下面是一个最精简的例子在服务器上启动 CARLA 无头模式后Python 脚本连接并获取场景里已有相机或自动放置一台相机然后把渲染画面保存成图片。import carla import numpy as np import cv2 client carla.Client(127.0.0.1, 2000) client.set_timeout(10.0) world client.get_world() # 在场景中创建一台 RGB 相机 bp_lib world.get_blueprint_library() camera_bp bp_lib.find(sensor.camera.rgb) camera_bp.set_attribute(image_size_x, 1280) camera_bp.set_attribute(image_size_y, 720) camera_transform carla.Transform( carla.Location(x-8.0, y0.0, z4.0), carla.Rotation(pitch-15) ) camera world.spawn_actor(camera_bp, camera_transform) # 用回调把图像保存为 jpg def save_image(image): array np.frombuffer(image.raw_data, dtypenp.uint8) array array.reshape((image.height, image.width, 4)) bgr array[:, :, :3][:, :, ::-1] cv2.imwrite(/tmp/carla_view.jpg, bgr) print(saved frame:, image.frame) camera.listen(save_image) # 保持脚本运行 while True: pass本地想查看抓到的图片可以再把/tmp/carla_view.jpg同步到本地或者在服务器上起一个简单的 HTTP 服务实时查看最新帧cd /tmp python3 -m http.server 8899本地浏览器访问http://服务器IP:8899/carla_view.jpg即可看到最新画面。这种方式虽然不像 VNC 那样能看到完整 UI但对数据驱动的调试流程非常有价值。5.3 无头渲染远程图像方案对比 VNC我个人的体会是方案二和方案三并不是互斥关系而是解决不同阶段的问题。VNC 适合“人机交互型”调试比如你得手动摆放车、调节天气、观察场景结构无头渲染Python 图像适合“任务执行型”实验比如跑一千个随机场景收集数据期间不需要人看。把两者搭配起来用效率是最高的。6. 常见问题与排查技巧实录6.1 常见问题速查表现象可能原因处理方式CARLA 启动后立刻退出Vulkan 驱动缺失或版本不兼容执行vulkaninfo检查重装 NVIDIA 驱动启动后黑屏卡住虚拟屏幕分辨率或色深不正确检查 Xvfb 参数提高色深到 24VNC 能连上但黑屏x11vnc 采集的 DISPLAY 和 CARLA 运行 DISPLAY 不一致确保 x11vnc 和 CARLA 都使用:99编号VNC 连接被拒绝端口未放行或者 x11vnc 未启动检查ss -tlnp | grep 5900和云安全组远程画面卡成幻灯片VNC 带宽不足或本地网络太慢降低虚拟分辨率、调低 VNC 画质、使用有线网络X11 转发白屏Vulkan 应用在 X11 网络链路上兼容性差放弃方案一直接用方案二 VNC多用户连接服务器时找不到 DISPLAYSSH 会话变量被重置在同一个 tmux 会话中统一设置export DISPLAY:99CARLA 想用鼠标拾取物体但点了没反应窗口焦点或者 3D 交互模式问题单击 CARLA 窗口确认焦点不要使用-RenderOffScreen6.2 用 tmux 管理常驻服务避免 SSH 断开导致进程被杀这是我踩过多次的坑直接在一个普通 SSH 会话中启动x11vnc和 CARLA然后本地网络一抖、SSH 断开服务器上所有前台进程全部被系统终止之前的启动工作全部白费。正确的做法是把这些进程放到 tmux 或 screen 会话里运行。我最常用的方式tmux new -s carla tmux send-keys -t carla Xvfb :99 -screen 0 1600x900x24 -ac Enter tmux send-keys -t carla export DISPLAY:99 Enter tmux send-keys -t carla x11vnc -display :99 -forever -shared -repeat -rfbport 5900 -passwd carla_display_123 Enter tmux new -s carla_app tmux send-keys -t carla_app cd /opt/carla Enter tmux send-keys -t carla_app export DISPLAY:99 Enter tmux send-keys -t carla_app ./CarlaUE4.sh -windowed -ResX1600 -ResY900 -quality-levelLow Enter以后不管 SSH 断多少次服务都一直停留在服务器上。重新连接时用tmux attach -t carla或tmux attach -t carla_app就能回到现场。6.3 多片 CARLA 并行时如何区分显示在服务器上跑多个 CARLA 实例时Xvfb 的 display 编号、VNC 端口、CARLA 端口都需要各自独立。比如第一个实例占用:99和 5900第二个实例可以开:100和 5901Xvfb :100 -screen 0 1280x720x24 -ac export DISPLAY:100 x11vnc -display :100 -rfbport 5901 -forever -shared -passwd carla_display_456 ./CarlaUE4.sh -carla-rpc-port2001 -windowed -ResX1280 -ResY720CARLA 的 Python API 默认连接 2000 端口要连第二片时就要指定client carla.Client(127.0.0.1, 2001)这样一台服务器就能同时跑多个仿真本地用多个 VNC Viewer 窗口分别观察非常适合并行调参。7. 进阶扩展Docker 容器里的 CARLA 远程显示7.1 容器内显示的关键依赖很多人的服务器环境已经容器化了Docker 里跑 CARLA 也很常见但容器默认没有显示设备VNC 方案也要做出相应调整。最基础的一步是确保 NVIDIA Container Toolkit 安装好让容器内能访问 GPUsudo apt install nvidia-container-toolkit sudo systemctl restart docker启动容器时需要把主机的 X 环境相关目录挂载进去并指定显示编号docker run -it \ --gpus all \ --net host \ -e DISPLAY:99 \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -v /opt/carla:/opt/carla \ nvidia/carla:0.9.15 \ bash这种挂载方式有个前提主机的 Xvfb 和 x11vnc 已经在运行。容器启动后直接运行 CARLA 并指定DISPLAY:99就会把渲染画面画到主机创建的虚拟屏幕上再通过主机的 VNC 端口传输到本地。7.2 为什么容器方案值得单独记录我之所以单独提容器方案是因为它解决了环境隔离问题。自动驾驶仿真项目里队友可能用不同版本的 CARLA直接用官方镜像或自建镜像可以避免“我这边能跑、你那跑不了”的尴尬。把 Xvfb、x11vnc 和 noVNC 都塞进容器也可以但容器越薄越容易维护我建议把图形服务留在宿主机容器只管 CARLA 本体。这条链路搭好后未来的使用体验会非常顺手笔记本上打开 VNC Viewer连上服务器 5900 端口就能看到一个完整的 CARLA 城市道路仿真环境服务器上的 GPU 在全力渲染本地电脑只需要一个轻量客户端。7.3 服务器场景下远程窗口只是一个开始这篇笔记写到这里远程显示的基础已经打通了。实际上“服务器跑 CARLA、本地显示窗口”只是系统学习的第一步后续还有一系列更深入的工作配场景、设置传感器、控制车辆、写自动评测脚本都是在这个基础上展开的。窗口能看到、交互不卡顿、端口能连通后续学习和实验才有安全感。我在实际使用中的体会是远程显示方案没有绝对的好坏关键是明确每个场景到底需要人看画面还是只需要机器处理数据然后灵活切换方案。VNC 稳定可靠适合调试无头渲染轻量高效适合跑批两者搭配起来用基本能覆盖从入门到项目落地的所有需求。