路径跟踪算法---Stanley Method实现

文章目录

  • 前言
  • 一、Stanley原理介绍
  • 二、主要代码实现
  • 三、效果


前言

Stanley Controller也是基于几何追踪的轨迹跟踪控制器,和Pure Pursuit不同的是,其基于前轮中心点为参考点进行控制,没有预瞄距离,以前轮中心点与最近参考轨迹点进行横向误差与导航角误差的计算。


一、Stanley原理介绍

在这里插入图片描述

如图,黑色曲线表示预设路径,红色方框表示车辆当前运动状态,偏离预设路径,使用Stanley Controller的目的是让车辆追踪预设路径,通过控制车的转向,使其靠近预设路径,图中黑色方框代表期望状态。图中红色箭头表示车辆实际运动方向,黑色箭头表示期望车辆运动方向,绿色虚线表示距离车辆最近路径点的切线,e_y 表示车与路径的最短距离,即横向偏差,θ e 为切线与实际运动方向的夹角,即航向偏差,δ e 表示期望运动方向与切线的夹角。

假定车辆实际位置在预设路径上,此时没有横向偏差,只需要转过 θe 角度即可,期望车辆转过的角度为:
δ = θ e θ e = θ r − θ x \ δ = θe \\ θe = θr - θx  δ=θeθe=θrθx
假定车辆实际运动方向与切线方向一致,此时没有航向偏差,只有横向偏差。车辆当前速度为v,t时间内运动距离为d,和速度存在一个系数k。
δ = δ e d = v / k t a n δ e = e y / d = k ∗ e y / v δ e = t a n − 1 ( k e y / v ) \ δ = δe \\ d = v / k \\tan δ e = e_y / d = k *e_y / v \\ δ e = tan^{-1}(k e_y/v)  δ=δed=v/ktanδe=ey/d=key/vδe=tan1(key/v)
同时,转向角不能任意,需要进行限幅处理,此时期望车转过的角度为(加入时间变化):
δ ( t ) = δ e ( t ) + θ e ( t ) = θ e ( t ) + t a n − 1 ( k e y ( t ) / v ( t ) ) , δ ( t ) ∈ [ δ m i n , δ m a x ] \ δ (t) = δ e(t) + θe(t) = θe(t) + tan^{-1}(k e_y(t)/v(t) ),δ (t) ∈ [δmin,δmax]  δ(t)=δe(t)+θe(t)=θe(t)+tan1(key(t)/v(t)),δ(t)[δmin,δmax]

二、主要代码实现

首先,需要发布路径,话题名为"/rc_path_pub",发布路径实现可参考博客读取机器人移动轨迹并在RVIZ界面中显示。
其次,作为测试仅仅将获取到的导航角偏差 δ ×一个比例系数作为角速度,预设的速度 v 作为线速度发送到底盘进行控制,因为用的模型是差速模型,没有进行角度限幅处理,实际想达到好的实验结果,可能需要将导航角偏差送到 pid 控制器进行实际的速度计算。代码参考知乎:Raiden

