循迹避障无线通信小车

目录

1. 舵机

(1) 接线方法

  (2)   工作原理

  (3)  舵机种类

(4) 代码书写

2.L298N驱动

(1) 简介

(2) 电源引脚

3.红外循迹

(1)简介

(2)引脚说明

4.超声波测距

(1)简介

(2)超声波测距原理 

(3) 使用方法

5.编码器测速

(1)引脚接法

(3)测速方法

(3)编码器接口简介

(4)编码器参数

(5)编码器倍频

(6)编码器分类:增量式编码器

(7)此文章写的很好,可以仔细阅读

4. 高级定时器和低级定时器的区别

5.esp8266

(1)工作模式

(2)服务端AT指令

(3)通信步骤

二、代码详解

(1)电机的初始化

(2) 循迹初始化

(3)PWM控制小车轮子速度

(4)初始化舵机

(5)超声波测距

(6)避障思路

三、小车运行完整视频

四、完整工程


1. 舵机

(1) 接线方法


                        红-------------------------VCC
                        棕色----------------------GND
                        橙色----------------------信号线

  (2)   工作原理

        舵机的控制信号为周期是20ms 的脉宽调制(PWM)信号,其中脉冲宽度从0.5ms-2.5ms,相对应舵盘的位置为0—180度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。舵机内部有一个基准电路,产生周期20ms,宽度1.5ms的基准信号,有一个比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。

        控制电路板接受来自信号线相应的PWM控制信号,进而控制电机转动,电机带动一系列齿轮组,减速后传动至输出舵盘。舵机的输出轴和位置反馈电位计是相连的,舵盘转动的同时,带动位置反馈电位计,电位计将输出一个电压信号到控制电路板,进行反馈,然后控制电路板根据所在位置决定电机的转动方向和速度,从而达到目标停止。

        舵机的控制需要MCU产生一个周期为20ms的脉冲信号,以0.5ms到2.5ms的高电平来控制舵机转动的角度。

	TIM_TimeBaseInitStructure.TIM_Period = (200-1);			//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler =  (7200-1);	//PSC
    //此时周期就为20ms,如果传入TIM_Period=5,则输出信号脉冲宽度为0.5ms

             循迹避障无线通信小车_第1张图片

  (3)  舵机种类

  1. 180度舵机可以控制旋转角度,有角度定位,上电后舵机会自动恢复到之前设置的角度位置
  2. 360度舵机不可以控制角度,只能顺时针旋转、逆时针旋转、停止、调节转速、无角度定位,上电之后不会角度不会复位
  3. 舵机又分为数字舵机和模拟舵机。

    数字舵机和模拟舵机(RC伺服系统)的机械结构是完全相同的,其最大的区别体现在控制电路上,数字舵机的伺服控制器采用了数字电路(拥有MCU和晶振),而模拟舵机的控制器采用的是模拟电路。
    模拟舵机需要给它不停的发送PWM信号,才能让它保持在规定的位置或者让它按照某个速度转动,数字舵机则只需要发送一次PWM信号就能保持在规定的某个位置。
    数字舵机以高得多的频率向马达发送动力脉冲,相对与传统的50脉冲/秒(50Hz),数字舵机的频率是300脉冲/秒(300Hz),因此反应速度更快。

    结论:数字舵机系统总体优于模拟舵机

  4. 看舵机有无机械限位,有机械限位那么在上电是不能手动旋转舵机,反之

(4) 代码书写

//初始化舵机的PWM,通道3
void steer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = (200-1);			//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler =  (7200-1);	//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;						 //配置为PWM模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;													 //设置占空比大小,在主函数compare中又设置一遍
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		 //输出通道电平极性配置
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;	 //输出通道空闲电平极性配置
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);			   						 //初始化通道3
	TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);						 //使能通道3输出
	
	TIM_Cmd(TIM2, ENABLE);
}


TIM_SetCompare3(TIM2,15);//中转

2.L298N驱动

(1) 简介

        L298N,是一款接受高电压的电机驱动器,直流电机和步进电机都可以驱动。一片驱动芯片可同时控制两个直流减速电机做不同动作,在6V到46V的电压范围内,提供2安培的电流,并且具有过热自断和反馈检测功能,可对电机进行直接控制,通过主控芯片的I/O输入对其控制电平进行设定,就可为电机进行正转反转驱动,操作简单、稳定性好,可以满足直流电机的大电流驱动条件。

