基于stm32f103c8t6HAL库六路电磁寻迹智能车

#基于stm32f103c8t6HAL库六路电磁寻迹智能车
学习单片机第一次参加相关比赛,下面分享一些关于调车的心得。
1.控制舵机
舵机是控制小车转向的器件,而PWM波可以控制舵机,占空比越大,舵机旋转角度越大。接下来我们打开cubemx配置定时器输出pwm波(时钟树和其他部分请参照我的上一篇文章)。
在这里插入图片描述

这里用定时器2,在通道一处选择pwm输出,这里就有一个频率的问题。因为我们配置的晶振是72Mhz,所以将psc设为720,arr设为2000,可以算出频率50hz(72000000/720/2000),另外还要在生成的工程中添加如下代码

HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);

如果要修改占空比,则添加下面的函数

__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,70);

要注意的是,我们用到的舵机只能向一个方向转,所以要实现舵机左右转,就要在一开始把它调在中间位置,也就是0度位置,像下面的图,
在这里插入图片描述
(ps忽略这感人画质,也是我截的),控制舵机的信号频率为50hz,__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,70);
这句代码后面的参数根据高电平时间除以20毫秒算出比例,再乘以arr设置的值(这里可能会因为硬件的缘故,舵机打满角和算出来的值不匹配,需要软件尝试,但是差不了多少)。
2.控制电机
电机就是控制车轮的器件,同样,电机的驱动也需要PWM波,这里还用到一个模块叫L298n电机驱动模块
在这里插入图片描述
这里引用另外一位博主对模块的介绍
1.模块可驱动两路直流电机,输出A接及B各接一直流电机即可
2.若使用12V供电,将12V供电端口及GND接上电源正负即可。
3.若不需要使用PWM调速,只需要控制电机正反转,则逻辑A与B跳线帽插上即可,相当于始终使能。
4.若需要使用PWM调速,需将跳线帽拔起,将使能端接上单片机IO口。
5.逻辑输入四个端口IN1、IN2、IN3、IN4接单片机四个IO口,每两个端口控制的一路电机。

————————————————
版权声明:本文为CSDN博主「weixin_44390843」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44390843/article/details/102802521
那如何控制轮子正反转呢?
在这里插入图片描述
由上图不难得知,只要对应引脚输出高低电平即可。
控制了电机和舵机,差不多就可以让小车动起来,下面贴一些简单的控制小车前进后退的测试代码

#include <carrun.h>
//#include "tim.h"

void leftF(void)
{
		HAL_GPIO_WritePin(GPIOB, left1_Pin,GPIO_PIN_SET);   //前
		HAL_GPIO_WritePin(GPIOB, left2_Pin,GPIO_PIN_RESET);
}
void rightF(void)
{
	 HAL_GPIO_WritePin(GPIOB, right1_Pin,GPIO_PIN_RESET);   //前
	HAL_GPIO_WritePin(GPIOB, right2_Pin,GPIO_PIN_SET);
}

void leftB(void)
{
		HAL_GPIO_WritePin(GPIOB, left1_Pin,GPIO_PIN_RESET);   //后
		HAL_GPIO_WritePin(GPIOB, left2_Pin,GPIO_PIN_SET);
}
void rightB(void)
{
	 HAL_GPIO_WritePin(GPIOB, right1_Pin,GPIO_PIN_SET);   //后
	HAL_GPIO_WritePin(GPIOB, right2_Pin,GPIO_PIN_RESET);
}

void leftSTOP(void)
{
	 HAL_GPIO_WritePin(GPIOB, left1_Pin,GPIO_PIN_RESET);   //停
	HAL_GPIO_WritePin(GPIOB, left2_Pin,GPIO_PIN_RESET);
}

void rightSTOP(void)
{
	 HAL_GPIO_WritePin(GPIOB, right1_Pin,GPIO_PIN_RESET);   //停
	HAL_GPIO_WritePin(GPIOB, right2_Pin,GPIO_PIN_RESET);
}
void turnleft(void)
{
	//__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,70);
	leftSTOP();
	rightF();
}

void turnright(void)
{
	rightSTOP();
	leftF();
}

#ifndef __carrun_H
#define __carrun_H

#include "stm32f1xx.h"
#include "gpio.h"

