Hybrid Astar 算法剖析和实现

Posted 穿越临界点

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hybrid Astar 算法剖析和实现相关的知识,希望对你有一定的参考价值。

在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的无效信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。

文章目录

0 前言

本篇介绍一种简单高效的凸多边形碰撞检测方案,以及代码实现。

1 AABB碰撞检测算法

1.1 原理

AABB(Axis-Aligned Bounding Box)碰撞检测方法法全称为基于轴向包围框的碰撞检测方法。

假设有A和B两个凸多边形,将它们的顶点投影到x轴,A对应的区间为 [ x A L , x A H ] [x_AL,x_AH] [xAL,xAH] ,B对应的区间为 [ x B L , x B H ] [x_BL,x_BH] [xBL,xBH]。如果这两个区间不相交,则一定不会发生碰撞,如果相交,则再将它们的顶点投影到y轴进行判断,如果投影到y轴的两个区间不相交,则一定不会发生碰撞,如果相交,对于AABB方法来说,则认为会发生碰撞。

其实,A和B两个突多边形在x轴和y轴的投影分别都有重叠,也并不一定会发生碰撞,但对于粗略判断来说,可以认为发生碰撞。

因此,AABB方法只能作为碰撞的粗略检测方案。但它的优点是速度快,因为向x轴和y轴投影就是顶点的横纵坐标值。

1.2 代码实现

示例代码如下。代码比较简单就不过多解释了。

template<int dim>
using TypeVectorVecd = typename std::vector<Eigen::Matrix<double, dim, 1>,
        Eigen::aligned_allocator<Eigen::Matrix<double, dim, 1>>>;
typedef TypeVectorVecd<2> VectorVec2d;

bool checkCollisionAABB(const Eigen::MatrixXd& vehicle, const std::vector<VectorVec2d>& obstacles)

    std::vector<double> vhxvehicle.block<8,1>(0,0)[0], 
                            vehicle.block<8,1>(0,0)[2], 
                            vehicle.block<8,1>(0,0)[4], 
                            vehicle.block<8,1>(0,0)[6];
    std::vector<double> vhyvehicle.block<8,1>(0,0)[1], 
                            vehicle.block<8,1>(0,0)[3], 
                            vehicle.block<8,1>(0,0)[5], 
                            vehicle.block<8,1>(0,0)[7];

    double vhx_max = *max_element(vhx.begin(), vhx.end());
    double vhx_min = *min_element(vhx.begin(), vhx.end());

    double vhy_max = *max_element(vhy.begin(), vhy.end());
    double vhy_min = *min_element(vhy.begin(), vhy.end());

    for (auto obs: obstacles) 
        double obsx_max = std::numeric_limits<double>::min();
        double obsx_min = std::numeric_limits<double>::max();
        double obsy_max = std::numeric_limits<double>::min();
        double obsy_min = std::numeric_limits<double>::max();

        for (auto point: obs) 
            if (point.x() > obsx_max) 
                obsx_max = point.x();
            if (point.x() < obsx_min) 
                obsx_min = point.x();
            if (point.y() > obsy_max) 
                obsy_max = point.y();
            if (point.y() < obsy_min) 
                obsy_min = point.y();
        
        
        if (vhx_min > obsx_max || 
            vhx_max < obsx_min || 
            vhy_min > obsy_max || 
            vhy_max < obsy_min) 
            continue;
         else 
            return true;
        

    

    return false; 


2 SAT碰撞检测算法

2.1 原理

基于SAT(Separating Axis Theorem)进行碰撞检测的原理其实也很简单,本质上是AABB方法的升级版。

都是做投影,只不过AABB是将顶点投影到x轴和y轴,而SAT是自己创建轴,然后再将两个凸多边形的顶点投影过去,查看是否有重叠区域。

创建轴的方法就是计算凸多变形每条边的法向量。

2.2 代码实现

示例代码如下。

其中,需要注意两点。一个是计算分离轴时不要忘记对闭合凸多边形的处理;另一个是计算法向量时需要对平行于坐标轴的情况进行特殊处理。

