前言

本文是《Docker使用教程》的后续,默认已经按照其中的步骤创建了以下环境:

  • 容器名:ros_noetic
  • 基础镜像:osrf/ros:noetic-desktop-full
  • 宿主机 ~/docker/ros_root 已挂载到容器 /root
  • X11 目录和认证文件已经挂载,容器可以运行 RViz

这里的“全新容器”是指容器已经创建,但还没有下载 Fast-Planner,也没有安装项目依赖。本文不再重复安装 Docker、拉取 ROS 镜像或创建容器,只介绍如何在这个容器中下载、编译和测试 dreamer198/Fast-Planner

本文默认容器内使用 root 用户,因此 ~ 就是 /root,安装命令不需要 sudo。没有特别说明时,命令都在容器内执行;需要在宿主机执行的命令会单独标出。

Fast-Planner 官方验证过 Ubuntu 20.04 + ROS Noetic。本文只运行项目自带的轻量仿真,不包含 PX4、Gazebo 或真机控制。

一、进入已经创建的容器

如果创建容器后已经停在 root@... 提示符,可以直接进入下一节。

如果容器已经退出,在宿主机执行:

1
docker start -ai ros_noetic

如果容器已经在后台运行,则执行:

1
docker exec -it ros_noetic bash

进入后确认 ROS 版本:

1
2
source /opt/ros/noetic/setup.bash
rosversion -d

输出应为:

1
noetic

二、安装编译依赖

ROS Noetic Desktop Full 已经包含 ROS 和 RViz,不需要再次安装。只补充源码编译需要的工具和库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apt update
apt install -y \
git \
build-essential \
cmake \
libarmadillo-dev \
libeigen3-dev \
libpcl-dev \
qtbase5-dev \
ros-noetic-cmake-modules \
ros-noetic-cv-bridge \
ros-noetic-dynamic-reconfigure \
ros-noetic-image-transport \
ros-noetic-pcl-ros

安装 NLopt 2.7.1

Fast-Planner 的 bspline_opt 会从 /usr/local/include/usr/local/lib/libnlopt.so 查找 NLopt。按照项目 README 指定的 v2.7.1 编译安装:

1
2
3
4
5
6
7
8
9
10
11
mkdir -p /root/deps
cd /root/deps
git clone --branch v2.7.1 --depth 1 https://github.com/stevengj/nlopt.git

cmake -S nlopt -B nlopt/build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_INSTALL_LIBDIR=lib
cmake --build nlopt/build -j"$(nproc)"
cmake --install nlopt/build
ldconfig

检查头文件和动态库:

1
2
test -f /usr/local/include/nlopt.hpp && echo "nlopt.hpp: OK"
test -f /usr/local/lib/libnlopt.so && echo "libnlopt.so: OK"

两行都显示 OK 后再继续。

三、下载 Fast-Planner

新建独立的 catkin 工作空间,并将代码克隆到 src 中:

1
2
3
mkdir -p /root/fast_planner_ws/src
cd /root/fast_planner_ws/src
git clone https://github.com/dreamer198/Fast-Planner.git

确认下载地址并记录当前版本:

1
2
3
cd /root/fast_planner_ws/src/Fast-Planner
git remote get-url origin
git rev-parse --short HEAD

第一条命令应输出:

1
https://github.com/dreamer198/Fast-Planner.git

记录第二条命令输出的 commit,后续遇到问题时可以确认使用的是不是同一版代码。

四、编译工作空间

1
2
3
source /opt/ros/noetic/setup.bash
cd /root/fast_planner_ws
catkin_make -DCMAKE_BUILD_TYPE=Release -j"$(nproc)"

如果容器可用内存较少,编译进程可能被系统终止。此时降低并行数重新编译:

1
catkin_make -DCMAKE_BUILD_TYPE=Release -j2

编译完成后加载工作空间,并确认 ROS 能找到核心包:

1
2
source /root/fast_planner_ws/devel/setup.bash
rospack find plan_manage

正常情况下会输出:

1
/root/fast_planner_ws/src/Fast-Planner/fast_planner/plan_manage

项目没有提供覆盖这些规划流程的自动化单元测试,因此下面通过仓库自带的仿真 Demo 完成功能测试。

五、运行 Kinodynamic 规划测试

该测试需要两个终端,它们都进入同一个 ros_noetic 容器。第一个终端运行 RViz,第二个终端运行规划器和轻量仿真器。

1. 终端 1:启动 RViz

如果 RViz 还没有图形显示权限,先在宿主机执行:

1
xhost +SI:localuser:root

然后在宿主机进入正在运行的容器:

1
2
3
4
docker exec -it \
-e DISPLAY="$DISPLAY" \
-e QT_X11_NO_MITSHM=1 \
ros_noetic bash

在容器内启动 RViz:

1
2
3
source /opt/ros/noetic/setup.bash
source /root/fast_planner_ws/devel/setup.bash
roslaunch plan_manage rviz.launch

2. 终端 2:启动规划器

在宿主机新开一个终端:

1
docker exec -it ros_noetic bash

进入容器后执行:

