#基于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通道设置少了,所以数据错误,导致车寻不到迹。在调车过程中,蓝牙的使用会方便查看数据。用心去做一个这样的东西,对自己能力的提高很有帮助,希望再接再厉,一直在前行。
欢迎指正