规控常见面试问题合集

一、你在项目中遇到的最有挑战的一件事情是什么?或者说有没有遇到什么困难?

二、A*算法原理(伪代码)

输入:代价地图、start 、 goal(Node结构,包含x、y、g、h、id、pid信息)

首先初始化:创建一个优先级队列openlist,它是一个最小堆,根据节点的f值排序 ( priority_queue<Node, std::vector<Node>, Node::compare_cost> openlist);

再创建一个无序集合unordered_map哈希表 closelist,用来存放已访问的节点 , 其键是节点的id (unordered_map<int, Node> closelist);

然后再将起点start 加入到openlist中 (openlist.push(start));

  • 进入while 循环 ,当openlist不为空时 ,执行以下步骤:

* 从 openlist 中取出具有最小f值的节点,称为 current 节点,并将其从 openlist 中移除,

* 将 current 节点添加到 closelist 中。

* 如果当前节点current是目标点goal,则从当前点回溯到起点 ,返回路径path;

否则,对于 current 节点的每个邻域节点 w:(分三种情况)

  • 如果 w 是障碍物或已在 closelist 中,则continue,忽略它并继续下一个循环
  • 如果 w 不在 openlist 里面 , 将其加入 openlist 中,
  • 如果 w在openlist里面(需要判断是否更新他的父节点,是current还是current.parent),检查是否通过 current 节点到达 w 的路径更优(即具有更小的g值):f(w) > f(n)+d(w,n)+h(w)

如果g值更小 , 则更新w的父节点为当前节点n 并更新 他的g值g(w) = f(n)+d(w,n)

------ 则:f(w) = f(n)+d(w,n)+h(w) --------

------ w.parent = n. -----------

最终没有路径的话就返回false。

核心代码:

 bool Astar::plan(const Node& start, const Node& goal, std::vector<Node>& path, std::vector<Node>& expand) {
     // clear vector
     path.clear();
     expand.clear();

     // openlist  and   closelist
     std::priority_queue<Node, std::vector<Node>, Node::compare_cost> openlist;// 底层queue内部使用vector容器,比较器实现最小堆(从小到大)
     //  return (n1.g() + n1.h() > n2.g() + n2.h()) || ((n1.g() + n1.h() == n2.g() + n2.h()) && (n1.h() > n2.h()));
     std::unordered_map<int, Node> closelist;
     
     openlist.push(start);

     // get all possible motions
     const std::vector<Node> motions = Node::getMotion();// 8领域的坐标x y 和 g

     //main process
     while (!openlist.empty())
     {
         // pop current node from openlist
         Node current = openlist.top();
         openlist.pop();

        
         if (closelist.find(current.id()) != closelist.end())continue; // 如果闭列表里面有current节点,跳过while循环

         //if current node does not exists in closelist
         closelist.insert(std::make_pair(current.id(), current)); // 将current加入到closelist中
         expand.push_back(current);

         //goal found 
         if (current == goal) {
             path = _convertClosedListToPath(closelist, start, goal);// 回溯父节点找到路径
             return true;
         }

         //explore neighbor of current Node
         for (const auto& motion : motions) {
             //explore a new node
             Node node_new = current + motion;
             node_new.set_id(grid2Index(node_new.x(), node_new.y()));

             // if node_new in closelist
             if (closelist.find(node_new.id()) != closelist.end())continue;

             // if node_new is not in closelist
             node_new.set_pid(current.id());//设置node_new的父节点id 

             // next node hit the boundary or obstacle   碰撞检查:没有超出地图边界并且没有碰到障碍物
             // prevent planning failed when the current within inflation   防止current点在障碍物的膨胀区域
             if ((node_new.id() < 0) || (node_new.id() >= map_size_) || //超出地图边界
                 (costmap_->getCharMap()[node_new.id()] >= costmap_2d::LETHAL_OBSTACLE * factor_ &&   //检查 node_new 对应的成本地图 costmap_ 中的值是否表示障碍物
                     costmap_->getCharMap()[node_new.id()] >= costmap_->getCharMap()[current.id()])) //比较 node_new 和当前节点 current 在成本地图中的成本值
                 continue;
            // 如果周围点在openlist中(表面该邻居已有父节点),计算该父节点经过当前点n再到周围点是否使其能够得到更小的g,如果可以,将该周围点的父节点设置为当前点n,并更新其g和h值。

             // if using dijkstra implementation, do not consider heuristics cost
             if (!is_dijkstra_) {
                 node_new.set_h(helper::dist(node_new, goal));//hypot(node1.x() - node2.x(), node1.y() - node2.y())
                 // node_new 到 goal 的直线欧式距离
             }


             // if using GBFS implementation, only consider heuristics cost
             if (!is_gbfs_) {
                 node_new.set_g(0.0);
             }

             openlist.push(node_new);// 将周围的可行邻域加入 openlist 中

         }
     }

     return false;// can't find a path 
 }

