当前位置: 代码网 > 科技>操作系统>Windows > 小车快速循迹 串级PID算法 稳得很 纯纯干货

小车快速循迹 串级PID算法 稳得很 纯纯干货

2024年08月01日 Windows 我要评论
网上的文章翻了一遍,都没有讲智能小车如何做到快速循迹,而且又稳的,是不是。有讲PID算法循迹的,要么运用到自己小车身上就不行,要么就是文章中没有效果展示,代码收费,导致不敢买。你的循迹小车是不是做不到速度快了小车还能稳稳循迹的效果,网上人家智能车竞速的视频深深吸引着你,你在思考这小车怎么做到速度这么快,而且又稳的,此篇就帮你解决这个问题。话不多说,先看视频效果。怎么样?稳吧,(如果还没你的好此时你应该退出这篇文章),下面正文开始。

   网上的文章翻了一遍,都没有讲智能小车如何做到快速循迹,而且又稳的,是不是代码高保密,只传亲学弟

  有讲pid算法循迹的,要么运用到自己小车身上就不行,要么就是文章中没有效果展示,代码收费,导致不敢买。你的循迹小车是不是做不到速度快了小车还能稳稳循迹的效果,出线、左右摆的问题一直困扰你?网上人家智能车竞速的视频深深吸引着你,你在思考这小车怎么做到速度这么快,而且又稳的,此篇就帮你解决这个问题。话不多说,先看视频效果。

http://【32小车快速循迹 串级pid 稳得很】 https://www.bilibili.com/video/bv1xj3jewe6s/?share_source=copy_web&vd_source=95344b969e8c93113a217b133e31aef9

怎么样?稳吧,(如果还没你的好此时你应该退出这篇文章),下面正文开始。

一、基础篇

  如果你知道小车是如何循迹的可直接跳过。小车一般采用灰度、或者红外模块来判断小车在循迹线的位置,

  我用到的是第二种,可以看到总共8个灯(8路),从左到右我们依次记为灯1 - 灯8,小车在线的中间位置时灯4和灯5就会亮起,所对应的信号输出口就会返回0,如果小车往右偏一点,那么灯3和灯4所对应的信号输出口就为0,小车就可以据此来做出判断。快速循迹一般采用12路循迹模块,最少8路,我使用的是12路,因为路数越多,小车的微动变化主控也能判断。

二、进阶篇

  此篇主讲主控得到信号后怎样处理。你不会还在用if  elseif 吧,太low了!以stm32标准库为例,有基础的想必都知道如果要读取c1口的高低电平的函数是

gpio_readinputdatabit(gpioc,gpio_pin_1);

一般做法是将它读取出来赋值给一个变量,像这样

int h1 = gpio_readinputdatabit(gpioc, gpio_pin_1);

依次读取8个引脚,分别赋值给h1-h8,然后再对变量h1-h8进行if elseif 判断。每次写 if elseif 写一大堆,还不好看,今天我用另外一种处理方法来代替它,代码简洁明了。

我们知道假如第一个灯亮起,那么8个灯所返回的值依次是01111111,可以看做它一个二进制数,所对相应的就是127,此时我们用 switch语句来判断不就好了,关键在于怎样将8个数合并成一个数呢,直接上代码

int read(void)
{
 int val;
  val |= (gpio_readinputdatabit(gpioc, out1) << 7);
  val |= (gpio_readinputdatabit(gpioc, out2) << 6);
  val |= (gpio_readinputdatabit(gpioc, out3) << 5);
  val |= (gpio_readinputdatabit(gpioc, out4) << 4);
  val |= (gpio_readinputdatabit(gpioc, out5) << 3);
  val |= (gpio_readinputdatabit(gpioc, out6) << 2);
  val |= (gpio_readinputdatabit(gpioc, out7) << 1);
  val |= (gpio_readinputdatabit(gpioc, out8) << 0);
  return val;
}

这样不就全部保存在val这个变量里了嘛,下面就是用switch语句来对这个变量判断,上代码

    read();
	switch (read())
	{
		case 127:     break; //0111 1111
		case 191:     break; //1011 1111
		case 223:     break; //1101 1111
		case 239:     break; //1110 1111
		case 247:     break; //1111 0111
		case 251:     break; //1111 1011
		case 253:     break; //1111 1101
		case 254:     break; //1111 1110

		case 0:       break; //0000 0000
		case 255:     break; //1111 1111
		default:      break;
   }

  两个灯亮和三个灯亮的情况一样,这里就不给你了,自己动动小手算算一算吧。这不就完美解决了if elseif 写一堆的问题了嘛。

三、单级pid

 加12758 来了来了,它终于来了! 不过此篇还是单级pid,耐心看完,你会有收获的,还不知道什么叫做pid的小伙伴请去翻阅资料,我在此不做解释了,懂pid的小伙伴此时是不是不知道pid怎样运用在循迹小车上呢,我来给你解惑。pid最重要的是得有误差反馈,误差从何而来,就是你给它,什么意思呢,直接看代码

 float error;
 read();
	switch (read())
	{
		case 127:  error = -3;     break; //0111 1111
		case 191:  error = -1;     break; //1011 1111
		case 223:  error = -0.5;   break; //1101 1111
		case 239:  error = 0;      break; //1110 1111
		case 247:  error = 0;      break; //1111 0111
		case 251:  error = 0.5;    break; //1111 1011
		case 253:  error = 1;      break; //1111 1101
		case 254:  error = 3;      break; //1111 1110

		case 0:    error = 0;      break; //0000 0000
		case 255:  error = 0;      break; //1111 1111
		default:   error = 0;      break;
   }

这样误差不就有了嘛,小车往右偏,反馈误差为负,偏的越很,误差越大,小车在中间误差为0,

误差有了,那么下面就是对误差的pid算法处理,我们知道pid算法常见的有位置pid和增量式pid,很明显咱们要用位置pid,此处我只用p和d,上代码

    p = error;                      //p项
	d = error - previous_error;     //d项(当前误差减上次误差)
	pid_value = (kp * p)+ (kd * d); //核心公式
	previous_error = error;         //将当前误差保存
    
    x = pwm +pid_value;              //最终计算出左右轮要输出的pwm     
	y = pwm -pid_value;   
		
    if(x>=100) { x=100;}else if(x<-100){x=-100;}  //限幅
    if(y>=100) { y=100;}else if(y<-100){y=-100;}
	
    motor(x,y);    //电机执行

previous_error,pid_value,x,y,pwm均已定义,motor函数为电机执行函数,如果motor函数传入的是两个负数,电机后转,一边正一边负就会左转或右转。限幅100是因为我给你pwm满量程为100;pwm这个变量是你想让小车达到速度,想让小车以50的速度循迹就给50,想让小车以100的速度循迹就给100。在调参时先调kp,再调kd,具体调参过程不再细讲,请搜索相关文章,以我的经验来说kd要比kp大的多。

至此,单级pid循迹已经完成,但是!效果并不是太好,面对低速还可以,但是面对高速状态下仍然是左右震荡、出线!下面的串级pid完美解决了该问题。

四、串级pid

 52972所谓串级pid,用大白话来说就是两个pid串一块。具体原理请搜索相关文章,在此只说另外一个pid是什么,另外一个pid是加上了陀螺仪,我用的是最便宜的mpu6050陀螺仪,十几块钱,对它哪个值进行pid运算呢?z轴角速度值!关于陀螺仪角速度、姿态角之类的不懂的请搜索相关文章,怎样串,先谁后谁,具体代码是什么,请有偿联系,创作不易,谢谢。(代码基于stm32f103zet6,标准库)

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com