四轮两驱小车(四):STM32驱动5路灰度传感器PID循迹

news/2025/3/31 22:01:11/

目录

前言:

小车效果展示:

5路数字灰度传感器:

巡线思路:

加入PID调节的代码:


前言:

        之前买了一批5路灰度传感器,想用这传感器进行循迹,无奈网上和官方的资料提供的还是比较少,这里还是做一下当初的学习记录。

小车效果展示:

STM32RCT6主控,5路灰度寻迹,超声波HC_SR04中断式测距,蓝牙模块HC_08通信,AS4950电机驱动芯片,减缓了MPU6050零漂问题,PID丝滑_哔哩哔哩_bilibili

5路数字灰度传感器:

         这是某宝上买的5路灰度传感器,价格稍微有点贵,50多块一个。当然,一分钱一分货,这个模块可以用小螺丝刀来调节传感器上面的旋钮,通过这个旋钮来调节灵敏度,这个灵敏度调节好了的话可以识别黑白循迹、红白循迹。所以还是比较值得的。

        对于这款5路数字灰度传感器来说。识别到黑线,传回来的数字量就是0,识别到白色,传回来的数字量就是1。

巡线思路:

        博主想着用这5路的中间三路来巡线,用最左和最右端的传感器用来识别十字或者丁字路口,巡线时,加入PID算法,遇到十字或者丁字路口就用最左和最右的传感器来识别,识别到了之后,我们就可以搭配MPU6050进行转90°弯了。

加入PID调节的代码:

        其中 sensor_bias 是根据中间三路传感器和黑线的相对位置来估计出的误差(如果你要问我怎么得来的,其实这个数据大差不差就行,它只是为PID服务的一个变量罢了,甚至你可以把62.5改成50,最后只要调好PID三个参数,达到的效果是一样的),这里的decide类似于状态机的信号,我令decide为6的时候,也就是小车跑出了黑线,小车停止。