循迹避障无线通信小车_第2张图片

(2) 电源引脚

  • 循迹避障无线通信小车_第3张图片5V 驱动芯片内部逻辑供电引脚,如果安装了5V跳帽,则此引脚可输出5V电压,为微控板或其他电路提供电力供给,如果拔掉5V跳帽,则需要独立外接5V电源

12V供电----------------------------------电池的正极
输出A(out1,out2)----------------------接电机的正负极(正负极的改变可以改变轮子极性)
5V供电-----------------------------------可以给单片机供电,但一定要共地
输出A使能-------------------------------电机会以全速的状态运行,如果不接,则外接PWM控制速度
逻辑输入---------------------------------连接单片机引脚输入高低电平控制电机的转向

3.红外循迹

(1)简介

        循迹原理非常简单,模块上配有一个输出指示灯,部分模块还有电源指示灯,我们主要关注输出指示灯。红外发射器一直发射红外线,红外线经发射后被接收,此时输出低电平,输出指示灯点亮。
        黑色是不反射红外线的,也就是说循迹模块遇到黑线,模块输出高电平,输出指示灯熄灭。
当然除了遇到黑线熄灭,当距离太远红外线反射后检测不到,此时指示灯也会熄灭。那么如果要循迹,模块离地面要近,在没有遇到黑线时确保指示灯长亮,一旦指示灯熄灭就说明遇到黑线了

(2)引脚说明

接口说明:

(1) VCC 外接3.3V-5V电压(可以直接与5v单片机和3.3v单片机相连)

(2) GND 外接GND

(3) OUT 小板数字量输出接口(0和1)

PS: 对于循迹来说,四个引脚一般就只用三个引脚即可(VCC,GND,DO)

        当循迹模块距离地面太高时,会出现与循迹模块遇到黑线的一样情况,因此循迹模块距离地面不要太高。

4.超声波测距

(1)简介

循迹避障无线通信小车_第4张图片

超声波传感器发出的啁啾声通常在23 kHz到40 kHz之间,远高于人类听觉在20 kHz时的典型可听范围,因此称为超声波。

超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离。

超声波有四个引脚口,即Vcc(5V),Gnd,Trig(控制端),Echo(接受端)。

(2)超声波测距原理 

循迹避障无线通信小车_第5张图片

(1)STM32给超声波的Trig管脚一个10微秒的高电平,此时将触发超声波工作。

(2)超声波发射端会发送8个40KHz的方波,方波发射后遇障碍物返回到超声波接收端。

(3)模块将记录超声波来回的时间,并从Echo管脚输出一个与该时间等长的高电平。

PS:

  1. 建议测量周期为60ms以上,以防止发射信号对回响信号的影响。
  2. 此模块不宜带电连接,若要带电连接,则先让模块的GND端先连接,否则会影响模块的正常工作。
  3. 测距时,被测物体的面积不少于05平方米且平面尽量要求平整,否则影响测量的结果。
  4. 由于声速取决于温度和湿度,环境条件可能会改变测量的准确性。

(3) 使用方法

使用方法:一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出。一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离。如此不断的周期测,即可以达到你移动测量的值;

测试距离=(高电平时间*声速(340M/S))/2 =uS/58(厘米)   注意:1/58=0.017

5.编码器测速

(1)引脚接法

循迹避障无线通信小车_第6张图片循迹避障无线通信小车_第7张图片

循迹避障无线通信小车_第8张图片

