跳到主要内容C++ 使用 OMPL 库实现 RRT*与 Informed RRT*路径规划对比 | 极客日志C++AI算法
C++ 使用 OMPL 库实现 RRT*与 Informed RRT*路径规划对比
综述由AI生成OMPL 库在 C++ 中的路径规划应用,演示了 RRT*与 Informed RRT*算法的对比。通过定义状态有效性检查函数处理圆形及矩形障碍物,提供完整的编译运行流程及 Python 可视化脚本。文章涵盖安装步骤、代码实现、参数配置及结果分析,帮助开发者快速掌握基于采样的高级运动规划方法及其优化策略。
全栈工匠29 浏览 我们来用 C++ 和 OMPL 库 实现一个完整的 Informed RRT* vs RRT* 对比 Demo。
这个程序会:
- 在 2D 空间中规划路径
- 使用相同的环境(起点、终点、障碍物)
- 分别运行
RRT* 和 Informed RRT*
- 输出:是否找到解、最终路径长度、以及中间过程的优化趋势
- 可视化数据可通过输出文件绘图(如 Python / MATLAB)
一、安装 OMPL(C++ 版)
sudo apt-get install libompl-dev
git clone https://github.com/ompl/ompl.git
cd ompl && mkdir build && cd build
cmake ..
make -j4
sudo make install
二、完整 C++ 代码(compare_rrt_star.cpp)
#include <ompl/base/SpaceInformation.h>
#include <ompl/base/spaces/RealVectorStateSpace.h>
#include <ompl/geometric/planners/rrt/RRTstar.h>
#include <ompl/geometric/planners/rrt/InformedRRTstar.h>
#include <ompl/geometric/SimpleSetup.h>
#include <ompl/base/objectives/PathLengthOptimizationObjective.h>
#include <iostream>
#include <fstream>
#include <vector>
namespace ob = ompl::base;
og = ompl::geometric;
{
* s = state-><ob::RealVectorStateSpace::StateType>();
x = s->values[];
y = s->values[];
(x*x + y*y) >= ;
}
{
std::cout << << plannerName << << std::endl;
;
ss.(obj);
ss.(planner);
ob::ScopedState<>(ss.());
ob::ScopedState<>(ss.());
start-><ob::RealVectorStateSpace::StateType>()->values[]=;
start-><ob::RealVectorStateSpace::StateType>()->values[]=;
goal-><ob::RealVectorStateSpace::StateType>()->values[]=;
goal-><ob::RealVectorStateSpace::StateType>()->values[]=;
ss.(start, goal);
ob::PlannerStatus solved = ss.();
(solved){
std::cout << plannerName << << std::endl;
ss.();
&path = ss.();
length = path.();
smoothness = path.();
std::cout << plannerName << << length << std::endl;
logFile << plannerName << << length << << path.() << std::endl;
;
path.(pf);
pf.();
}{
std::cout << plannerName << << std::endl;
logFile << plannerName << << std::endl;
}
}
{
;
space->(,);
;
ss.(isStateValid);
ss.()->();
;
logFile << ;
rrtstar = std::<og::RRTstar>(ss.());
rrtstar->();
rrtstar->();
rrtstar->();
(, rrtstar, ss, logFile);
ss.();
informed_rrtstar = std::<og::InformedRRTstar>(ss.());
informed_rrtstar->();
informed_rrtstar->();
informed_rrtstar->();
(, informed_rrtstar, ss, logFile);
logFile.();
std::cout << << std::endl;
;
}
namespace
bool isStateValid(const ob::State *state)
const
auto
as
double
0
double
1
return
1.0
void planWithPlanner(const std::string& plannerName, const ob::PlannerPtr& planner, og::SimpleSetup& ss, std::ofstream& logFile)
"\n=== Running "
" ==="
auto obj(std::make_shared<ob::PathLengthOptimizationObjective>(ss.getSpaceInformation()))
setOptimizationObjective
setPlanner
start
getStateSpace
goal
getStateSpace
as
0
-4.0
as
1
-4.0
as
0
4.0
as
1
4.0
setStartAndGoalStates
solve
10.0
if
": Found solution!"
simplifySolution
const
auto
getSolutionPath
double
length
double
smoothness
" Final Path Length: "
","
","
getStateCount
std::ofstream pf((plannerName + "_path.csv").c_str())
printAsMatrix
close
else
": No solution found."
",inf,0"
int main()
auto space(std::make_shared<ob::RealVectorStateSpace>(2))
setBounds
-5.0
5.0
og::SimpleSetup ss(space)
setStateValidityChecker
getSpaceInformation
setStateValidityCheckingResolution
0.01
std::ofstream logFile("results.csv")
"Planner,PathLength,NumStates\n"
auto
make_shared
getSpaceInformation
setRange
0.5
setGoalBias
0.05
setRewireFactor
1.2
planWithPlanner
"RRT*"
clear
auto
make_shared
getSpaceInformation
setRange
0.5
setGoalBias
0.05
setRewireFactor
1.2
planWithPlanner
"InformedRRT*"
close
"\n✅ Results saved to 'results.csv' and path files."
return
0
三、编译与运行
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(ompl_rrt_comparison)
set(CMAKE_CXX_STANDARD 17)
find_package(OMPL REQUIRED)
add_executable(compare_rrt_star compare_rrt_star.cpp)
target_link_libraries(compare_rrt_star ${OMPL_LIBRARIES})
mkdir build && cd build
cmake ..
make
./compare_rrt_star
四、输出说明
results.csv:包含两个算法的路径长度对比
RRT*_path.csv 和 InformedRRT*_path.csv:路径坐标点(可用 Python 绘图)
Planner,PathLength,NumStates
RRT*,9.65,87
InformedRRT*,8.32,73
五、可视化路径(Python 脚本)
import numpy as np
import matplotlib.pyplot as plt
def plot_path(filename, label, color):
data = np.loadtxt(filename, delimiter=' ')
plt.plot(data[:,0], data[:,1],'-o', label=label, color=color, markersize=4)
plt.figure(figsize=(8,8))
plot_path('RRT*_path.csv','RRT*','red')
plot_path('InformedRRT*_path.csv','Informed RRT*','blue')
circle = plt.Circle((0,0),1.0, color='gray', alpha=0.5)
plt.gca().add_patch(circle)
plt.xlim(-5,5)
plt.ylim(-5,5)
plt.xlabel("X")
plt.ylabel("Y")
plt.title("RRT* vs Informed RRT* Path Comparison")
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.show()
- Informed RRT* 更快绕过障碍,路径更接近直线
- RRT* 初始路径更曲折,收敛更慢
六、核心差异总结
| 特性 | RRT* | Informed RRT* |
|---|
| 采样区域 | 全局随机 | 椭圆区域(基于当前最优解) |
| 收敛速度 | 较慢 | ✅ 更快 |
| 路径质量 | 渐进最优 | ✅ 更快逼近最优 |
| 实现复杂度 | 简单 | 中等(需维护启发式采样) |
| 是否需要初始解 | ❌ 否 | ✅ 是(首次为全空间,之后缩小) |
🔍 原理:Informed RRT* 使用 informed sampling —— 只在'有可能找到更好解'的椭球区域内采样,避免无效探索。
七、总结
你现在已经拥有了一个完整的 C++ Demo,可以:
- 编译运行,比较两种算法性能
- 导出数据进行分析或发表论文
- 扩展到高维空间(如机械臂)、加入动力学约束等
障碍物配置详解
一、原代码中障碍物在哪里设置的?
在你提供的 C++ 代码中,障碍物是通过 状态有效性检查函数 isStateValid 定义的:
bool isStateValid(const ob::State *state){
const auto* s = state->as<ob::RealVectorStateSpace::StateType>();
double x = s->values[0];
double y = s->values[1];
return (x*x + y*y) >= 1.0;
}
🔍 关键点:OMPL 不直接建模障碍物几何体,而是通过 isStateValid() 函数判断某个状态(如机器人位置)是否'碰撞'。
所以,所有障碍物逻辑都写在这个函数里。
二、如何改成 10 个矩形障碍物?
假设每个矩形由 (xmin, xmax, ymin, ymax) 定义。我们可以定义一个矩形列表,然后在 isStateValid 中逐个检测是否与任意矩形相交。
修改后的代码如下:
#include <vector>
#include <utility>
#include <array>
using Rectangle = std::array<double,4>;
const std::vector<Rectangle> obstacles = {
{-3.0,-2.5,-1.0,1.0},
{2.0,2.5,-2.0,-1.0},
{0.0,1.0,2.0,3.0},
{-1.5,-0.5,3.0,4.0},
{3.0,4.0,0.0,1.0},
{-4.0,-3.0,-4.0,-3.0},
{1.5,2.5,1.5,2.5},
{-2.0,-1.0,-3.0,-2.0},
{0.5,1.5,-4.0,-3.0},
{-0.5,0.5,-0.5,0.5}
};
bool isStateValid(const ob::State *state){
const auto* s = state->as<ob::RealVectorStateSpace::StateType>();
double x = s->values[0];
double y = s->values[1];
for(const auto& rect : obstacles){
double xmin = rect[0], xmax = rect[1];
double ymin = rect[2], ymax = rect[3];
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax){
return false;
}
}
return true;
}
✅ 说明:矩形是 轴对齐(AABB),即边平行于坐标轴。如果你需要旋转矩形,需用更复杂的点 - 多边形包含判断(可用 Eigen 或自定义)。这种方式适用于静态障碍物。动态障碍物需结合时间维度(OMPL 支持时态规划,但更复杂)。
三、完整整合建议
把 obstacles 定义放在 main() 外部(全局或命名空间),或者封装成一个类(推荐用于大型项目)。
如果你希望 可视化这些矩形,可以在 Python 绘图脚本中添加:
import matplotlib.patches as patches
for rect in [[-3.0,-2.5,-1.0,1.0],[2.0,2.5,-2.0,-1.0]]:
xmin, xmax, ymin, ymax = rect
width = xmax - xmin
height = ymax - ymin
rect_patch = patches.Rectangle((xmin, ymin), width, height, linewidth=1, edgecolor='black', facecolor='gray', alpha=0.6)
plt.gca().add_patch(rect_patch)
四、进阶提示(可选)
| 需求 | 建议 |
|---|
| 障碍物很多(>100) | 用 空间加速结构(如 KD-Tree、Grid Hash)避免 O(n) 检测 |
| 任意多边形障碍 | 将障碍物表示为顶点列表,使用 射线法 判断点是否在多边形内 |
| 机器人有尺寸 | 使用 Minkowski 和膨胀障碍物,或将机器人视为点 + 膨胀障碍 |
| 动态障碍 | 引入时间维度,状态变为 (x, y, t),障碍物随时间移动 |
五、总结
- 障碍物逻辑在
isStateValid() 函数中
- 10 个矩形 = 定义 10 个
[xmin,xmax,ymin,ymax],循环检测点是否在其内部
- 返回
false 表示碰撞(无效),true 表示自由空间(有效)
你现在可以自由设计任意数量、任意位置的矩形障碍物了!
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online