轨迹规划 | 图解路径跟踪PID算法(附ROS C++/Python/Matlab仿真)

news2024/10/5 20:17:24

目录

  • 0 专栏介绍
  • 1 PID控制基本原理
  • 2 基于PID的路径跟踪
  • 3 仿真实现
    • 3.1 ROS C++实现
    • 3.2 Python实现
    • 3.3 Matlab实现

0 专栏介绍

🔥附C++/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。

🚀详情:图解自动驾驶中的运动规划(Motion Planning),附几十种规划算法


1 PID控制基本原理

PID控制是一种常用的经典控制算法,其应用背景广泛,例如

  • 工业自动化控制:温度控制、压力控制、流量控制、液位控制等过程控制系统多采用PID闭环,可以帮助维持系统参数在设定值附近,以提高生产过程的稳定性和效率;
  • 机械工程:PID算法可用于实现精确的运动控制,包括控制位置、速度和力。这包括机器人控制、电机控制、汽车巡航控制等;
  • 农业自动化:PID算法可用于控制温室环境,包括温度、湿度和光照,以促进植物的生长和提高农业生产;

PID代表比例(Proportional)积分(Integral)微分(Derivative),它通过根据误差信号的大小和变化率来调整控制器的输出,以使系统的输出尽可能接近期望值,其控制框图如下所示

在这里插入图片描述

连续型PID控制律如下

u ( t ) = K p e ( t ) + K i ∫ t 0 t e ( τ ) d τ + K d e ˙ ( t ) u\left( t \right) =K_pe\left( t \right) +K_i\int_{t_0}^t{e\left( \tau \right) \mathrm{d}\tau}+K_d\dot{e}\left( t \right) u(t)=Kpe(t)+Kit0te(τ)dτ+Kde˙(t)

其中 K p K_p Kp K i K_i Ki K d K_d Kd分别称为比例、积分与微分增益系数

位置式离散型PID控制律如下

u ( k ) = K p e ( k ) + K i ∑ i = 0 k e ( i ) Δ t + K d ( e ( k ) − e ( k − 1 ) ) / Δ t u\left( k \right) =K_pe\left( k \right) +K_i\sum_{i=0}^k{e\left( i \right) \varDelta t}+K_d{{\left( e\left( k \right) -e\left( k-1 \right) \right)}/{\varDelta t}} u(k)=Kpe(k)+Kii=0ke(i)Δt+Kd(e(k)e(k1))/Δt

由于位置式PID算法需要计算累计偏差,占用存储单元,可以通过

u ( k ) − u ( k − 1 ) u\left( k \right) -u\left( k-1 \right) u(k)u(k1)

计算增量式PID控制律

Δ u ( k ) = K p Δ e ( k ) + K i e ( k ) Δ t + K d ( Δ e ( k ) − Δ e ( k − 1 ) ) / Δ t \varDelta u\left( k \right) =K_p\varDelta e\left( k \right) +K_ie\left( k \right) \varDelta t+K_d{{\left( \varDelta e\left( k \right) -\varDelta e\left( k-1 \right) \right)}/{\varDelta t}} Δu(k)=KpΔe(k)+Kie(k)Δt+Kd(Δe(k)Δe(k1))/Δt

其中

Δ u ( k ) = u ( k ) − u ( k − 1 ) Δ e ( k ) = e ( k ) − e ( k − 1 ) \varDelta u\left( k \right) =u\left( k \right) -u\left( k-1 \right) \\ \varDelta e\left( k \right) =e\left( k \right) -e\left( k-1 \right) Δu(k)=u(k)u(k1)Δe(k)=e(k)e(k1)

2 基于PID的路径跟踪

在基于PID的局部路径规划中,希望机器人能快速跟踪上预设的轨迹,设误差量为 e k e_k ek e k e_k ek可以根据实际的控制目标进行选择,例如线速度误差、角速度误差、轨迹跟踪误差等

在这里插入图片描述

以轨迹跟踪误差为例,如图所示,根据几何关系可得

e k = sin ⁡ ( θ k , d − θ k ) ⋅ d k e_k=\sin \left( \theta _{k,d}-\theta _k \right) \cdot d_k ek=sin(θk,dθk)dk

其中

θ k , d = a tan ⁡ ( y k , d − y k , x k , d − x k ) d k = ( x k , d − x k ) 2 + ( y k , d − y k ) 2 \theta _{k,d}=\mathrm{a}\tan \left( y_{k,d}-y_k,x_{k,d}-x_k \right) \\ d_k=\sqrt{\left( x_{k,d}-x_k \right) ^2+\left( y_{k,d}-y_k \right) ^2} θk,d=atan(yk,dyk,xk,dxk)dk=(xk,dxk)2+(yk,dyk)2

