【32最小系统板】pid循迹小车(铁丝循迹)
文章目录
- 前言
- 一、任务、要求及评分标准
- 1.1 任务
- 1.2 要求及评分标准
- 1.3 说明
- 二、先上视频效果
- 三、小车循迹方法
- 1.第一次做循迹时
- 2.第二次做循迹时
- 状态机
- 调PID
- 四、铁丝与硬币的判断
- 原理
- 五、如何加快速度
- 硬件
- 软件
- 总结
前言
循迹小车做了两次,准备这次做一个小的总结,这次是对铁丝的循迹,让我对循迹有了新的认识。
一、任务、要求及评分标准
1.1 任务
设计制作一个自动循迹小车。循迹传感器不限,在规定的平面跑道自动
按顺时针方向循迹前进。跑道的标识为一根直径 0.6~0.9mm 的细铁丝,按照图 1 的示意尺寸,用透明胶带将其贴在跑道上。图中所有圆弧的半径均为为20cm±2cm。
1.2 要求及评分标准
(1)在图 1 小车所在的直线区任意指定一起点(终点),小车依据跑道上设置的
铁丝标识,自动绕跑道跑完一圈。时间不得超过 10 分钟。小车运行时必须
保持轨迹铁丝位于小车垂直投影之下。如有越出,每次扣 2 分。 (30 分)
(2)实时显示小车行驶的距离和运行时间。(15 分)
(3)在任意直线段铁丝上放置 4 个直径约 19mm 的镀镍钢芯硬币(1 角硬币),
硬币边缘紧贴铁丝,如图 1 所示。小车路过硬币时能够发现并发出声音提
D-2
示。(15 分)
(4)尽量减少小车绕跑道跑完一圈运行时间。 (20 分)
(5)设计报告(20 分
1.3 说明
(1)自动循迹小车允许用玩具车改装。小车用自带电池供电运行,不能使用外
接电源。小车的尺寸为其在地面的投影不超过 A4 纸大小。小车自动运行后,
不得有任何人工干预小车运动的行为,如遥控等。
(2)跑道除指定的铁丝外,不得另外增加任何标记。跑道附近不应有其他额外
金属物体。
二、先上视频效果
投稿在b站的小车循迹
大体是20s完成
三、小车循迹方法
1.第一次做循迹时
之前寻黑工胶带的代码,黑工胶带大概是1cm宽,0 是检测到黑线,1 是没检测到,信号线接在P2口,当时用的是51单片机入门做的。
主要方法是遇到大转弯delay多一点,小转弯dalay小一点,delay的作用主要是为了让转弯的时间多一点,多调整几次速度,就能获得较好的巡线效果。
四路循迹 参考代码如下(示例):
void xunji()
{ switch(P2&0x0f){case 0x0f: // 1111全部没有压线,前进run();break;case 0x0e: // 1110右压线,左转leftrun();delay(10);break;case 0x0c: // 1100右压线,左转leftrun();delay(5);break;case 0x07: // 0111左压线,右转rightrun();delay(5); //转向延时break;case 0x03: // 0011左压线,右转rightrun(); delay(10); //转向延时break;case 0x00:stop();break;default:break;}}
2.第二次做循迹时
后来发现这样做,在寻细线(铁丝),或者如果要竞速(速度较快时),会出现两个问题:
1、那些比较直的转弯基本很难转过去,如果能转过去也需要调很久,换一个速度就需要重新调速,不适用于所有速度。
2、当走直线时,即使我们调的pwm值是一样的,却走不出来直线,会影响速度。
针对第一个问题:我们用状态机来解决。
针对第二个问题:我们用pid来解决。
状态机
问题引出
现在我们要解决的问题是,我们小车没办法在冲出转弯的时候意识到自己已经冲出转弯,而是转到一半,以为自己已经转到位了,便继续直行,这就是第一个出现的问题。
基本使用方法
于是我们现在需要让小车知道自己运行在什么状态,比方说我们小车一开始是直行,然后检测到左边有铁丝了,需要右转来控制使小车身压在铁丝正下方,此时,我们切换直行状态到右转状态,而转到什么来告诉小车现在是压在正下方呢,当我们发现小车在正下方时(我用的是四路传感器,即所有检测传感器都检测不到时),我们再次切换状态,从右转状态切回直行状态。
以上就是状态机的基本使用方法,我感觉像是给机器增加了一个上一步的记忆。
举个例子 按键的状态机
0是按下,1是未按下(相当于抬起来),就可以不需要delay函数消抖,提高了程序效率。
if (key == 0)a = 1;if (key == 1)if (a ==1 ){ 你的实现效果;a = 0;}
我们小车现在有5种状态:直行,左转弯,急左转弯,右转弯,急右转弯,我们首先在头文件枚举。
enum State
{RapidLeft = -2,TurnLeft = -1,TurnRight = 1,RapidRight = 2,Straight = 0
} typedef State;
然后在.c原文件初始化最开始的状态
State st = Straight;
参考循迹程序如下
void xunji(void)
{switch (st){case Straight:{Target_LV = 300;Target_RV = 300;}break;case TurnLeft:{Target_RV = 300;Target_LV = 100;}break;case TurnRight:{Target_RV = 100;Target_LV = 300;}break;case RapidLeft:{Target_RV = 300;Target_LV = 0;}break;case RapidRight:{Target_RV = 0;Target_LV = 300;}break;}if (Left1 == 1 && Left2 == 0 && Right2 == 1 && Right1 == 1){st = TurnLeft;}else if (Left1 == 1 && Left2 == 1 && Right2 == 0 && Right1 == 1){st = TurnRight;}else if (Left1 == 0 && Left2 == 1 && Right2 == 1 && Right1 == 1){st = RapidLeft;}else if (Left1 == 1 && Left2 == 1 && Right2 == 1 && Right1 == 0){st = RapidRight;}else if (Left1 == 1 && Left2 == 1 && Right2 == 1 && Right1 == 1){if(st == TurnLeft || st == TurnRight) st = Straight;}
}
具体思路就是循环检测传感器,每次方向有变化zhuangtai就改变状态值,如果方向有到想要的变化时,才改变状态,否则就一直维持上一个状态,直到状态改变。这样就基本理论上可以实现完美循迹(只要传感器足够灵敏)。
调PID
调节pid的步骤:
1、调节pwm
2、限幅pwm
3、输出pwm
Leftpwm = Incremental_PI(LeftEncoder, Target_L);//PID得到pwmRightpwm = Incremental_PI(RightEncoder, Target_R); Limit_Pwm();//限幅函数 使pwm限幅 为0~100 //但有正反 所以 -100~100 SetCompare_Pwm(Leftpwm,Rightpwm);//pwm输出函数
1、调节pid,一般pid分为增量式pid和位置式pid,增量式pid一般是PI控制,然后位置式pid一般是PD控制,增量式pid的误差只会与前三次误差有关,所以一般来讲,一次错误的累积不会影响总体的误差判断,所以我选了增量式pid。
/**************************************************************************
函数功能:增量PI控制器
入口参数:编码器测量值,目标速度
返回 值:电机PWM
根据增量式离散PID公式
pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
e(k)代表本次偏差
e(k-1)代表上一次的偏差 以此类推
pwm代表增量输出
在我们的速度控制闭环系统里面,只使用PI控制
pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_PI (int Encoder,int Target)
{ static float error,Pwm,Last_error,Last_Last_error;error=Target-Encoder; //计算偏差Pwm+=Kp*(error-Last_error)+Ki*error + Kd*(error - 2*Last_error + Last_Last_error); //增量式PI控制器Last_error=error; //保存上一次偏差Last_Last_error = Last_error; //保存上上次误差//OLED_ShowSignedNum(1,8,error,5);return Pwm; //增量输出
}
注:输出的pwm就是编码器下降沿(跳变)的个数,理论上最后的Pwm与Target几乎一致,最后把调制出的pwm输出就是速度。
2、限幅pid,我pwm设的幅度为0-100,在实际测的时候发现在pwm在60以后左右电机偏差就会很大,于是限幅在了0-60。
3、输出pwm
我的编码器个数数的是AB相各一个脉冲,所以编码器的数字会出现负数,具体请看编码器测速。所以输出的会有正负。
//函数功能:输出给PWM寄存器
void SetCompare_Pwm(int Leftpwm,int Rightpwm)//将Leftpwm,Rightpwm输出出去,使舵机和小车电机受到相应控制
{if (Leftpwm >= 0) //正数 代表正转{GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);PWM_SetCompareLeft(Leftpwm);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_3);GPIO_SetBits(GPIOA, GPIO_Pin_2);PWM_SetCompareLeft(-Leftpwm); //因为SetCompare要传的是正数 所以 speed加负号}if (Rightpwm >= 0) //正数 代表正转{GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);PWM_SetCompareRight(Rightpwm);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);PWM_SetCompareRight(-Rightpwm); //因为SetCompare要传的是正数 所以 speed加负号} //PWM_SetCompareLeft( Leftpwm);//PWM_SetCompareRight( Rightpwm);}
调pid参数
一开始我定时器是500ms定时,调的时候至少20s才能调到想要的速度。
后来试着把定时器调到5ms定时,调好的时候几乎1s不到就能到想要的速度了。
注意:调节时,把速度指定为最大的速度的一半,这样调出的pid值对速度大速度小都有一个较好的调节。我最大的速度为700mm/s,由于偏向竞速,我选择速度为400ms为调节的速度。
1、PID,先调的P,此时其他置0,P是比例系数,影响最大,调节到有一个稳态误差时(一直与想要的速度有一个稳定的差值),P就差不多好了。
2、然后调I,我I的值是从P的值的1/00开始加的,直到达到想要的速度。
3、增量式一般D的影响不是很大,就置的0。
最后自己调的值为(5ms定时时)为
float Kp = 3.2,Ki = 0.1,Kd = 0.0000;
定时不同PID也要调节500ms定时时,调出来的pid值也是不同的,为
//0.68 0.01 //0.0025 0.0001
四、铁丝与硬币的判断
原理
硬币是1角钱硬币,铁丝是0.6mm粗的铁丝,虽然都含铁,但硬币的面积大,在切割磁感线的时候,变化更加明显,原理就是这样。如果用AD模拟量输出的话,会发现经过硬币时确实会有一个较大的变化。
注:由于AD涡流传感器需要一个5v(或者3.3v)的稳定电压来供电,所以千万不能用给电机供电的稳压板上的5v给它供电,因为小车运转的同时,电压会变化,所以需要一个单独的电源模块给它供电。
为保证数字是稳定变化的,所以取了一个20次的平均值,且为了防止电压不稳会导致模拟量阈值不定,用了绝对值变化消除影响。
参考:
float ad ,last_ad;last_ad = Get_adc_Average(ADC_Channel_0, 20);while(1){ad =Get_adc_Average(ADC_Channel_0, 20); OLED_ShowNum(3, 13, My_abs(ad-last_ad), 4); if (My_abs(ad-last_ad) >80){Buzzer_ON();delay_ms(300);Buzzer_OFF(); }last_ad = ad;}
还有一个注意事项:
1、我小车用的是铝合金的板子,所以在用模拟量时,要是底盘太低,靠近了涡流传感器上的线圈,也会产生较大的干扰,所以我把小车底盘架高(反过来装了)。
2、电池也不能靠近线圈,否则模拟量输出为0。
3、不能同时装有两个线圈,会分别干扰失去作用。
但是如果小车速度太快的话,也会导致蜂鸣器乱叫(就是模拟量乱跳),我怀疑是铝合金钢板太大了不可忽视,最好还是换成亚克力板
五、如何加快速度
硬件
1、编码器用的是光电编码器比较精确的测量的个数,或许对调节速度可能更精准(调pid参数比较好调)。
2、两片c8t6最小系统板,一块用来循迹,一块用来干其他事,这样循迹的主程序就受干扰。
3、差速的两轮小车比舵机的转向更加灵活,且没有最小转弯半径,支持原地自转。
4、牛眼轮比万向轮的摩擦更小。
软件
有一个不知道算方法的方法:
当你左右两个速度一样时,重心是在小车两轮中间,当左边速度是100,右边速度是300时,重心是在两轮右边偏1/4处,可以根据这个来调速度。
例
void xunji(void)
{switch (st){case Straight:{Target_LV = 300;Target_RV = 300;}break;case TurnLeft:{Target_RV = 300;Target_LV = 100;}break;case TurnRight:{Target_RV = 100;Target_LV = 300;}break;case RapidLeft:{Target_RV = 300;Target_LV = 0;}break;case RapidRight:{Target_RV = 0;Target_LV = 300;}break;}
还有一个方法可以让主程序的速度变快
int n = 0;
int main(void)
{while(1)
{n = (n + 1) % 50;if (n == 0){}else if (n == 1){}else if (n == 2){}else if (n == 3){}
}
}
理论上速度提高到了本来的50倍,本来是每次while都会执行里面四个函数,现在是很快的刷新while,第一次只执行n == 0里的内容,第二次只执行n == 1里的内容,50次循坏只执行4下,而原来每次循环执行4下,所以运行速度提高了本来的50倍。
总结
小车代码详见
链接:https://pan.baidu.com/s/1YpokxuVx42A8Ovzcs4vM8Q?pwd=ey8z
提取码:ey8z
【32最小系统板】pid循迹小车(铁丝循迹)相关推荐
- (STM32CubeMx生成HAL库)STM32F103C8T6最小系统板,4个按键分别控制42混合步进电机启停、变向、加减速
用的定时器1通道1生成pwm脉冲,改变ARR值改变脉冲频率从而实现调速,采用按键中断控制 直接上图 引脚定义: PA5 EN 使能 PA7 DIR/CW 方向 PA8 PUL/CLK ...
- stm32f103c8t6最小系统电路原理图_嵌入式单片机之STM32F103C8T6最小系统板电路设计参考...
.STM32F103C8T6最小系统板电路设计 一.电源部分 设计了一个XH插座,以便使用3.7V锂电池供电,接入电压不允许超过6V. 二.指示灯部分 电源指示灯可以通过一个短路帽控制亮灭,以达到节电 ...
- ATmega8,ATmega16,最小系统板,第一个好评来啦!
终于收到第一个好评啦!小小庆祝一下,第一笔小小的收获,也是平哥和我的这两个周的心血啊,有木有 ? 血拼的双十一,我们没有活动,但是我们有行动!在大家不经意间,一弹弹的新宝贝已经发出啦 ! 第一弹> ...
- stm32核心板可以点亮灯吗_利用STM32F103C8T6最小系统板点亮流水灯
后台网友建议制作一个流水灯,正好发现自己有之前购买的STM32F103C8T6核心板,今天搭建一个流水灯,正好学习一下STM32 GPIO输出如何实现,将来驱动蜂鸣器.继电器等都会使用的. 流水灯相当 ...
- NXP LPC1768最小系统板硬件介绍
NXP LPC1768最小系统板硬件介绍 关键字:NXP LPC1768 LPC1700 ARM Cortex-M3 RISC 最小系统 mini板 硬件 电路 原理图 概述:它采用超大规模技术将具有 ...
- STM32F103最小系统板引脚定义
STM32F103最小系统原理图 本人初学stm32,若有误解之处,还望大佬们指正改进,感谢! STM32F103各引脚定义 可前往<STM32F103xCDE_数据手册-英文>的第三章 ...
- 最小系统板 STM32入门,点亮 LED 灯(STM32F103C6T6)
Hello, I'm Shendi 最近开整单片机,这里记录一下 我目前配置,最小系统板 STM32F103C6T6,ST-LINK V2 最小系统板,通电后PWR灯会亮,ST-LINK插上电脑后也会 ...
- STC89C52RC最小系统板
STC89C52RC最小系统板硬件设计(原理图+PCB) Author:Once Day "漫漫长路,有人对你微笑过嘛-" Solemnly declare:知识产权.正确性等皆未 ...
- 基于STM32F103C8T6的超声波模拟雷达设计。【C8T6最小系统板+标准固件库+1.8‘TFT-LCD屏】
前言: 之前为做毕设一直在网上浏览关于STM32单片机的DIY项目,大多数设计都是关于智能家居方面的应用,通过浏览不同平台的内容发现了一个采用超声波测距并通过屏幕反馈障碍物位置的模拟雷达设计,感觉很有 ...
最新文章
- 【Thread】- ReentrantLock、ReentrantReadWriteLock
- java clone 深复制_Java的clone():深复制与浅复制
- PEInfo编程思路讲解03 - 工具篇03|解密系列
- history linux 日志服务器_Linux下使用rsyslog部署日志服务器 记录history并发送到rsyslog服务器...
- 【MySQL】 已经存在大量数据的表做分区
- 上海内推 | 极氪智能科技百万年薪「氪学家」项目招聘规控/感知算法工程师
- html5 td中的5它空隙--待解决
- 用Heartbeat实现web服务器高可用
- 利用 Docker 搭建单机的 Cloudera CDH 以及使用实践
- hostapd 进程启动不了_项目管理|项目启动会实操要点,项目经理掌权的关键
- centos7 如何重启web服务_CentOS7重启网络服务失败。
- 使用Windows 7 管理Windows 2008 R2
- Ubuntu下替换软件列表
- Luogu5339 [TJOI2019]唱、跳、rap和篮球 【生成函数,NTT】
- 科学计算机调成了fx,科学计算器怎么编程
- 如果局域网当中两台电脑互相ping不通
- Learning to Rank(转)
- 主流视频会议租用产品对比
- 中国科学技术大学计算机考研难吗,中国科学技术大学(专业学位)计算机技术考研难吗...
- CSP-J 初赛一轮复习之软件系统与网络基础