(3)测速方法

        2.1 M法测速(周期测量法)

        简单地说就是根据单位时间一共有多少个脉冲来计算转速。

  • 编码器单圈总脉冲数为C(常数)
  • 统计时间为T0 (固定值,单位秒)
  • 该时间内统计到的编码器脉冲数为M0 (测量值)

        例如:统计时间 T0 为3s,在3s内测得的脉冲数M0 为60,而编码器的单圈脉冲数C为20,则转速n=60/(20*3)=1圈每秒        ​

        当M0​很大,即转速快时,这个方法测得精度和平稳性都很好,但当M0​很小,速度改变带来的M0​变化很小,即转速慢时算出的误差就很大。所以M法测速适用于高转速场景

        当转速较低时,每个统计时间 T0 内的计数值较小,由于统计时间的起始位置与编码器脉冲的上升沿不一定对应,当统计时间的起始位置不同时,会有一个脉冲的误差(只统计上升沿时,最多会有1个脉冲误差,统计上升沿和下降沿时,最多会有2个脉冲的误差)。

        2.2 T法测速(频率测量法)

        ​ T法测速是这样操作的:是指先建立一个频率已知且固定的高频脉冲,当编码器读到一个信号,开始对高频脉冲进行计数,编码器第二个信号到来后,停止计数。根据对高频脉冲计数的次数、高频脉冲频率和电机转一圈编码器产生的脉冲数进行速度计算。

  • 编码器单圈总脉冲数为C(常数)
  • 高频脉冲的频率为 F0 (固定值,单位Hz)
  • 捕获到编码器相邻两个脉冲的间隔时间为TE ,其间的计数值为 M1 (测量值)

循迹避障无线通信小车_第9张图片

        2.3 M/T法测速

循迹避障无线通信小车_第10张图片

(3)编码器接口简介

  • Encoder Interface 编码器接口
  • 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
  • 每个高级定时器和通用定时器都拥有1个编码器接口
  • 定时接入了编码器接口,此时定时器基本不能干其他事情,因此硬件资源减少,但是可以用软件资源外部中断弥补,即硬件资源和软件资源是互补的。
  • PS:有硬件资源的情况下,优先使用硬件资源,节约下来的软件资源去做其他更重要的事情。比如PWM,直接利用定时中断,然后在中断里面手动计数,手动翻转电平。输入捕获,利用外部中断或者定时中断,然后在终端里面手动把cnt的值取出来,当一个条件满足时,开启定时器功能,再将cnt里面的值置0,然后在中断里面进行计数,等到条件不满足了,在关闭定时器功能,把中断溢出次数加上cnt的值就可以获得次数。
  • 两个输入引脚借用了输入捕获的通道1和通道2

(4)编码器参数

4.1 分辨率

指编码器能够分辨的最小单位。

  • 对于增量式编码器,其分辨率表示为编码器转轴旋转一圈所产生的脉冲数,即脉冲数/转(Pulse Per Revolution 或PPR)

码盘上透光线槽的数目其实就等于分辨率,也叫多少线,较为常见的有5-6000 线。

  • 对于绝对式编码器,内部码盘所用的位数就是它的分辨率,单位是位(bit),具体还分单圈分辨率和多圈分辨率。

4.2 精度

首先明确一点,精度与分辨率是两个不同的概念。

精度是指编码器每个读数与转轴实际位置间的最大误差,通常用角度、角分或角秒来表示。

例如有些绝对式编码器参数表里会写±20′′,这个就表示编码器输出的读数与转轴实际位置之间存在正负20 角秒的误差。

精度由码盘刻线加工精度、转轴同心度、材料的温度特性、电路的响应时间等各方面因素共同决定。

4.3 最大响应频率

指编码器每秒输出的脉冲数,单位是Hz。计算公式为:

最大响应频率= 分辨率* 轴转速/60

例如某电机的编码器的分辨率为100(即光电码盘一圈有100条栅格),轴转速为120转每分钟(即每秒转2圈),则响应频率为100*120/60=200Hz,即该转速下,编码器每秒输出200个脉冲(电机带动编码器转了2圈嘛)。

4.4 信号输出形式

  • 对于增量式编码器,每个通道的信号独立输出,输出电路形式通常有集电极开路输出、推挽输出、差分输出等。
  • 对于绝对式编码器,由于是直接输出几十位的二进制数,为了确保传输速率和信号质量,一般采用串行输出或总线型输出,例如同步串行接口(SSI)、RS485、CANopen 或EtherCAT 等,也有一部分是并行输出,输出电路形式与增量式编码器相同。

(5)编码器倍频

        比如某光栅编码器一圈有N个栅格,理论上电机带动编码器转一圈,只能输出N个信号,通过倍频技术,可以实现转一圈,却能输出N*n个信号,这里的n为倍频数。