接着以该误差作为反馈测量值通过PID控制器生成控制量,机器人基于控制量和运动学模型运动,循环往复直到机器人完成控制目标

3 仿真实现

3.1 ROS C++实现

核心的线速度PID控制和角速度PID控制代码如下

double PIDPlanner::LinearPIDController(nav_msgs::Odometry& base_odometry, double b_x_d, double b_y_d)
{
  double v = std::hypot(base_odometry.twist.twist.linear.x, base_odometry.twist.twist.linear.y);
  double v_d = std::hypot(b_x_d, b_y_d) / d_t_;
  if (std::fabs(v_d) > max_v_)
    v_d = std::copysign(max_v_, v_d);

  double e_v = v_d - v;
  i_v_ += e_v * d_t_;
  double d_v = (e_v - e_v_) / d_t_;
  e_v_ = e_v;

  double v_inc = k_v_p_ * e_v + k_v_i_ * i_v_ + k_v_d_ * d_v;

  if (std::fabs(v_inc) > max_v_inc_)
    v_inc = std::copysign(max_v_inc_, v_inc);

  double v_cmd = v + v_inc;
  if (std::fabs(v_cmd) > max_v_)
    v_cmd = std::copysign(max_v_, v_cmd);
  else if (std::fabs(v_cmd) < min_v_)
    v_cmd = std::copysign(min_v_, v_cmd);

  return v_cmd;
}
double PIDPlanner::AngularPIDController(nav_msgs::Odometry& base_odometry, double e_theta)
{
  regularizeAngle(e_theta);

  double w_d = e_theta / d_t_;
  if (std::fabs(w_d) > max_w_)
    w_d = std::copysign(max_w_, w_d);

  double w = base_odometry.twist.twist.angular.z;
  double e_w = w_d - w;
  i_w_ += e_w * d_t_;
  double d_w = (e_w - e_w_) / d_t_;
  e_w_ = e_w;

  double w_inc = k_w_p_ * e_w + k_w_i_ * i_w_ + k_w_d_ * d_w;

  if (std::fabs(w_inc) > max_w_inc_)
    w_inc = std::copysign(max_w_inc_, w_inc);

  double w_cmd = w + w_inc;
  if (std::fabs(w_cmd) > max_w_)
    w_cmd = std::copysign(max_w_, w_cmd);
  else if (std::fabs(w_cmd) < min_w_)
    w_cmd = std::copysign(min_w_, w_cmd);

  return w_cmd;
}

在这里插入图片描述

3.2 Python实现

主体控制流程如下:

def plan(self):
    plan_idx = 0
    for _ in range(self.max_iter):
        # break until goal reached
        if math.hypot(self.robot.px - self.goal[0], self.robot.py - self.goal[1]) < self.p_precision:
            return True, self.robot.history_pose
        
        # find next tracking point
        while plan_idx < len(self.path):
            ...
    
        # calculate velocity command
        if math.hypot(self.robot.px - self.goal[0], self.robot.py - self.goal[1]) < self.p_precision:
            if abs(self.robot.theta - self.goal[2]) < self.o_precision:
                u = np.array([[0], [0]])
            else:
                u = np.array([[0], [self.angularController(self.goal[2])]])
        elif abs(theta_d - self.robot.theta) > np.pi / 2:
            u = np.array([[0], [self.angularController(theta_d)]])
        else:
            v_d = math.hypot(b_x_d, b_y_d) / self.dt / 10
            u = np.array([[self.linearController(v_d)], [self.angularController(theta_d)]])

        # feed into robotic kinematic
        self.robot.kinematic(u, self.dt)
    
    return False, None

在这里插入图片描述

3.3 Matlab实现

核心的线速度PID控制和角速度PID控制代码如下

function [v, e_v_, i_v_] = linearController(robot, b_x_d, b_y_d, dt, e_v_, i_v_)
    v_d = norm([b_x_d, b_y_d]) / dt / 10;
    
    e_v = v_d - robot.v;
    i_v_ = i_v_ + e_v * dt;
    d_v = (e_v - e_v_) / dt;
    e_v_ = e_v;

    k_v_p = 1.00;
    k_v_i = 0.00;
    k_v_d = 0.00;
    v_inc = k_v_p * e_v_ + k_v_i * i_v_ + k_v_d * d_v;

    v = robot.v + v_inc;