1
2
3
source /opt/ros/noetic/setup.bash
source /root/fast_planner_ws/devel/setup.bash
roslaunch plan_manage kino_replan.launch

3. 在 RViz 中发送目标

等待 RViz 中出现随机障碍物和无人机模型,然后:

  1. 确认 RViz 的 Fixed Frameworld
  2. 点击工具栏中的 2D Nav Goal
  3. 在地图内没有障碍物的位置点击并拖动,发送一个目标点。

当前仓库的 Kinodynamic Demo 默认使用手动目标模式。目标的 X、Y 坐标来自点击位置,飞行高度默认为 1 m。正常情况下会立即生成 B-spline 轨迹,无人机随后沿轨迹飞向目标。

六、检查测试结果

在宿主机再开一个终端并进入同一容器:

1
docker exec -it ros_noetic bash

加载环境:

1
2
source /opt/ros/noetic/setup.bash
source /root/fast_planner_ws/devel/setup.bash

先确认节点已经启动:

1
rosnode list

列表中应能看到规划器、轨迹服务器、仿真器和点云渲染等节点。再检查里程计是否持续发布:

1
rostopic hz /state_ukf/odom

看到稳定频率后按 Ctrl+C 退出,再检查仿真点云:

1
rostopic hz /pcl_render_node/cloud

点云同样应持续更新,看到频率后按 Ctrl+C 退出。接着检查规划输出:

1
rostopic echo -n 1 /planning/bspline

这条命令会等待下一条轨迹消息。保持命令运行,回到 RViz 再发送一次目标;终端打印出 B-spline 消息并自动退出,说明规划器已经生成轨迹。

在无人机执行轨迹期间,还可以检查控制指令:

1
rostopic hz /planning/pos_cmd

如果能看到持续更新的频率,说明“目标输入 -> 路径规划 -> 轨迹下发”链路已经跑通。

七、运行 Topological 规划测试

先在运行 kino_replan.launch 的终端按 Ctrl+C 停止 Kinodynamic Demo,RViz 可以继续运行。不要同时启动两个 Demo,因为它们会创建同名节点并使用相同话题。

然后在规划器终端执行:

1
2
3
source /opt/ros/noetic/setup.bash
source /root/fast_planner_ws/devel/setup.bash
roslaunch plan_manage topo_replan.launch

这个仓库的 topo_replan.launch 已经默认使用 flight_type=1,可以直接在 RViz 中通过 2D Nav Goal 发送目标,不需要修改 launch 文件。看到多条拓扑候选路径和最终轨迹,并且无人机开始执行轨迹,即表示 Topological Demo 测试通过。

八、后续重新运行

代码和编译结果都位于 /root。按照《Docker使用教程》的挂载方式,它们会同步保存在宿主机 ~/docker/ros_root 中。apt 安装的软件和 /usr/local 下的 NLopt 属于容器文件系统;停止再启动同一个容器时仍然存在,但删除容器后不会由 /root 挂载保留。

下次启动同一个容器后不需要重新下载和编译,只需在每个新终端加载环境:

1
2
source /opt/ros/noetic/setup.bash
source /root/fast_planner_ws/devel/setup.bash

然后分别启动:

1
roslaunch plan_manage rviz.launch

以及二选一:

1
roslaunch plan_manage kino_replan.launch
1
roslaunch plan_manage topo_replan.launch

如果本次测试结束后不再运行容器中的图形程序,可以在宿主机撤销临时的 X11 授权:

1
xhost -SI:localuser:root

九、常见问题

1. roslaunch 找不到 plan_manage

说明当前终端没有加载工作空间,或者编译没有成功:

1
2
3
4
5
source /opt/ros/noetic/setup.bash
cd /root/fast_planner_ws
catkin_make -DCMAKE_BUILD_TYPE=Release -j2
source devel/setup.bash
rospack find plan_manage

2. 链接时找不到 libnlopt.so

检查 NLopt 的安装位置并刷新缓存:

1
2
3
4
ls -l /usr/local/include/nlopt.hpp
ls -l /usr/local/lib/libnlopt.so
ldconfig
ldconfig -p | grep nlopt

项目明确查找 /usr/local/lib/libnlopt.so。如果动态库被安装到了 /usr/local/lib64,重新执行第二节的 CMake 命令,并保留 -DCMAKE_INSTALL_LIBDIR=lib

3. RViz 无法打开或提示 X11 权限错误

先退出到宿主机,确认容器仍然按照《Docker使用教程》挂载了 /tmp/.X11-unix.Xauthority,然后执行:

1
xhost +SI:localuser:root

再使用第五节中带 DISPLAYdocker exec 命令进入容器并启动 RViz。

4. RViz 中有地图,但点击目标后没有轨迹

依次检查输入和输出:

1
2
3
rostopic echo -n 1 /move_base_simple/goal
rostopic echo -n 1 /waypoint_generator/waypoints
rostopic echo -n 1 /planning/bspline

每条命令都应先运行,再回到 RViz 发送一次新目标。同时确认目标位于地图范围内、没有落在障碍物中,并且当前只运行了一个规划 Demo。

参考资料