增量式编码器输出的脉冲波形一般为占空比50% 的方波,通道A 和B 相位差为90°。

  • 如果只使用通道A计数,并且只捕获通道A的上升沿,则一圈的计数值=码盘的栅格数,即为1倍频(没有倍频)
  • 如果只使用通道A计数,并且捕获了通道A的上升沿和下降沿,则编码器转一圈的计数值翻倍,实现2倍频
  • 如果既使用通道A计数,又使用通道B计数,且都捕获了上升沿和下降沿,则实现了4倍频

(6)编码器分类:增量式编码器

增量式编码器是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大 小。其特点如下:

  • 只有当设备运动时才会输出信号。
  • 一般会输出通道A和通道B 两组信号,并且有90° 的相位差(1/4个周期),同时采集这两组信号就可以计算设备的运动速度和方向。

如下图,通道A和通道B的信号的周期相同,且相位相差1/4个周期,结合两相的信号值:

  • 当B相和A相先是都读到高电平(1 1),再B读到高电平,A读到低电平(1 0),则为顺时针
  • 当B相和A相先是都读到低电平(0 0),再B读到高电平,A读到低电平(1 0),则为逆时针
  • 除通道A、通道B 以外,还会设置一个额外的通道Z 信号,表示编码器特定的参考位置

如下图,传感器转一圈后Z 轴信号才会输出一个脉冲,在Z轴输出时,可以通过将AB通道的计数清零,实现对码盘绝对位置的计算。

  • 增量式编码器只输出设备的位置变化和运动方向,不会输出设备的绝对位置。

(7)此文章写的很好,可以仔细阅读

编码器计数原理与电机测速原理——多图解析 - 知乎 (zhihu.com)

4. 高级定时器和低级定时器的区别

5.esp8266

(1)工作模式

ATK_ESP8266 模块支持 STA/AP/STA+AP 三种工作模式:

STA 模式:ESP8266 模块通过路由器连接互联网,手机或电脑通过互联网实现对设备的远程控制。

AP 模式:默认模式 ATK_ESP8266 模块作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制。

STA+AP 模式:两种模式的共存模式,(STA 模式)即可以通过路由器连接到互联网,并通过互联网控制设备;

(2)服务端AT指令

AT+CWMODE=1 配置STA模式
AT+RST 重启生效
AT+CWJAP=“wifi名称”,“WiFi密码” 连接WIFI
AT+CIPMUX=0 设置单路连接模式,=1为多路连接
AT+CIPSTART=“TCP”,“服务器ip地址”,端口号 连接服务器
AT+CIPMODE=1 开启透传模式
AT+CIPSEND 开始透传



void esp8266_start_trans(void)
{
	//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
	esp8266_send_cmd("AT+CWMODE=1","OK",50);
	
	//让Wifi模块重启的命令
	esp8266_send_cmd("AT+RST","ready",20);
	
	delay_ms(1000);         //延时3S等待重启成功
	delay_ms(1000);
	delay_ms(1000);
	delay_ms(1000);
	
	//让模块连接上自己的路由
	while(esp8266_send_cmd("AT+CWJAP=\"TP_226\",\"226226226\"","WIFI GOT IP",600));
	
	//=0:单路连接模式     =1:多路连接模式
	esp8266_send_cmd("AT+CIPMUX=0","OK",20);
	
	//建立TCP连接  这四项分别代表了 要连接的ID号0~4   连接类型  远程服务器IP地址   远程服务器端口号
	while(esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"192.168.1.100\",8080","CONNECT",200));
	
	//是否开启透传模式  0:表示关闭 1:表示开启透传
	esp8266_send_cmd("AT+CIPMODE=1","OK",200);
	
	//透传模式下 开始发送数据的指令 这个指令之后就可以直接发数据了
	esp8266_send_cmd("AT+CIPSEND","OK",50);
}

(3)通信步骤

1.如果要发送AT指令,则先发送+++退出透传模式,然后通过串口发送数据给esp8266

2.如果要发数据,则先进入透传模式,然后通过串口发送数据给esp8266

二、代码详解

(1)电机的初始化

void motor_gpio()
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_8|GPIO_Pin_4|GPIO_Pin_3;		
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 	 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 
  GPIO_Init(GPIOA, &GPIO_InitStructure);			     
}

推挽输出和开漏输出的比较,见下面文章

(2) 循迹初始化