#include "sensor.h"
#include "stm32f10x.h"
#include "move.h"
#include "motor.h"
#include "FSM.h"//STEER4 		--> PA11  --> R2  红线
//STEER3 		--> PC9 	--> R1  橘线
//			 		--> PB4   --> M0  黄线
//STEER1 		--> PA6   --> L1  绿线
//ENCODE1_A --> PB5	  --> L2  棕线float Kp_sensor = 8.134, Ki_sensor = 0.021, Kd_sensor = 2.36;//pid弯道参数参数 
float sensor_bias = 0;
float sensor_bias_last = 0;
float P = 0, I = 0, D = 0, PID_value = 0;  //pid直道参数 
int decide;unsigned char move_flag;
extern unsigned char FSM_state;
void sensor_Init()
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//开启C时钟   PC9GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//这句话其实可以不用,在使用输入功能时,不需要配置频率GPIO_Init(GPIOC, &GPIO_InitStructure);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启A时钟  PA11  PA6GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_6;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启B时钟  PB4  PB5GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;GPIO_Init(GPIOB, &GPIO_InitStructure);
}unsigned char times;
extern unsigned char FSM_hc08;
unsigned char back_flag;
unsigned char one_time;
unsigned char one_flag;
unsigned char channel_num;//channel的存在导致发送2号通道的时候只会进入一次
void sensor_read()
{if((L2 == 1)&&(L1 == 1)&&(M0 == 1)&&(R1 == 0))// 1 1 1 0 {if(one_time == 0){if(FSM_hc08 == Channel_1){FSM_state = Turn_lift_state;//跳出循环,将PID分别清零。one_time++;P = 0;I = 0; D = 0;}else if(FSM_hc08 == Channel_2){if(one_flag == 0){channel_num++;one_flag = 1;}if(channel_num == 2){	FSM_state = stay2_state;//跳出循环,将PID分别清零。one_time++;P = 0;I = 0; D = 0;}}}}else if((L1 == 0)&&(M0 == 1)&&(R1 == 0))// 0 1 0 {sensor_bias = 0;decide = 3;one_flag = 0;//积分项清零}else if((L1 == 1)&&(M0 == 1)&&(R1 == 0))// 1 1 0 {sensor_bias = -62.5;decide = 2;}else if((L1 == 0)&&(M0 == 1)&&(R1 == 1))// 0 1 1 {sensor_bias = 62.5;decide = 2;}else if((L1 == 1)&&(M0 == 0)&&(R1 == 0))// 1 0 0 {sensor_bias = -125;decide = 4;}else if((L1 == 0)&&(M0 == 0)&&(R1 == 1))// 0 0 1 {sensor_bias = 62.5;decide = 4;}else if((L1 == 0)&&(M0 == 0)&&(R1 == 0))// 0 0 0 {decide = 6;}else if((L1 == 1)&&(M0 == 1)&&(R1 == 1))// 1 1 1 {decide = 6;FSM_state = Judge_state;		//如果读取到了整条黑线,那么就进入下一状态if(back_flag == 1){FSM_state = Back_state;back_flag = 0;}			//第一次识别到全黑线为小车停止线。第二次识别到,代表小车即将回归循迹}}
void Sensor_pid()
{if(decide<=5){P = sensor_bias;I = I + sensor_bias;D = sensor_bias-sensor_bias_last;PID_value = Kp_sensor*P + Ki_sensor*I + Kd_sensor*D;sensor_bias_last = sensor_bias;//对积分值设置一个限制,防止积分值超标if(I >=3500)I = 3500;if(I <= -3500)I = -3500;PWM_value_R = 2099 - (int)PID_value;PWM_value_L = 2099 + (int)PID_value;//当线在左,左轮要慢,右轮要快,左轮要加,右轮要减,但这里的偏差是负值Motor3_forward(PWM_value_R);Motor4_forward(PWM_value_L);//4 --> 右电机//3 --> 左电机	}else{Move_stop();}
}

        对应的头文件部分

#ifndef __SENSOR_H
#define __SENSOR_H//STEER4 --> PA11 --> R2  绿线
//STEER3 --> PC9 	--> R1  黄线
//		B  --> PB6  --> M0  橘线
//STEER1 --> PA6  --> L1  红线
// 		A  --> PB7	--> L2  白线
// 灰度传感器,当传感器识别到黑线的时候,输出为1,其余时刻输出为0
// 所以在这里我们要使用下拉输入
#define L2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)
#define L1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)
#define M0 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)
#define R1 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_9)
#define R2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_11)void sensor_Init(void);
void sensor_read(void);
void Sensor_pid(void);#endif


http://www.ppmy.cn/news/19828.html

相关文章

Opencv项目实战:20 单手识别数字0到5

目录 0、项目介绍 1、效果展示 2、项目搭建 3、项目代码展示 HandTrackingModule.py Figures_counter.py 4、项目资源 5、项目总结 0、项目介绍 今天要做的是单手识别数字0到5&#xff0c;通过在窗口展示&#xff0c;实时的展示相应的图片以及文字。 在网上找了很久的…

C语言进阶——文件管理

每当我们写好一段代码运行结束之后&#xff0c;再次运行的时候就会发现&#xff0c;之前在终端上输入的数据都会消失&#xff0c;那么如何把之前输入的数据保存下来呢&#xff1f; 我们一般把数据持久化的方式有把数据存放在磁盘文件中、存放到数据库。打印等方式进行保存。 …

【二叉树】java实现代码,详解二叉树,带大家更深刻的掌握二叉树递归思想

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#x1fa90;&#x1fa90;&#x1fa90;&#xff0c;在探索数据结构的旅程中&#xff0c;二叉树可以说是数据结构中的重点&#xff0c;笔试面试经常出现的问题&#xff0c;同时也是难点。&#x1f425;&#x1f425;&#x1f4…

【数据结构之二叉树系列】万字深剖普通二叉树的遍历+分治算法思想

目录前言一、背景知识二、前序遍历三、中序遍历四、后序遍历五、求二叉树中结点的个数1. 遍历计数&#xff08;1&#xff09;前序遍历计数&#xff08;2&#xff09;中序遍历计数&#xff08;3&#xff09;后序遍历计数2.分治算法思想&#xff08;推荐&#xff09;敬请期待前言…

芒果改进YOLOv7系列:超越ConvNeXt结构,原创结合Conv2Former改进结构,Transformer 风格的卷积网络视觉基线模型,高效涨点

💡该教程为改进进阶指南,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀💡本篇文章 基于 YOLOv5、YOLOv7芒果改进YOLO系列:芒果改进YOLOv7系列:超越ConvNeXt结构,原创结合Conv2Former改进结构,Transformer 风格的卷积网络视觉基线模型,高效涨点、…

idekctf2022部分web

前言 我爱idekctf&#xff01;&#xff01;&#xff01;&#xff01;有dockerfile真是太棒了 因为实在不会前端&#xff0c;所以暂时只复现非xss的题目 题目附件我都放在了这儿 Web/Readme 0x00 一个代码审计题&#xff0c;用的go语言&#xff0c;平常接触的不多&#xf…

机器学习知识总结 —— 19.朴素贝叶斯网络

文章目录贝叶斯概率简述朴素贝叶斯训练过程预测过程简单的说贝叶斯概率简述 在我写过的关于统计学相关文章 《概率论基础 —— 2. 条件概率、全概率、贝叶斯概率公式》 提到过一个很重要的概率公式—— 贝叶斯公式。其基本形式如下&#xff1a; P(xi∣Y)P(xi)P(Y∣xi)P(Y)P(x_…

ISIS的3级别(level-1、level-2、level-1-2)4大类(IIH、LSP、CSNP、PSNP)9小类与邻接关系建立LSP交互过程介绍

2.2.0 ISIS 4种报文类型IIH、LSP、CSNP、PSNP、邻居建立过程、交互LSP过程 ISIS的3级别4大类9小类 ISIS拥有3种级别的路由器&#xff0c;分别是level-1、level-2、level-1-2。 不同级别之间进行交互的报文也是有所区别的&#xff0c;常规的ISIS报文分有4大类&#xff1a;IIH、…