void leftF(void);
void rightF(void);
void leftB(void);
void rightB(void);
void leftSTOP(void);
void rightSTOP(void);
void turnleft(void);
void turnright(void);
#endif

同样,改变占空比可以改变车速,还用这个函数,
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,2000);
3.ADC采集
对于自动寻迹,我们采用的是电磁寻迹,简单来说就是电磁感应,在车的前端安装电磁杆,赛道是通电的导线,周围会产生磁场,而电磁杆可以感应赛道交变磁场,产生感应电动势。离导线越近,磁场越强,产生的感应电动势就越大,单片机采集回来的电压就越大,判断转弯,也依据这个。讲完原理,我们来看一下采集电压的部分。
在这里插入图片描述

使能ADC1方式,按照需求打开通道,这里我开了六个通道,
在这里插入图片描述
打开DMA功能,可以解决批量数据的输入/输出问题。
在这里插入图片描述
把相关的配置选好,打开扫描模式和连续转换模式:
Scan Conversion Mode 扫描模式,当我们使用多通道采集的时候需要使能他去轮询读取每个通道值
Continous Conversion Mode 持续转换模式,一般我们都是连续转换,这个我们需要使能它
(注意使用几个通道打开几个通道,不然会数据错位,别问我怎么知道,问就是我踩过雷)
然后在生成的工程中添加代码

 HAL_ADC_Start_DMA(&hadc1,(uint32_t *)dat,6);

4.数据处理
我们通过ADC采到了电压之后,可以通过串口,OLED,或者蓝牙打印出来,返回的四位数,通过运算(x*3.3/4096)会得到电压,这里不返回实际电压也可以。为了让小车准确的转弯和直行,我们依次对数据进行滤波,归一化,有必要也可以限幅,再进行Pid。
##1.滤波算法有很多,我们这里是取20次数据然后求取平均值,为了小车更平滑,我们对平均值又取了20次求均值,就,无线套娃(手动狗头),代码如下

	for(i = 0;i < 6;i++)
					{
						for(j = 0;j < 20;j++)
						{
							data[j][i] = dat[i];
							sum += data[j][i];
						}
										adc[i]=sum/20;
										sum=0;
					}
					
					for(i = 0;i < 6;i++)
					{
					for(j = 0;j < 20;j++)
						{
							data2[j][i] = adc[i];
							sum += data[j][i];
						}
										data3[i]=sum/20;
										sum=0;
					}

##2.归一化,在刚开始了解归一化的时候,搜到了这张图
在这里插入图片描述
不禁小丑竟是我自己,其实归一化就是按照比例,把数字缩小在一个范围内,如果要把数字放在1到100以内,按照下面这个公式
y=100*(x-min)/(max-min),
于是我们得到代码

adc[j] = 100 * (adc[j] - 0) / (3400 - 0);

adc[j] 是滤波后的数据,max和min是赛道扫描得到的电感最大值和最小值。
经过归一化,就得到1到100之间的电压值,转弯的时候,靠近赛道的那一边感应电动势会变大,相应的数据变大,也就是哪边数据大,往哪边拐。
说到拐弯,就有拐弯角度的问题,这里就要用到PID算法,这里引用一篇别人的文章戳这里
关于PID我理解的也不是很深刻,就是比例,积分,微分,把偏差值按照比例累积,直接看代码吧


if(pwm1 <2)
	{
		__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,70);
	}
		if(adc[2]>adc[3]||adc[0]>adc[5])
		{
							
							i = pwm1*0.5+(i - i1)*0.3;
					__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,70 + i);
		
		}
		if(adc[2]<adc[3]||adc[0]<adc[5])
		{
						
					i = pwm1*0.5+(i - i1)*0.3;

					__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,70-i);
			
		}
		i1 = i;

这里定义的pwm1是电磁杆两端的偏差,然后给偏差乘以相应的系数,最后得出偏转角,如果左转用舵机中间位置减这个值,右转用舵机中间值加这个值。之后的调车,也就改变这两个系数。
最后说一点自己的感悟吧,做这个比赛的时候还是走了不少弯路,因为ADC通道设置少了,所以数据错误,导致车寻不到迹。在调车过程中,蓝牙的使用会方便查看数据。用心去做一个这样的东西,对自己能力的提高很有帮助,希望再接再厉,一直在前行。
欢迎指正

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地球先生_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值