void xunji_gpio()
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_5;		
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);		
}
//采用浮空输入的原因在于循迹模块不知道默认的电平是多少,所以采用浮空输入

(3)PWM控制小车轮子速度

//定时器2的2个PWM通道驱动小车的四个轮子
void PWM_Init(u16 arr,u16 psc)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = arr;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = psc;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

//PWM_Init(100,7199);则小车的速度可以为1--100档,低于10档驱动能力太弱,导致电机不能驱动轮子转动

(4)初始化舵机

//初始化舵机的PWM,通道3
void steer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = (200-1);			//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler =  (7200-1);	//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;						 //配置为PWM模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;													 //设置占空比大小,在主函数compare中又设置一遍
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		 //输出通道电平极性配置
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;	 //输出通道空闲电平极性配置
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);			   						 //初始化通道3
	TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);						 //使能通道3输出
	
	TIM_Cmd(TIM2, ENABLE);
}

(5)超声波测距

//获取定时器时间
u32 GetEchoTimer(void)
{
	u32 t = 0;
	t = msHcCount*1000;    
	t += TIM_GetCounter(TIM4);    
	TIM4->CNT = 0;     //将TIM2计数寄存器的计数值清零
	delay_ms(50);
	return t;
}

//一次获取超声波测距数据 两次测距之间需要相隔一段时间,隔断回响信号
//为了消除余震的影响,取五次数据的平均值进行加权滤波。
float Hcsr04GetLength(void )
{
	u32 t = 0;
	int i = 0;
	float lengthTemp = 0;
	float sum = 0;
	while(i!=5)
	{
		
	TRIG_Send = 1;      //发送口高电平输出
	delay_us(20);
	TRIG_Send = 0;
		
	while(ECHO_Reci == 0);      //等待接收口高电平输出
		
	OpenTimerForHc();        //打开定时器
	i = i + 1;
	while(ECHO_Reci == 1);
	CloseTimerForHc();        //关闭定时器
		
	t = GetEchoTimer();        //获取时间,分辨率为1US
		
	lengthTemp = ((float)t/58.0);
	sum = lengthTemp + sum ;
	
	}
	lengthTemp = sum/5.0;
	return lengthTemp;
}

//PS:每一次测距之间必须要有大于50Ms的延时

(6)避障思路

//先测量前方距离,如果距离小于40cm,则后退一些,测量左边和右边的距离,如果左边离障碍物的距离远,则左转,反之,
此程序有bug:
1.如果左右两边都不存在障碍物或者障碍物德距离一样,他可能出现先左转,在右转,一直循环到一个地方的情况
2.超声波检测不到很低范围的障碍物,导致当车子已经停止了,因为没有检测到障碍物,从而卡死在某个地方,所以就要采用编码器测速,当速度低于某一个值得时候,要先后退一些,要重新检测
3.总之,自己多想就会发现很多漏洞,需要一步一步完善,作者此处仅仅列出自己想到得,希望看到得你可以完善得更加完美
void avoidObstacle(void)
{
	forward(25);
	measureSpeed();
	float len=Hcsr04GetLength();
	showDistance(len);
	while(1)
	{
		len=Hcsr04GetLength();
		showDistance(len);
		
		measureSpeed();
		if(cnt<1)
		{
			len=0;
		}
		
		if(len<40)
		{
			back(30);
			delay_ms(500);
			
			TIM_SetCompare3(TIM2,10);//右转
			delay_ms(200);
			float len1=Hcsr04GetLength();
			showDistance(len1);
			
			TIM_SetCompare3(TIM2,20);//左转
			delay_ms(200);
			float len2=Hcsr04GetLength();
			showDistance(len2);
			
			TIM_SetCompare3(TIM2,15);//中转
			back(30);
			delay_ms(300);
			
			if(len1>len2)
			{
				right(50);
				delay_ms(500);
				forward(35);
			}
			else
			{
				left(50);
				delay_ms(500);
				forward(35);
			}
		}
	}
}

三、小车运行完整视频

循迹避障无线通信小车_第11张图片

循迹避障无线通信小车_第12张图片

 

小车完整视频

四、完整工程

链接:https://pan.baidu.com/s/1UK1skGeU-ubAGAOLYmdHZg?pwd=8888 
提取码:8888

你可能感兴趣的:(c语言,stm32,嵌入式硬件)