using path_type = std::pair<std::pair<double, double>, double>;//用amcl定位获取机器人位姿效果不好,故采用odom位姿,也可用其他定位方式void StanleyController::robotPoseCallBack(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg){// yaw =tf::getYaw(msg->pose.pose.orientation);// tf::pointMsgToTF(msg->pose.pose.position,current_pose);}void StanleyController::OdomCallback(const nav_msgs::Odometry::ConstPtr& odom_msg) {yaw =tf::getYaw(odom_msg->pose.pose.orientation);tf::pointMsgToTF(odom_msg->pose.pose.position,current_pose);}//两点间距离auto StanleyController::distance(path_type p1,path_type p2) -> double{return sqrt(pow(p1.first.first-p2.first.first,2) +pow(p1.first.second-p2.first.second,2));}//最近距离路径点索引auto StanleyController::GetMinDisIndex(path_type current_pose, std::vector<path_type> path) -> int{double min_dis = INFINITY;int idx = 0;for(int i = 0;i<path.size();i++){double dis  = distance(path[i],current_pose);if(dis < min_dis){min_dis = dis;idx = i;}}return idx;}void StanleyController::robotPathCallBack(const nav_msgs::PathConstPtr& msg){if(recv_path_flag){nav_path_.poses = msg->poses;recv_path_flag = false;start_pose_.position.x = nav_path_.poses[0].pose.position.x;start_pose_.position.y = nav_path_.poses[0].pose.position.y;path_vector.clear();for(int i = 0;i<nav_path_.poses.size();i++){path_type temp_path = std::make_pair(std::make_pair(nav_path_.poses[i].pose.position.x,nav_path_.poses[i].pose.position.y),tf::getYaw(nav_path_.poses[i].pose.orientation));path_vector.push_back(temp_path);}}}void StanleyController::run(){cmd_vel_pub = n_.advertise<geometry_msgs::Twist>("/cmd_vel",1);pose_sub = n_.subscribe<geometry_msgs::PoseWithCovarianceStamped>("amcl_pose",10,std::bind(&StanleyController::robotPoseCallBack,this,std::placeholders::_1));path_sub = n_.subscribe<nav_msgs::Path>("/rc_path_pub",10,std::bind(&StanleyController::robotPathCallBack,this,std::placeholders::_1));real_path_pub = n_.advertise<nav_msgs::Path>("rvizpath", 100, true);odom_pose_sub = n_.subscribe<nav_msgs::Odometry>("odom", 10, std::bind(&StanleyController::OdomCallback, this, std::placeholders::_1));ros::Rate loop_rate(10);recv_path_flag = true;path.header.frame_id = "/map";path.header.stamp = ros::Time::now();path_type init_pose = std::make_pair(std::make_pair(0.0,0.0),0.0);path_type now_pose = init_pose;while(ros::ok()){now_pose.first.first = current_pose.x();now_pose.first.second = current_pose.y();now_pose.second = yaw;//判断获取到路径if(path_vector.size()>0){int current_idx = GetMinDisIndex(now_pose,path_vector);path_type cur_path_point = path_vector[current_idx];//横向偏差double e_y = distance(now_pose,cur_path_point);e_y = (now_pose.first.second - cur_path_point.first.second) * cos(cur_path_point.second) - (now_pose.first.first - cur_path_point.first.first) * sin(cur_path_point.second) <=0 ? e_y : -e_y;//航向偏差,转到-PI 到 +PI之间double theta_e =  cur_path_point.second -now_pose.second ;  //参考点航向 - 自车航向角if(theta_e > M_PI){ theta_e = theta_e - 2* M_PI;} else if(theta_e < -M_PI){theta_e = theta_e + 2* M_PI;}//转角,限幅double delta =( theta_e + atan2(factor * e_y, speed) );// if(delta > M_PI/3){//     delta = M_PI/3;// } else if(delta < -M_PI/3){//     delta = -M_PI/3;// }//直接把转角当作角速度vel.linear.x = speed;vel.angular.z = delta * 2.5;cmd_vel_pub.publish(vel);}ros::spinOnce();loop_rate.sleep();}}

三、效果

最后,放一张效果图~~~
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/39762.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

天诚长租公寓智能门锁管理解决方案

人才是区域创新发展的第一资源&#xff0c;如何解决人才的住房问题&#xff0c;让人才“流进来”、“留下来”、“融进来”&#xff0c;就需要优先安排优质人才公寓、人才优租房和公共租赁住房房源&#xff0c;并为青年人才群体提供智能化、信息化的租住体验及通行服务。 一、…

四、(1)网络爬虫入门及准备工作(爬虫及数据可视化)

四、&#xff08;1&#xff09;网络爬虫入门及准备工作&#xff08;爬虫及数据可视化&#xff09; 1&#xff0c;网络爬虫入门1.1 百度指数1.2 天眼查1.3 爬虫原理1.4 搜索引擎原理 2&#xff0c;准备工作2.1 分析爬取页面2.2 爬虫拿到的不仅是网页还是网页的源代码2.3 爬虫就是…

数据库完整性约束:确保数据准确性的关键

目录 &#x1f397;一、实体完整性 示例&#xff1a;定义主键 &#x1f38a;二、参照完整性 示例&#xff1a;定义外键 &#x1f380;三、域完整性 示例&#xff1a;定义非空和唯一约束 &#x1f381;四、用户定义的完整性 示例&#xff1a;定义自定义约束 &#x1f3…

arthas监控工具笔记(二)monior等

文章目录 monitor/watch/trace 相关monitormonitor例子monitor -c <value>monitor -m <vaule>monitor 条件表达式monitor -b monitor文档(界面描述)monitor文档(help) stack - 输出当前方法被调用的调用路径trace - 方法内部调用路径&#xff0c;并输出方法路径上的…

c++中c_str()及atof()和stod()的用法详细解析

文章目录 函数作用语法及返回值使用方法1使用方法2atof函数的用法std::stod()函数的用法小结 函数作用 功能&#xff1a;c_str() 函数可以将 const string* 类型 转化为 const char* 类型 头文件&#xff1a;#include<cstring> 为了与c语言兼容&#xff0c;在c语言…

app单页下载页源码带管理后台

新版带后台管理APP应用下载页,自动识别安卓苹果下载页&#xff0c;带管理后台&#xff0c;内置带3套App下载模板带中文模板/英文模板随时切换。 app单页下载页源码带管理后台

nginx 配置文件location块中符号的含义

nginx -t 检查配置文件语法问题 nginx -s reload 重新加载conf文件 location 块 表示精确匹配 ~ 这个符号开头表示区分大小写 * 一般和 ~ 公用, ~* 表示不区分大小写 ^ 表示正则的开始 前缀匹配&#xff1a;默认的匹配方式&#xff0c;不带修饰符&#xff0c;匹配…