三、在决策规划中常用的非线性数值优化算法

1、牛顿法

对目标函数进行二阶泰勒近似,需要计算hessian矩阵:

f(x)/(x-x_new) = f'(x);
x_new = x - f(x)/f'(x);

牛顿法原本是求解函数零点的数值计算方法,利用迭代的方式逼近0点;

利用牛顿法求解函数极值的话,需要求解原函数一阶导的表达式,然后再对这个一阶函数使用牛顿法求解0点,需要求解原函数的二阶导。

2、梯度下降法

对目标函数进行一阶泰勒近似:

x_new = x - LearningRate * func_prime(x);
// 无约束优化算法
//
// Created by lg on 2024/7/12.
//
#include<iostream>
#include<cmath>

constexpr double eps = 1e-6;
constexpr double Delta = 1e-4;

//原函数
double func(const double& x) {
        return  x * x - 4 * x;
}

//原函数的一阶导
double func_prime(const double& x) {
        return (func(x + Delta) - func(x - Delta)) / (2 * Delta);
}

//原函数的一阶导
double func_prime2(const double& x) {
        return 2 * x - 4;;
}

double GradientDescent(const double& x0, const double& LearningRate) {
        double x = x0;
        double x_new = x - LearningRate * func_prime(x);
        while (abs(x_new-x)>eps)
        {
                x = x_new;
                x_new = x - LearningRate * func_prime(x);
        }
        return x;
}

int main() {
        std::cout << GradientDescen

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

自动驾驶/机器人C++八股精选 文章被收录于专栏

在自动驾驶和机器人领域,C++因其高性能、内存管理高效和跨平台兼容性等特性,被广泛应用。本专栏整理了C++面试中常遇到的八股问题,可私信作者要飞书文档,不论是嵌入式软开、算法、软件开发都可以阅读,包括了C++的虚函数、C++11新特性、C++的STL库、Linux常见命令......

全部评论
写得好!!!
2 回复 分享
发布于 2024-08-13 18:06 湖南
点赞 回复 分享
发布于 09-01 23:12 广东
主包现在在哪工作
点赞 回复 分享
发布于 09-01 23:12 广东
加油!
点赞 回复 分享
发布于 09-01 23:11 广东
厉害👍🏻👍🏻
点赞 回复 分享
发布于 09-01 23:11 广东
很厉害
点赞 回复 分享
发布于 09-01 23:11 广东
写的很详细哦
点赞 回复 分享
发布于 09-01 23:11 广东
面试有希望了
点赞 回复 分享
发布于 09-01 23:10 广东
写的很好
点赞 回复 分享
发布于 09-01 23:10 广东
好厉害
点赞 回复 分享
发布于 09-01 23:10 广东
同湖大
点赞 回复 分享
发布于 09-01 23:10 广东
校友
点赞 回复 分享
发布于 09-01 23:10 广东
太厉害了
点赞 回复 分享
发布于 09-01 23:10 广东
点赞 回复 分享
发布于 09-01 23:10 广东
期待更新!
点赞 回复 分享
发布于 09-01 23:08 广东
棒棒哒
点赞 回复 分享
发布于 09-01 23:08 广东
很厉害
点赞 回复 分享
发布于 09-01 23:08 广东
优秀
点赞 回复 分享
发布于 09-01 23:08 广东
太好了
点赞 回复 分享
发布于 09-01 23:08 广东
很棒
点赞 回复 分享
发布于 09-01 23:08 广东

相关推荐

搞机墨镜猫:生产实习放项目下面,简化一点,如果有更好的东西就可以直接替换掉,比如你说你拆过他们的伺服电机很了解结构,可以照着画一下写成项目 项目看看能不能再找一个课设之类的包装一下(别写减速器),两个项目比较好,把项目后面的三位建模几个字去掉(这样会觉得有实物)
机械人,你的秋招第一份简...
点赞 评论 收藏
分享
评论
15
89
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务