Webots 快速上手
本教程在一台 Linux x86_64 主机上启动 Tiago Webots 仿真,以及 Robonix 的系统组件、原语(Primitive)、服务(Service)和技能(Skill),然后通过 Liaison 提交一条自然语言任务。第一次执行会编译 Rust 工作区、构建容器并下载依赖;后续复用缓存时才是快速启动流程。
1. 检查主机
默认图形界面路径需要可用的 X Server 和图形栈。命令行工具需要 Git、Make、Python 3.10+、Rust stable、uv、Docker Engine 和 Compose v2。
当前完整 Webots 测试使用 NVIDIA GPU、NVIDIA 驱动和 nvidia-container-toolkit;下面的主流程以这条已验证路径为准。仓库的基础 Compose 也映射了 /dev/dri,镜像内还包含 Xvfb。但 Intel/AMD 图形和 CPU 软件渲染尚未纳入完整端到端验收,只作为兼容与排错路径。
在 Ubuntu / Debian 上安装基础工具:
sudo apt update
sudo apt install -y \
build-essential git curl ca-certificates \
python3 python3-pip python3-grpc-tools alsa-utils ffmpeg
alsa-utils 和 ffmpeg 供语音链路使用。第 6 节会用麦克风和扬声器完成一次语音任务,arecord 和 aplay 也来自 alsa-utils。
安装 Rust stable:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
安装 uv:
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
Docker 使用官方的 Ubuntu 或 Debian 安装步骤。安装后确认当前用户可以直接运行 Docker;如果刚加入 docker 组,需要重新登录当前桌面会话。
scene 镜像的构建需要 BuildKit(RUN --mount=type=cache),因此还需 buildx 插件。按上面 Docker 官方源装的,它随 docker-buildx-plugin 一并装上。用发行版自带的 docker.io 则要另装,Ubuntu 和 Debian 的包名都是 docker-buildx:
sudo apt install docker-buildx
git --version
make --version | head -n 1
python3 --version
rustc --version
cargo --version
uv --version
docker version --format '{{.Server.Version}}'
docker compose version
docker buildx version
python3 -c 'import grpc_tools.protoc; print("grpc_tools: ok")'
预期结果: 版本命令均以状态码 0 退出;Python 版本不低于 3.10,grpc_tools: ok 可见,Docker 命令不需要 sudo,docker compose version 显示 Compose v2。
2. 安装 Robonix
克隆源码并初始化子模块。本页的命令输出、参数默认值和界面截图都取自 223675d9,跟着做时检出同一个提交,看到的东西才和这里一致:
git clone --recurse-submodules https://github.com/syswonder/robonix.git
cd robonix
git checkout --detach 223675d9a5000e70debae4f2512404cec5c9c442
git submodule update --init --recursive
git rev-parse HEAD
git submodule status --recursive
make install
make install 把 rbnx、代码生成器和 Atlas、Executor、Soma、Vitals、Pilot、Liaison 等系统可执行文件安装到 ~/.cargo/bin。它同时把当前克隆目录登记为 Robonix 源码根目录。确认安装结果:
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
rbnx --version
rbnx path root
预期结果: git rev-parse HEAD 输出 223675d9a5000e70debae4f2512404cec5c9c442;rbnx path root 输出刚克隆的 Robonix 仓库绝对路径。
3. 配置视觉语言模型
Pilot 需要兼容 OpenAI 接口的视觉语言模型(VLM)访问地址。以下变量必须出现在执行 rbnx boot 的同一个命令行环境中:
export VLM_API_KEY='sk-...'
export VLM_BASE_URL='https://api.example.com/v1'
export VLM_MODEL='your-model-name'
不要把真实 key 写进 Git。Robonix 当前不会自动加载 deployment 目录中的 .env;如果团队用 .env 管理本机变量,应将其加入 .gitignore,并在启动前显式加载:
set -a
source .env
set +a
检查变量是否存在时不要打印 key:
test -n "${VLM_API_KEY:-}" && echo 'VLM_API_KEY is set'
printf 'VLM_BASE_URL=%s\nVLM_MODEL=%s\n' "$VLM_BASE_URL" "$VLM_MODEL"
4. 构建 Webots 部署
从 Robonix 仓库根目录进入示例:
cd examples/webots
rbnx build
构建读取 examples/webots/robonix_manifest.yaml,准备本地软件包,并把清单中通过 url: 引用的音频、建图、导航和自主探索仓库放入 rbnx-boot/cache/。
第一次构建时间主要取决于容器镜像、模型下载、网络和 CPU。不要把冷启动时间与复用缓存后的启动时间混为一谈。
Webots 部署包含一条完整的语音链路:音频原语、语音识别与合成、声纹。第 6 节会用到它。默认识别后端是本地 FunASR,第一次构建会安装语音依赖并下载 paraformer-zh-streaming 模型。要改用腾讯云,或想了解为什么默认不启用 Whisper,见语音后端配置。
预期结果: rbnx build 以状态码 0 退出。构建脚本的输出直接显示在当前终端,各软件包的构建产物位于各自的 rbnx-build/;随后执行 rbnx boot 时,运行日志才会写入当前部署目录的 rbnx-boot/logs/。
5. 启动仿真与 Robonix
仿真和 Robonix 分两个终端启动,第 6 节提交任务时再开第三个。三个终端都进第 2 节克隆的那一份源码,不要另外克隆:仿真脚本、部署清单和 rbnx 解析的路径都以它为准。
| 终端 | 作用 | 生命周期 |
|---|---|---|
| 1 | Webots 仿真、ROS 2、RViz2 | 前台阻塞,关掉即停仿真 |
| 2 | rbnx boot 拉起 Robonix 全栈 | 前台阻塞,Ctrl+C 即关闭部署 |
| 3 | rbnx caps / rbnx chat 等查询与交互 | 随时开关 |
终端 1:Webots、ROS 2 与 RViz2
cd /path/to/robonix
bash examples/webots/sim/start.sh --world office.wbt
脚本会启动仿真容器,等待 ROS 2 话题就绪,并在容器内启动 RViz2。它默认使用 ROS 中间件实现(ROS Middleware Implementation,RMW)rmw_zenoh_cpp;同一部署中的 ROS 2 进程必须使用相同的 RMW_IMPLEMENTATION。Webots 容器会为该示例启动 rmw_zenohd,本快速上手流程不需要另起路由器,也不需要设置第二个 Robonix 专用 RMW 变量。
预期结果: 终端先出现 [sim/start] waiting for live sim sensor data...,随后是 [sim/start] live odom, RGB, and lidar data received 和 RViz2 日志路径;Webots 与 RViz2 窗口可见。就绪判据是 /odom、/head_front_camera/rgb/image_raw、/scanner 三个话题各收到一帧。
RViz2 窗口里在看什么
RViz2 是验收和排障工具,机器人无头运行时不需要它。示例自带的配置是 examples/webots/sim/rviz2_default.rviz,Fixed Frame 设为 map,默认打开这些显示项:
| Displays 面板中的名字 | 话题 | 用途 |
|---|---|---|
SlamMap | /map | 建图服务输出的二维占据栅格 |
GlobalCostmap | /global_costmap/costmap | 导航的全局代价地图 |
LocalCostmap | /local_costmap/costmap | 导航的局部代价地图 |
LaserScan | /scanner_normalized | 雷达点,用来判断是否与墙面重合 |
GlobalPlan | /plan | 全局路径 |
LocalPlan | /local_plan | 局部路径 |
Odometry | /odom | 底盘里程计 |
GoalPose | /rviz_goal_pose | 从 RViz 工具栏下发的目标点 |
TF | — | 坐标树 |
Grid | — | 参考网格,不来自机器人 |
左侧 Displays 面板控制每一项的开关。刚启动时 /map 还是空的,建图服务收到足够数据后才会出现栅格。
三件事最值得先看。
TF 是否连通。在左侧 Displays 面板里找到 TF 这一项,点它左边的三角展开,里面有 Frames 和 Tree 两个子项。Frames 列出当前收到的所有坐标系,Tree 才是要看的那个,展开后按父子关系缩进显示,正常应该读成 map 底下挂 odom,odom 底下挂 base_link。某一级没出现,就是那一级的发布者没起来:缺 map 是建图服务没起或还没输出,缺 odom → base_link 是底盘原语没发里程计。命令行的等价做法是 ros2 run tf2_ros tf2_echo map base_link,连通时持续打印平移和旋转,断了会一直报找不到变换。雷达是否贴合:机器人静止时 LaserScan 的点应当落在墙上,明显偏移说明定位不对。代价地图是否合理:机器人周围不应出现大片致命代价,否则规划会失败。