自动装配在Spring框架中的原理与实现方式

自动装配在Spring框架中的原理与实现方式 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 自动装配的概念与背景 在Spring框架中&#xff0c;自动装配&#x…

告别PS修图,设计师都在用的AI抠图工具

引言 大家好&#xff01;如果你是美工或设计师&#xff0c;肯定深知Photoshop修图的繁琐和耗时。现在有一款超方便的工具&#xff0c;让你摆脱这些问题——千鹿设计助手。它不仅是个抠图工具&#xff0c;还能通过先进的AI技术&#xff0c;让抠图变得简单快速&#xff0c;让你专…

[Leetcode 128][Medium] 最长连续序列

目录 题目描述 整体思路 具体代码 题目描述 原题链接 整体思路 首先看到找连续升序排序的最长序列长度&#xff0c;想到对数组进行排序预处理。但是排序算法时间复杂度需要O(nlogn)&#xff0c;题目要求时间复杂度为O(n)。因此不能进行排序与处理 接着想到数据结构哈希表&a…

Laravel 文件操作全指南:上传与下载实践

Laravel 提供了一系列强大的工具来简化文件上传和下载的过程&#xff0c;使得在 Web 应用程序中处理文件变得更加容易和安全。本文将详细介绍如何在 Laravel 中实现文件的上传和下载&#xff0c;包括表单创建、路由设置、控制器逻辑以及安全性考虑。 文件上传基础 文件上传是…

为什么网上商店需要翻译成其他语言

网上商店不仅仅是一个可以买到商品的网站。它是一个完整的电子商务平台&#xff0c;为来自世界各地的用户提供购买所需物品的机会。但是&#xff0c;为了让这些用户舒适地使用网站&#xff0c;需要高质量的翻译和本地化。 本地化是指产品或服务适应特定文化或市场的过程。它包…

问题 P: 表达式树的值

问题 P: 表达式树的值 题目描述 读入表达式树的先序遍历字符串&#xff0c;求其值。运算符只可能是加减乘除&#xff0c;保证输入的每个子表达式树的结果都是整数值且可以用C语言的int类型表达。 输入 输入由多组测试数据组成。 每组数据包含一行字符串&#xff0c;即表达式…

Nginx详解-安装配置等

目录 一、引言 1.1 代理问题 1.2 负载均衡问题 1.3 资源优化 1.4 Nginx处理 二、Nginx概述 三、Nginx的安装 3.1 安装Nginx 3.2 Nginx的配置文件 四、Nginx的反向代理【重点】 4.1 正向代理和反向代理介绍 4.2 基于Nginx实现反向代理 4.3 关于Nginx的location路径…

CSS 文本输入框右下角的尺寸控件(三斜线:-webkit-resizer)消除,以及如何配置其样式,添加 resize 让标签元素可进行拖拽放大。

前言&#xff1a;在日常的前端开发中&#xff0c;不管是原始的和 还在在各类组件库中的文本输入框中&#xff0c;元素内容的右下角总是有一个三斜线的样式&#xff0c;本文简单了解它是什么&#xff1f;如何去控制并修改样式&#xff1f; 一、它是&#xff1f; 这三个斜线其实…

echarts实现3D柱状图(视觉层面)

一、第一种效果 效果图 使用步骤 完整实例&#xff0c;copy就可直接使用 <template><div :class"className" :style"{height:height,width:width}" /> </template><script>import echarts from echartsrequire(echarts/theme/…

leetcode基础算法刷题汇总

前言 总结算法刷题的一些模板和刷题规律。 目录 单调栈并查集滑动窗口前缀和 & HASH差分拓扑排序字符串二分查找BFSDFS动态规划贪心算法字典树

Python面向对象编程:派生

本套课在线学习视频&#xff08;网盘地址&#xff0c;保存到网盘即可免费观看&#xff09;&#xff1a; ​​https://pan.quark.cn/s/69d1cc25d4ba​​ 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它通过将数据和操作数据的方法封装在一起&#xff0…

Qt通过句柄获取其它进程控件实例

1.通过spy获取想要获取控件的句柄id 通过spy获取另一个软件的文本框的句柄 2.Qt写代码&#xff0c; 根据句柄获取文本框的内容 void getTextFromExternalWindow(HWND hwnd) {const int bufferSize 256;TCHAR buffer[bufferSize];// 获取窗口文本内容int length GetWindowT…

一文读懂企业为什么需要数字工厂管理系统

在当今这个日新月异的数字化时代&#xff0c;企业面临着前所未有的挑战与机遇。为了在激烈的市场竞争中保持领先地位&#xff0c;实现高效、灵活、可持续的生产运营&#xff0c;企业纷纷转向数字化转型&#xff0c;而数字工厂管理系统作为其中的关键一环&#xff0c;正逐步成为…