bool checkCollisionSAT(const Eigen::MatrixXd& vehicle, const VectorVec2d& obs)

    //1.find all axis of vehicle
    VectorVec2d vaxis;
    for (std::size_t i = 0; i < 2u; ++i) 
        auto vtemp0 = vehicle.block<2,1>(2*i,0);
        auto vtemp1 = vehicle.block<2,1>(2*(i+1),0);
        auto vaxi = vtemp1 - vtemp0;
        vaxis.push_back(vaxi);
    

    //2.find all axis of obstacle
    for (std::size_t j = 0; j < obs.size(); ++j) 
        auto dx = obs[(j+1) % obs.size()][0] - obs[j][0]; //使用取余运算处理凸多边形首尾衔接问题
        auto dy = obs[(j+1) % obs.size()][1] - obs[j][1];

        Eigen::Vector2d oaxi;
        if (dx != 0)
            oaxi << dy/dx, -1;
        else //对平行于y轴的情况进行特殊处理
            oaxi << 1, 0;

        vaxis.push_back(oaxi);
    

    //3.project
    for (auto axi: vaxis) 
        //3.1 cal projection of vehicle
        std::vector<double> vpros;
        for (std::size_t i = 0; i < 4u; ++i)  
            auto vtemp = vehicle.block<2,1>(2*i,0);
            double pro = vtemp.dot(axi);
            vpros.push_back(pro);
        

        //3.2 cal projection of obstacle
        std::vector<double> opros;
        for (std::size_t j = 0; j < obs.size(); ++j) 
            auto x = obs[j][0];
            auto y = obs[j][1];
            Eigen::Vector2d vec(x,y);
            double pro = vec.dot(axi);
                       opros.push_back(pro);
        

        //3.3 judge collision
        auto vmax = *max_element(vpros.begin(), vpros.end());
        auto vmin = *min_element(vpros.begin(), vpros.end());
        auto omax = *max_element(opros.begin(), opros.end());
        auto omin = *min_element(opros.begin(), opros.end());
        if (vmax < omin || vmin > omax) 
            return false;
        
    
    
    return true; 

3 加速方案

3.1 方案设计

最终的碰撞检测方案是将AABB和SAT方法结合使用。先使用AABB粗筛,然后使用SAT精确计算车辆和障碍物是否发生碰撞。

细节实现上可以通过下述技巧进行加速:

  1. 在SAT中使用法向量计算公式,不使用反三角函数。
  2. 在SAT中提前计算好所有障碍物的分离轴,保存在障碍物的数据结构中。
  3. 在SAT中只考虑车辆周边有限范围内的障碍物(可以请定位同事给障碍物打上标签)。
  4. 在SAT中去除平行分离轴,避免重复投影和判断。

3.2 代码实现

代码实现如下。

//入参是车辆当前位姿
bool checkCollision(const double &x, const double &y, const double &theta) 

    Mat2d R;
    R << std::cos(theta), -std::sin(theta),
            std::sin(theta), std::cos(theta);

    Eigen::MatrixXd vehicle_shape;
    vehicle_shape.resize(8, 1);

    //坐标变换
    for (unsigned int i = 0; i < 4u; ++i) 
        transformed_vehicle_shape.block<2, 1>(i * 2, 0) = 
            R * vehicle_shape_.block<2, 1>(i * 2, 0) + Vector2d(x, y);
    

    //AABB
    if (!checkCollisionAABB(vehicle_shape, obstacles_)) 
        return false;
    

    //SAT
    for (auto obs: obstacles_) 
        if (!checkCollisionSAT(vehicle_shape, obs)) 
            continue;
         else 
            return true;
        
    
    return false;

4 总结

本篇基于AABB和SAT实现了一种较快速的碰撞检测方案,并在实现细节上给出了建议。

恭喜你又坚持看完了一篇博客,又进步了一点点!如果感觉还不错就点个赞再走吧,你的点赞和关注将是我持续输出的哒哒哒动力~~

以上是关于Hybrid Astar 算法剖析和实现的主要内容,如果未能解决你的问题,请参考以下文章

Hybrid Astar 算法剖析和实现

Hybrid Astar 算法剖析和实现

Hybrid Astar 算法剖析和实现

Hybrid Astar 算法剖析和实现

Hybrid Astar 算法剖析和实现

Hybrid Astar 算法剖析和实现