end
function [w, e_w_, i_w_] = angularController(robot, theta_d, dt, e_w_, i_w_)
    e_theta = theta_d - robot.theta;
    if (e_theta > pi)
        e_theta = e_theta - 2 * pi;
    elseif (e_theta < -pi)
        e_theta = e_theta + 2 * pi;
    end

    w_d = e_theta / dt / 10;
    e_w = w_d - robot.w;
    i_w_ = i_w_ + e_w * dt;
    d_w = (e_w - e_w_) / dt;
    e_w_ = e_w;

    k_w_p = 1.00;
    k_w_i = 0.00;
    k_w_d = 0.01;
    w_inc = k_w_p * e_w_ + k_w_i * i_w_ + k_w_d * d_w;

    w = robot.w + w_inc;
end

在这里插入图片描述

完整工程代码请联系下方博主名片获取


🔥 更多精彩专栏

  • 《ROS从入门到精通》
  • 《Pytorch深度学习实战》
  • 《机器学习强基计划》
  • 《运动规划实战精讲》

👇源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系👇

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

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

相关文章

Python基础入门例程25-NP25 有序的列表(列表)

最近的博文&#xff1a; Python基础入门例程24-NP24 淘汰排名最后的学生&#xff08;列表&#xff09;-CSDN博客 Python基础入门例程23-NP23 删除好友&#xff08;列表&#xff09;-CSDN博客 Python基础入门例程22-NP22 删除简历&#xff08;列表&#xff09;-CSDN博客 目录 最…

进阶设计一(DDR3)——FPGA学习笔记<?>

一.简介 DDR3 SDRAM&#xff0c;以其单位存储量大、高数据带宽、读写速度快、价格相对便宜等优点 吸引了大批客户&#xff0c;占领市场较大份额。同时&#xff0c;作为内存条中不可缺少的一部分&#xff0c;DDR3 SDRAM 在计算机领域也占有一席之地。 要掌握 DDR3 SDRAM…

公众号流量主项目,只需搬运,一篇文章收益2000+

最近公众号流量主火得不行&#xff0c;大家都想着抓住这个赚钱机会。 连培训团队都看到了商机&#xff0c;开起了学费最低要四位数&#xff0c;甚至高达9880的培训班&#xff01;看来这行确实是个风口项目啊。 以前公众号是个封闭的圈子&#xff0c;你的阅读量和粉丝数量是成正…

Vue指令大全:深入探索Vue提供的强大指令功能

目录 v-bind指令 v-on指令 v-if和v-show指令 v-for指令 自定义指令 其他常用指令 总结 Vue.js是一款流行的JavaScript框架&#xff0c;具备丰富的指令系统。Vue指令允许开发者直接在模板中添加特殊属性&#xff0c;以实现DOM操作、事件绑定、样式控制等功能。在本文中&a…

PHP+MySQL的大学宿舍管理系统【附源码】

视频如下&#xff1a; PHPMySQL宿舍管理系统【】 ** 图&#xff1a; ** 目 录 摘 要 I Abstract II 前 言 IV 1 概述 1 1.1系统开发的目的 1 1.2国内外的研究情况 1 1.3本文主要完成的工作 2 2 开发环境以及开发工具 3 2.1开发环境 3 2.1.1 硬件的开发环境 3 2.1.2 软件的开发…

【Unity ShaderGraph】| 快速制作一个 卡通阴影色块效果

前言 【Unity ShaderGraph】| 快速制作一个 卡通阴影色块效果一、效果展示二、卡通阴影色块效果三、应用实例 前言 本文将使用ShaderGraph制作一个卡通阴影色块的效果&#xff0c;可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章&#xff1a;【Unity …

同屏实时渲染百万级独立的3D可渲染对象

大规模渲染在游戏、家装、或者其他生产制造相关的环境下有直接的刚需&#xff0c;能独立渲染的3D对象越多&#xff0c;越容易实现复杂的场景需求。 下图是200多万(2 * 1024 * 1024)个可渲染的3D对象&#xff0c;的实时渲染情况截图。

API接口在电商数据采集【例如:淘宝平台商品详情SKU订单数据接口的采集 】中的接入说明及参数讲解

No.1 接口请求方式类型 常见的http请求方式包括&#xff1a;get&#xff08;查&#xff09;、post&#xff08;增&#xff09;&#xff0c;除此之外还有put&#xff08;改&#xff09;、delete&#xff08;删&#xff09;等。接口所属类型是由业务决定的。比如你打开淘宝&…

【javaweb】学习日记Day13 - AOP 事务管理 切入点 连接点