上面这些显示项只读话题,但 RViz2 不止能看。本示例的 RViz 配置带了三样能动机器人的工具:
| 工具或面板 | 位置 | 作用 |
|---|---|---|
| 2D Pose Estimate | 顶部工具栏 | 发布到 /initialpose,用来在定位跑偏时手工把机器人摆回正确位置 |
| 2D Goal Pose | 顶部工具栏 | 发布到 /rviz_goal_pose,在地图上点一下即可下发导航目标 |
| Navigation 2 面板 | 左下 | 显示导航状态,并可取消正在执行的目标 |
2D Goal Pose 能真正驱动机器人,是因为启动脚本额外拉起了一个中继进程 goal_pose_relay.py,它把 /rviz_goal_pose 转成 navigate_to_pose 动作再发给 Nav2。中继还会把时间戳清零,因为 RViz 的目标工具即使在 use_sim_time 下也盖墙上时间,规划器无法拿它对齐仿真时钟的 TF。
需要急停时,用 Navigation 2 面板取消当前目标;它只终止导航,不停止其他组件。完整的本体验收清单见本体接入指南 §7.4,那里还说明了自建部署里 SetGoal 与 GoalTool 的区别。
终端 2:Robonix 系统
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
export VLM_API_KEY='sk-...'
export VLM_BASE_URL='https://api.example.com/v1'
export VLM_MODEL='your-model-name'
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
cd /path/to/robonix/examples/webots
rbnx boot
audio_driver 默认自动探测系统的麦克风和扬声器。设备选择在第 6 节的 Ctrl+A 页面里做,这里不用配。
机器上确实没有任何声卡时(无声卡服务器或 CI),audio_driver 会启动失败。在执行 rbnx boot 的同一终端退回空设备:
export AUDIO_MIC_DEVICE='null'
export AUDIO_SPEAKER_DEVICE='null'
字符串 null 选择 ALSA 内置的空 PCM,不需要创建 .asoundrc。此时第 6 节的语音步骤无法验证,其余步骤不受影响。
Webots 部署清单配置以下系统组件和软件包:
- 系统:Atlas、Soma、Vitals、Scene、Executor、Pilot、Liaison
- 原语:Tiago 底盘、RGB-D 相机、二维激光雷达、
tiago_health(模拟本体遥测,供 Soma/Vitals 消费),以及通过独立仓库取得的 ALSA 音频和客户端音频桥 - 服务:记忆(memsearch 与
memgraph结构化记忆并行)、语音、声纹、建图、导航 - 技能:探索;启动后保持
INACTIVE,第一次被调用时由 Executor 激活
预期结果: 启动摘要中没有 failures,系统组件显示监听地址,原语与服务为 ACTIVE,Explore 为 INACTIVE。终端最后显示组件已启动以及 rbnx-boot/logs 路径。
Scene 调试页默认位于 http://127.0.0.1:50107/。页面同时显示二维占据栅格、语义对象、机器人位姿、三维点云和相机流;这些数据只有在相应提供方已经启动并发布后才会出现。
6. 提交第一条任务
保持终端 1 和终端 2 运行,在终端 3 检查注册状态:
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
cd /path/to/robonix/examples/webots
rbnx caps -v
rbnx tools
rbnx chat
rbnx chat 先通过 Atlas 发现 Liaison,再由 Liaison 把用户输入交给 Pilot,不绕过交互层直连 Pilot。
下面三句各走一条不同的链路,建议依次试:
What can you see in front of the robot?
这句只读相机。Pilot 调用场景服务的能力,回答里应当出现房间里的物体。
Explore the current room and report what you find.
这句会让机器人动起来。Pilot 选中第 5 节列出的探索技能,Executor 首次调用它时把它从 INACTIVE 激活。在第三个终端重新执行 rbnx caps 可以看到状态变了:
● explore [ACTIVE] robonix/skill/explore (4 caps)
What tasks are currently running?
这句查执行状态,不下发新动作。
界面顶部会打印本次可用的按键:
Enter = send · F2 = voice (auto end on silence) · Ctrl+A = audio settings · Esc = abort turn · Ctrl+C = quit.

