赞
踩
目录
红-------------------------VCC
棕色----------------------GND
橙色----------------------信号线
舵机的控制信号为周期是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
舵机又分为数字舵机和模拟舵机。
数字舵机和模拟舵机(RC伺服系统)的机械结构是完全相同的,其最大的区别体现在控制电路上,数字舵机的伺服控制器采用了数字电路(拥有MCU和晶振),而模拟舵机的控制器采用的是模拟电路。
模拟舵机需要给它不停的发送PWM信号,才能让它保持在规定的位置或者让它按照某个速度转动,数字舵机则只需要发送一次PWM信号就能保持在规定的某个位置。
数字舵机以高得多的频率向马达发送动力脉冲,相对与传统的50脉冲/秒(50Hz),数字舵机的频率是300脉冲/秒(300Hz),因此反应速度更快。
结论:数字舵机系统总体优于模拟舵机
看舵机有无机械限位,有机械限位那么在上电是不能手动旋转舵机,反之
- //初始化舵机的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);//中转
L298N,是一款接受高电压的电机驱动器,直流电机和步进电机都可以驱动。一片驱动芯片可同时控制两个直流减速电机做不同动作,在6V到46V的电压范围内,提供2安培的电流,并且具有过热自断和反馈检测功能,可对电机进行直接控制,通过主控芯片的I/O输入对其控制电平进行设定,就可为电机进行正转反转驱动,操作简单、稳定性好,可以满足直流电机的大电流驱动条件。
12V供电----------------------------------电池的正极
输出A(out1,out2)----------------------接电机的正负极(正负极的改变可以改变轮子极性)
5V供电-----------------------------------可以给单片机供电,但一定要共地
输出A使能-------------------------------电机会以全速的状态运行,如果不接,则外接PWM控制速度
逻辑输入---------------------------------连接单片机引脚输入高低电平控制电机的转向
循迹原理非常简单,模块上配有一个输出指示灯,部分模块还有电源指示灯,我们主要关注输出指示灯。红外发射器一直发射红外线,红外线经发射后被接收,此时输出低电平,输出指示灯点亮。
黑色是不反射红外线的,也就是说循迹模块遇到黑线,模块输出高电平,输出指示灯熄灭。
当然除了遇到黑线熄灭,当距离太远红外线反射后检测不到,此时指示灯也会熄灭。那么如果要循迹,模块离地面要近,在没有遇到黑线时确保指示灯长亮,一旦指示灯熄灭就说明遇到黑线了
接口说明:
(1) VCC 外接3.3V-5V电压(可以直接与5v单片机和3.3v单片机相连)
(2) GND 外接GND
(3) OUT 小板数字量输出接口(0和1)
PS: 对于循迹来说,四个引脚一般就只用三个引脚即可(VCC,GND,DO)
当循迹模块距离地面太高时,会出现与循迹模块遇到黑线的一样情况,因此循迹模块距离地面不要太高。
超声波传感器发出的啁啾声通常在23 kHz到40 kHz之间,远高于人类听觉在20 kHz时的典型可听范围,因此称为超声波。
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离。
超声波有四个引脚口,即Vcc(5V),Gnd,Trig(控制端),Echo(接受端)。
(1)STM32给超声波的Trig管脚一个10微秒的高电平,此时将触发超声波工作。
(2)超声波发射端会发送8个40KHz的方波,方波发射后遇障碍物返回到超声波接收端。
(3)模块将记录超声波来回的时间,并从Echo管脚输出一个与该时间等长的高电平。
PS:
使用方法:一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出。一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离。如此不断的周期测,即可以达到你移动测量的值;
测试距离=(高电平时间*声速(340M/S))/2 =uS/58(厘米) 注意:1/58=0.017
2.1 M法测速(周期测量法)
简单地说就是根据单位时间一共有多少个脉冲来计算转速。
例如:统计时间 T0 为3s,在3s内测得的脉冲数M0 为60,而编码器的单圈脉冲数C为20,则转速n=60/(20*3)=1圈每秒
当M0很大,即转速快时,这个方法测得精度和平稳性都很好,但当M0很小,速度改变带来的M0变化很小,即转速慢时算出的误差就很大。所以M法测速适用于高转速场景
当转速较低时,每个统计时间 T0 内的计数值较小,由于统计时间的起始位置与编码器脉冲的上升沿不一定对应,当统计时间的起始位置不同时,会有一个脉冲的误差(只统计上升沿时,最多会有1个脉冲误差,统计上升沿和下降沿时,最多会有2个脉冲的误差)。
T法测速是这样操作的:是指先建立一个频率已知且固定的高频脉冲,当编码器读到一个信号,开始对高频脉冲进行计数,编码器第二个信号到来后,停止计数。根据对高频脉冲计数的次数、高频脉冲频率和电机转一圈编码器产生的脉冲数进行速度计算。
4.1 分辨率
指编码器能够分辨的最小单位。
码盘上透光线槽的数目其实就等于分辨率,也叫多少线,较为常见的有5-6000 线。
4.2 精度
首先明确一点,精度与分辨率是两个不同的概念。
精度是指编码器每个读数与转轴实际位置间的最大误差,通常用角度、角分或角秒来表示。
例如有些绝对式编码器参数表里会写±20′′,这个就表示编码器输出的读数与转轴实际位置之间存在正负20 角秒的误差。
精度由码盘刻线加工精度、转轴同心度、材料的温度特性、电路的响应时间等各方面因素共同决定。
4.3 最大响应频率
指编码器每秒输出的脉冲数,单位是Hz。计算公式为:
最大响应频率= 分辨率* 轴转速/60
例如某电机的编码器的分辨率为100(即光电码盘一圈有100条栅格),轴转速为120转每分钟(即每秒转2圈),则响应频率为100*120/60=200Hz,即该转速下,编码器每秒输出200个脉冲(电机带动编码器转了2圈嘛)。
4.4 信号输出形式
比如某光栅编码器一圈有N个栅格,理论上电机带动编码器转一圈,只能输出N个信号,通过倍频技术,可以实现转一圈,却能输出N*n个信号,这里的n为倍频数。
增量式编码器输出的脉冲波形一般为占空比50% 的方波,通道A 和B 相位差为90°。
增量式编码器是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大 小。其特点如下:
如下图,通道A和通道B的信号的周期相同,且相位相差1/4个周期,结合两相的信号值:
如下图,传感器转一圈后Z 轴信号才会输出一个脉冲,在Z轴输出时,可以通过将AB通道的计数清零,实现对码盘绝对位置的计算。
编码器计数原理与电机测速原理——多图解析 - 知乎 (zhihu.com)
ATK_ESP8266 模块支持 STA/AP/STA+AP 三种工作模式:
STA 模式:ESP8266 模块通过路由器连接互联网,手机或电脑通过互联网实现对设备的远程控制。
AP 模式:默认模式 ATK_ESP8266 模块作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制。
STA+AP 模式:两种模式的共存模式,(STA 模式)即可以通过路由器连接到互联网,并通过互联网控制设备;
- 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);
- }
1.如果要发送AT指令,则先发送+++退出透传模式,然后通过串口发送数据给esp8266
2.如果要发数据,则先进入透传模式,然后通过串口发送数据给esp8266
- 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);
- }
推挽输出和开漏输出的比较,见下面文章
- 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);
- }
- //采用浮空输入的原因在于循迹模块不知道默认的电平是多少,所以采用浮空输入
- //定时器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档驱动能力太弱,导致电机不能驱动轮子转动
- //初始化舵机的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);
- }
- //获取定时器时间
- 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的延时
- //先测量前方距离,如果距离小于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);
- }
- }
- }
- }
小车完整视频
链接:https://pan.baidu.com/s/1UK1skGeU-ubAGAOLYmdHZg?pwd=8888
提取码:8888
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。