目录 一、完善解散部门功能 二、spring 事务 &#xff08;1&#xff09;Transactional 事务管理 ① rollbackFor 控制异常类型 ② propagation 事务传播控制 1、定义解散部门操作日记 三、AOP基础 1、概述 2、快速入门 &#xff08;1&#xff09;案例&#xff1a;统…

c++拷贝构造与赋值运算符重载

目录 目录&#xff1a; 1&#xff1a;拷贝构造 2&#xff1a;赋值运算符重载 前言&#xff1a;在上一章我们已经学习过了&#xff0c;构造与析构这两个默认成员函数了&#xff0c;接下来让我们一起来学习另外两个重要的默认成员函数。 首先让我们来讲一下默认成员函数这个概念…

[架构之路-245/创业之路-76]:目标系统 - 纵向分层 - 企业信息化的呈现形态:常见企业信息化软件系统 - 企业资源管理计划ERP

目录 前言&#xff1a; 一、企业信息化的结果&#xff1a;常见企业信息化软件 1.1 企业资源管理计划 1.1.1 什么是ERP&#xff1a;企业最常用的信息管理系统 1.1.2 ERP的演进过程 1.1.3 EPR模块 1.1.4 EPR五个层级 1.1.5 企业EPR业务总体流程图 1.1.6 什么类型的企业需…

微信小程序云开发如何优雅的实现模糊查询

微信官方自从推出微信小程序云开发之后&#xff0c;让小程序开发的门槛再次降低&#xff0c;你可以不需要掌握任何后端的语言和数据库&#xff0c;有一些js的基本功&#xff0c;就可以完成一个完整带前后端交互功能的小程序项目。今天我们介绍一个日常开发中非常常见的需求&…

转化率(CVR)是什么意思,怎么计算和提高转化率?

转化率指的是在一定时间范围内&#xff0c;企业在线上或线下从事某项营销推广&#xff08;比如竞价广告&#xff09;活动时&#xff0c;成功完成转化行为的次数占推广信息总点击次数的百分比率。它是产品营销推广中的一个重要数据指标&#xff0c;转化率越高&#xff0c;成本越…

【教3妹学编辑-算法题】H 指数 II

3妹&#xff1a;2哥早啊&#xff0c; 新的一周开始了&#xff0c;奥利给&#xff01;&#xff01;&#xff01; 2哥 :3妹&#xff0c;今天起的很早嘛&#xff0c;精神也很饱满。 3妹&#xff1a;昨天睡的早&#xff0c;早睡早起好身体&#xff01; 2哥&#xff1a;既然离时间还…

不定长顺序表2

接下来我们看怎么完成不定长顺序表的代码实现 这里先加一个头文件&#xff0c;名字叫dsqlist.h&#xff0c;存放不定长顺序表的函数定义与声明 然后建立一个名字叫dsqlist.cpp的源文件&#xff0c;跟其头文件配对成一对&#xff0c;(也可以叫别的名字不配对&#xff09;&…

Java 中的 synchronized 同步锁

导致线程安全问题的根本原因在于&#xff0c;存在多个线程同时操作一个共享资源&#xff0c;要想解决这个问题&#xff0c;就需要保证对共享资源访问的独占性&#xff0c;因此人们在Java中提供了synchronized关键字&#xff0c;我们称之为同步锁&#xff0c;它可以保证在同一时…

力扣每日一题83:删除排序数组中的重复元素

题目描述&#xff1a; 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入&#xff1a;head [1,1,2…

Day14力扣打卡

打卡记录 H 指数&#xff08;二分&#xff09; 链接 以最大值 x 为分割点的正整数数轴上&#xff0c;满足&#xff1a; 少于等于 x 的数值必然满足条件&#xff1b;大于 x 的数值必然不满足。 采用右边界二分查找&#xff0c;寻找满足条件的最大 H 指数要求。 class Soluti…

shell脚本函数(极其粗糙版)

分界点&#xff1a;以下内容需要更改&#xff0c;正常放假更改 函数&#xff1a; 1、把整个命令序列按照格式写在一起 2、可以方便的重复使用的命令序列 使用函数可以避免代码重复 函数可以将大的工程分割为诺干小的功能模块&#xff0c;可以随时调用&#xff0c;代码的可读…

Windows一键添加命名前缀(文件)

温馨提示&#xff1a;使用前建议先进行测试和原文件备份&#xff0c;避免引起不必要的损失。 &#xff08;一&#xff09;需求描述 在上班摸鱼的我正准备打开手机刷会儿CSDN论坛&#xff0c;老板发给我一个压缩包并要求我给里面所有的文件的名称添加一个前缀”大项目_”。我本…