Esc 中断当前交互回合,Ctrl+C 退出文本用户界面(Text User Interface,TUI)。
预期结果: 每一轮对话,界面从上到下依次出现四种内容:自己输入的那句话、Pilot 的规划状态、被调用的能力,以及最终回复。左侧是这条时间线,右上的 Task / Forest 面板同步显示当前任务和它的机器人任务描述语言(Robot Task Description Language,RTDL)树。
回复不符合预期时,先分清是规划错了还是执行错了。界面上能看到 Pilot 选了哪些能力,这是规划部分;能力自己做了什么要看提供方日志,每个提供方一个文件,例如 Explore 的在 rbnx-boot/logs/explore.log。只看启动器日志的尾部通常看不出问题。
选择麦克风与扬声器
在 rbnx chat 里按 Ctrl+A 打开音频设置页。它一屏显示四项:麦克风提供方、麦克风设备、扬声器提供方、扬声器设备。
| 按键 | 作用 |
|---|---|
Tab / Shift+Tab | 在四个区块之间切换 |
↑ ↓ 或 k j | 在当前区块内移动 |
Enter 或 Space | 选中当前项 |
r | 重新从 Atlas 拉取提供方与设备列表 |
Esc 或 Ctrl+A | 关闭并保存 |
本机运行仿真时,两个提供方都选 audio_driver,它使用这台机器的 ALSA 设备。设备项留空表示用系统默认;默认设备不对时在这里显式选一个。关闭后聊天界面会打印一行 audio settings updated: mic=… · speaker=… 确认。
Atlas 里没有麦克风或扬声器提供方时,页面会提示 no mic provider in atlas — voice input disabled。这不影响文本任务。
用语音提交一条任务
按 F2 开始说话,停止说话后录音自动结束,不需要再按一次。对着麦克风说一句和上面同样的话,例如“你前面有什么”。
Liaison 依次调用麦克风采集、语音识别、声纹、Pilot 规划和语音合成,最后由扬声器播报回复。这条链路用到第 4 节下载的 FunASR 模型和刚才选定的设备。
预期结果: 界面依次显示识别文本、规划状态和回复,扬声器播出回复语音。
识别文本为空或明显不对时,先确认录音设备本身可用:
arecord -d 3 -f S16_LE -r 16000 -c 1 /tmp/mic-test.wav
aplay /tmp/mic-test.wav
这段录放音直接使用 ALSA,不经过 Robonix。听不到声音说明问题在设备或权限,不在语音服务。
7. 选择其他 Webots 场景
示例内置五个场景,每次启动选其中一个。office.wbt 是默认场景,第 5 节已经用过。
其余四个在第一次运行前,需要先下载一次 Cyberbotics 官方离线资源包。下载只做一次,之后复用持久化缓存:
cd /path/to/robonix
ROBONIX_WEBOTS_DOWNLOAD_ALL_ASSETS=1 \
bash examples/webots/sim/start.sh --world apartment.wbt
资源就绪后,换场景只需改 --world。仿真正在运行时直接执行也可以,Compose 会按新的场景重建容器:
bash examples/webots/sim/start.sh --world complete_apartment.wbt
bash examples/webots/sim/start.sh --world break_room.wbt
bash examples/webots/sim/start.sh --world kitchen.wbt
office.wbt![]() | apartment.wbt![]() |
complete_apartment.wbt![]() | break_room.wbt![]() |
kitchen.wbt![]() |
仿真容器第一次启动时,无论选哪个场景,都会通过 https://ghfast.top/ 下载一次带校验和的 webots-office-seed-v3,随后从持久化 Webots 缓存卷复用。要绕过镜像站直连 GitHub,可把 ROBONIX_WEBOTS_SEED_MIRROR 设为空;ROBONIX_WEBOTS_SEED_URL 可以覆盖完整下载地址。
8. 停止并清理运行进程
首先停止 Robonix:在运行 rbnx boot 的终端按 Ctrl+C,并等待关闭完成;也可以从另一个终端在部署目录执行 rbnx shutdown。随后再停止 Webots 仿真和由示例记录的 RViz2 进程:
cd /path/to/robonix/examples/webots
# 仅在没有通过 Ctrl+C 停止 rbnx boot 时执行:
rbnx shutdown
bash sim/stop.sh
sim/stop.sh 是全量清场脚本,不只停仿真:它按进程名 pkill -9 掉 Robonix 的系统二进制(atlas、executor、soma、pilot、vitals、liaison)和各软件包进程,按模式杀 RViz2,再 docker rm -f 掉 mapping、scene、explore 容器,最后 docker compose -f compose.yaml down。
正常关闭仍应先 rbnx shutdown,让各组件走完生命周期;sim/stop.sh 是那之后的兜底。它保留可复用的镜像、Webots 资源卷和软件包构建缓存。
排错
Webots 或 RViz2 窗口未出现
printf 'DISPLAY=%s\n' "${DISPLAY:-<unset>}"
docker ps --filter name=robonix_tiago_sim
本地图形桌面通常使用 DISPLAY=:0。若日志包含 X11 权限错误,按 start.sh 打印的 xhost 命令授权本地 Docker 用户。
ROBONIX_SIM_STREAM=1 会启动浏览器查看器:主机存在 /dev/nvidia0 时自动选择 NVIDIA Xorg,否则回退到 Xvfb 软件渲染。Xvfb 不需要 NVIDIA 设备,但速度明显较低。
ROBONIX_SIM_STREAM=1 bash examples/webots/sim/start.sh
本机打开 http://127.0.0.1:8080/。查看器连接优化后的 WebSocket 端口 1235,不要连接 Webots 原始端口 1234。端口可分别通过 ROBONIX_SIM_VIEWER_PORT 和 ROBONIX_SIM_STREAM_PORT 覆盖。
远程机器运行时,把查看器和 WebSocket 一起转发:
ssh -N \
-L 18080:127.0.0.1:8080 \
-L 11235:127.0.0.1:1235 \
user@server
然后打开 http://127.0.0.1:18080/?wsPort=11235。
audio_driver 启动失败
先检查 ALSA 是否识别到硬件,再对照 audio_driver 日志中的设备名:
arecord -l
aplay -l
rbnx logs -t audio_driver -l warn
-l 只列硬件设备,不列 null 之类的 ALSA 插件。有硬件但日志报打不开设备时,按第 6 节“选择麦克风与扬声器”显式指定 hw:N,M,或改用 plughw:N,M 让 ALSA 重采样。两条命令都列不出任何设备,才按同一张提示卡退回空设备;此时第 6 节的语音步骤无法验证。
软件包启动失败
先读启动摘要中点名的提供方日志,不要只看启动器日志尾部:
ls -1 rbnx-boot/logs
provider_id=tiago_lidar
tail -n 120 "rbnx-boot/logs/${provider_id}.log"
远程软件包不是最新版本
rbnx-boot/cache/ 会复用已克隆的上游仓库。显式更新:
rbnx update
更新会改变实际运行的源码修订号;团队复现问题时,应同时记录部署仓库和每个远程软件包的提交号。
下一步
- 图形客户端:把
rbnx chat换成网页界面,可以看 RTDL 树、用客户端电脑的麦克风和扬声器。 - 系统部署与启动:理解真实启动所有权、生命周期和日志位置。
- 本体接入指南:把 Webots 能力提供方替换为真实机器人硬件。
- 开发者指南:从 template-rbnx 开发自己的原语、服务或技能。
- 接口目录:查询标准契约与 ROS 接口定义。
参考
- Webots 论文:Michel O。Cyberbotics Ltd. Webots: Professional Mobile Robot Simulation。International Journal of Advanced Robotic Systems, 2004。代码见 cyberbotics/webots。
- ROS 2 论文:Macenski S, Foote T, Gerkey B, Lalancette C, Woodall W。Robot Operating System 2: Design, architecture, and uses in the wild。Science Robotics, 2022。
- Docker Engine 与 buildx 的安装步骤以 Docker 官方文档为准。
- Robonix 源码:syswonder/robonix。




