接前面几篇文章:
这节,终于让我们的小车成功的驱动起来了,能够实现基本功能:前进、后退、左转、右转,完成这一步,剩下的也就不难了,本节采用的是Wifi通信的方式来进行控制。
1、本节实验平台
- 小熊派开发板(当然如果你手上没有可以用别的stm32板子代替) 用于控制小车
- 普中STM32F103ZET6开发板(小车上的载板)
2、Wifi小车控制原理
2.1 说说Wifi控制的逻辑
本节采用的是小熊派上的两个按键,分别来控制小车前进、后退、停止,由于只有两个按键,所以后面又把它用来测试小车的左转、右转。
那么要用wifi控制小车动起来,控制板(小熊派)需要有一个wifi,让它处于客户端模式,而小车上的载板(上面连接着WIFI),让它处于服务器模式,这样,让控制板连接载板成功以后,接下来控制板发送自定义指令给载板,载板收到指令后即响应具体的指令,完成小车的前进、后退、左转、右转、停止的工作。
自定义协议定义:
控制指令 | 含义 |
LEFT | 让小车左转 |
RIGHT | 让小车左转 |
GO | 让小车前进 |
BACK | 让小车后退 |
STOP | 让小车停止 |
那么如何让WIFI处于服务器、客户端模式呢?请看以前的文章链接:
基于小熊派WIFI-ESP8266实践(中)-多功能处理显示等大杂烩
WIFI DTU产品设计与实现(基于STM32F103+QT配置上位机案例设计分享)
我们直接用以前做好的成功来完成我们的功能就好了。
2.2 再说说小车的控制逻辑
在我们前面第一、第二篇文章测试电机转的时候,默认我们使用的是全速转,也就是给;298N电机驱动模块某个管脚一个高电平,电机就全速转起来了,至于让四个轮如何向前转,如何向后转,这得根据你自己的接线方式来定,我是按照下面这个图来接的:(自己画的,还是不懂怎么接的话随时骚扰我)
本人经过接线测试后得出以下结论:
上面所表示的二进制数指的是电机驱动模块的控制端,而我有两个控制端,所以需要两组。
看到这里,那大家可能就会说了,如果我只给某个IO输出一个高电平,这样电机不就一直是全速前进或者全速后退吗?怎么能控制电机的速度呢?怎么能实现左转、右转呢?这里需要用到PWM的知识,什么是PWM呢?
PWM(Pulse Width Modulation):脉冲宽度调制
我们可以看看上图,上图就是一个典型的PWM的波形图。
T是一个周期,T1就是高电平所占用的时间,T2就是低电平所占用的时间。
如上图所示T1为脉冲宽度(就是导通时间),周期为T,则输出电压的平均值为U=VCC*T1/T=a*VCC
,a是占空比,变化范围为0≤a≤1
。在电压不变的情况下,改变a的大小就可以改变输出电压的平均值。这就是单片机的PWM调制技术。
如何改变a呢?可以采用定时器,也可以用普通的延时,一般情况下用定时器产生PWM输出信号,误差极小,而且控制也很准,我们平时经常听到的占空比,也就是高电平占整个周期的比例。
当要前进的时候,左右前后电机同时向前转,这时候PWM值可以设大一些。
当要后退的时候,左右前后电机同时向后转,这时候PWM值可以设大一些。
如下演示视频所示:
当要左转的时候,右边前后电机转的快一点(PWM值大一些),左边前后两个电机转的慢一点(PWM值小一些)。
当要右转的时候,左边前后电机转的快一点(PWM值大一些),右边前后两个电机转的慢一点(PWM值小一些)。
如下演示视频所示:
2.3 整体控制逻辑
- (1)控制板连接小车载板
- (2)连接载板成功后,控制板通过按键发送指令给小车载板(前进、后退、左转、右转)
- (3)小车载板收到控制指令后即控制电机实现指令要求的逻辑。
这样小车的基本框架就有了。
核心处理逻辑如下:(1)省略,文末自行查看代码,WIFI处理采用串口+DMA的方式
控制端(小熊派)
void button1_down_callback(void *ptr) { printf("按下1键\n"); //发送指令前进 wifi_init_printf("GO"); //发送指令左转 //wifi_init_printf("LEFT"); } void button1_up_callback(void *ptr) { printf("释放1键\n"); //发送指令停止 wifi_init_printf("STOP"); } void button2_down_callback(void *ptr) { printf("按下2键\n"); //发送指令后退 wifi_init_printf("BACK"); //发送指令右转 //wifi_init_printf("RIGHT"); } void button2_up_callback(void *ptr) { printf("释放2键\n"); //发送指令停止 wifi_init_printf("STOP"); }
小车载板端(STM32F103ZET6)
电机的8个控制端采用的是PWM进行驱动:
TIM1:PWM控制左边四路电机
TIM2:PWM控制右边四路电机
改变PWM占空比函数实现:
static void Motor_PWM_SetValue(TIM_HandleTypeDef *htim, uint32_t Channe, unsigned short value) { TIM_OC_InitTypeDef sConfigOC; if(value >= 1000 - 1) value = 999; sConfigOC.OCMode = TIM_OCMODE_PWM1; //改变PWM值 sConfigOC.Pulse = value; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; if (HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC, Channe) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Start(htim, Channe) != HAL_OK) { Error_Handler(); } }
相应的测试PWM值:
//停止 #define CCR0_Val 0 #define CCR1_Val 125 #define CCR2_Val 250 #define CCR3_Val 500 #define CCR4_Val 750 //最快速 #define CCR5_Val 999
WIFI小车控制处理
/*wifi接收指令处理*/ static void Wifi_Recv_Cmd_Process(void) { static int cmd_index = 0 ; char *cmd[] = {"LEFT", "RIGHT", "GO", "BACK", "STOP"}; if(strstr((char *)esp8266_info.rx_buffer, cmd[cmd_index]) != NULL) { HAL_UART_DMAStop(&huart2); HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); printf("接收到客户端发来的指令:%s\n", esp8266_info.rx_buffer); switch(cmd_index) { //左转 case 0: Motor_PWM_SetValue(&htim1, TIM_CHANNEL_1, CCR0_Val); //0 ==> 控制左前轮后 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_2, CCR2_Val); //1 ==> 控制左前轮前 ===> 慢 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_3, CCR5_Val); //1 ==> 控制右前轮前 ===> 快 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_4, CCR0_Val); //0 ==> 控制右前轮后 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_1, CCR2_Val); //1 ==> 控制左后轮前 ===> 慢 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_2, CCR0_Val); //0 ==> 控制左后轮后 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_3, CCR0_Val); //0 ==> 控制右后轮后 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_4, CCR5_Val); //1 ==> 控制右后轮前 ===> 块 break ; //右转 case 1: Motor_PWM_SetValue(&htim1, TIM_CHANNEL_1, CCR0_Val); //0 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_2, CCR5_Val); //1 快 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_3, CCR2_Val); //1 慢 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_4, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_1, CCR5_Val); //1 快 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_2, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_3, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_4, CCR2_Val); //1 慢 break ; //前进 case 2: Motor_PWM_SetValue(&htim1, TIM_CHANNEL_1, CCR0_Val); //0 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_2, CCR5_Val); //1 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_3, CCR5_Val); //1 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_4, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_1, CCR5_Val); //1 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_2, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_3, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_4, CCR5_Val); //1 break ; //后退 case 3: Motor_PWM_SetValue(&htim1, TIM_CHANNEL_1, CCR5_Val); //1 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_2, CCR0_Val); //0 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_3, CCR0_Val); //0 Motor_PWM_SetValue(&htim1, TIM_CHANNEL_4, CCR5_Val); //1 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_1, CCR0_Val); //0 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_2, CCR5_Val); //1 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_3, CCR5_Val); //1 Motor_PWM_SetValue(&htim2, TIM_CHANNEL_4, CCR0_Val); //0 break ; //停止 case 4: Moto_Stop(); break ; } memset(esp8266_info.rx_buffer, 0, RX_BUFF_SIZE); HAL_UART_Receive_DMA(&huart2, esp8266_info.rx_buffer, RX_BUFF_SIZE); } ++cmd_index ; if(5 == cmd_index) cmd_index = 0 ; }
这节我们直接实现了单片机跟单片机之前的WIFI通信,后面我们将继续拓展,开发一个手机APP,实现Android手机wifi连接小车,或者在笔记本PC端开发一个QT APP,然后通过笔记本的wifi连接小车,控制小车前进,后退,左转,右转。
案例下载
公众号后台回复wifi小车
即可获取。