DIY智能小车篇(三):功能模块之遥控、蓝牙、MERGE

若如初见. 提交于 2019-11-29 06:13:22

遥控模式

此模式可以利用遥控器完成模式的选择和小车前进后退等驱动功能,模式选择放在最后MERGE部分进行介绍。通讯协议直接用的YFRobot工作室写好的,方便实用,自己其实只需要会用就OK啦。通讯协议部分的程序这里就不贴啦,网上都能找得到。这里主要总结一下遥控器驱动小车的算法优化问题。遥控器模式选用红灯模式,摇杆返回模拟量,范围0~256,这里的算法思想就是,在0 ~ 128之间驱动小车前进,128 ~ 256之间驱动小车后退,并且按模拟量大小,速度线性变化,从而达到轻推摇杆以低速前进或者后退,重推摇杆以高速前进或者后退的目的。左转弯和右转弯类比前进与后退。驱动函数和普通的驱动函数不太一样,在驱动控制部分可以找得到。

/**
 * @brief: 实现了小车在遥控模式下的前进、后退、转向、停车
 * @param: NONE
 * @retval:NONE
 * @others: 对摇杆返回参数进行了一定的算法优化
**/
void Remote_Ctr(void)
{
	static int pss_data[2];//摇杆返回值数组,用于记录左右摇杆的返回值
	static int pulse_run;//驱动小车前进的pulse值
	static int turn_rate;//转向调整速率
	pss_data[0]=PS2_AnologData(PSS_LY);
	pss_data[1]=PS2_AnologData(PSS_RX);
	if(pss_data[0]<64)  //高速前进,利用一侧减速进行转弯
	{
		pulse_run=(int)(3.91*pss_data[0]);
		drive_pulse(pulse_run);
		if(pss_data[1]<128)
		{
			turn_rate=(int)(1-pss_data[1]/128);
			turn_pulse(pulse_run*(1+turn_rate),pulse_run);  //左侧减速		
		}
		else
		{
			turn_rate=(int)((pss_data[1]+1)/128-1);
			turn_pulse(pulse_run,pulse_run*(1+turn_rate));  //右侧减速
		}
	}
	else if(pss_data[0]<128)  //低速前进,利用一侧加速进行转弯
	{
		pulse_run=(int)(3.91*pss_data[0]);
		drive_pulse(pulse_run);
		if(pss_data[1]<128)		
		{
			turn_rate=(int)(1-pss_data[1]/128);
			turn_pulse(pulse_run,pulse_run*(1-turn_rate));		//右侧加速		
		}
		else
		{
			turn_rate=(int)((pss_data[1]+1)/128-1);
			turn_pulse(pulse_run*(1-turn_rate),pulse_run);		//左侧加速
		}
	}
	else if(pss_data[0]<192)		//低速后退,利用一侧加速进行转弯
	{
		pulse_run=(int)(500-3.91*(pss_data[0]-128));
		reverse_pulse(pulse_run);
	}
	else  //高速后退,利用一侧减速进行转弯
	{
		pulse_run=(int)(500-3.91*(pss_data[0]-128));
		reverse_pulse(pulse_run);
	}
}

蓝牙模式

此模式可以利用手机蓝牙完成模式的选择和小车前进后退等驱动功能,模式选择放在最后MERGE部分进行介绍。这里和遥控部分又不太一样,驱动函数和平时所用的一样,主要就是通过蓝牙信号的读取来驱动小车的运动,速度控制通过全局变量的GEAR来实现

串口配置

首先要对HC-05所连串口进行初始化,我这里选用了STM32的串口2

/**
 * @brief: 蓝牙模式初始化函数,初始化了串口2
 * @param: NONE
 * @retval:NONE
 * @others: NONE
**/
void Bluetooth_Ctr_Init(void)
{
	  GPIO_InitTypeDef GPIO_InitStructure;  
    USART_InitTypeDef USART_InitStrue;  
    NVIC_InitTypeDef NVIC_InitStrue;  
      
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//GPIOA端口使能  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//串口端口使能  
       
		GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART1); //GPIOA2复用为USART2
		GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART1); //GPIOA3复用为USART2
		
		//USART2端口配置
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; //GPIOA2与GPIOA3
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
		GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
		GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
		GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA2,PA3
      
    USART_InitStrue.USART_BaudRate=115200;  
    USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  
    USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;  
    USART_InitStrue.USART_Parity=USART_Parity_No;  
    USART_InitStrue.USART_StopBits=USART_StopBits_1;  
    USART_InitStrue.USART_WordLength=USART_WordLength_8b;  
      
    USART_Init(USART2,&USART_InitStrue);
      
    USART_Cmd(USART2,ENABLE);//使能串口2 
      
    USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//开启接收中断  
      
    NVIC_InitStrue.NVIC_IRQChannel=USART2_IRQn;  
    NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;  
    NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=0;  
    NVIC_InitStrue.NVIC_IRQChannelSubPriority=0;  
    NVIC_Init(&NVIC_InitStrue);  
}

串口2的中断服务函数与正点原子例程中串口1的中断函数完全一致

/**
 * @brief: 串口2中断服务函数
 * @param: NONE
 * @retval:NONE
 * @others: 与正点原子例程中串口1中断服务函数无差别
**/

void USART2_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART2);//(USART2->DR);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART_RX_STA&0x4000)//接收到了0x0d
			{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
			}
			else //还没收到0X0D
			{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
				{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
  } 
}

蓝牙控制的实现

这部分实现起来很简单,直接贴上代码

/*Bluetooth ctr-----------------------------------------------------------------*/
/**
 * @brief: 蓝牙的控制函数--小车的前进、后退、转向、停车
 * @param: NONE
 * @retval:NONE
 * @others: 打印字符是5,但是ASCII码却不是5而是0x35,大坑出现
**/
void Bluetooth_Ctr(void)
{
		extern u16 GEAR;
		if(USART_RX_BUF[0]==0x31)	//这里是个大坑,打印字符是5,但是ASCII码却不是5而是0x35。折腾了一下午
		{
			LED0=!LED0;
			drive(GEAR);
		}
		else if(USART_RX_BUF[0]==0x32)
		{
			LED1=!LED1;
			reverse(GEAR);
		}
		else if(USART_RX_BUF[0]==0x33)
		{
			LED0=!LED0;
			left_move(GEAR);
		}
		else if(USART_RX_BUF[0]==0x34)
		{
			LED1=!LED1;
			right_move(GEAR);
		}
		else if(USART_RX_BUF[0]==0x30)
		{
			LED0=0;
			LED1=0;
			stop();
		}
}

手机蓝牙调试助手的配置

前面功能的实现是基于手机蓝牙调试助手的,这里介绍下其配置过程

下载蓝牙调试助手

这里直接给大家啦,在网上找资源没找到

配置

将蓝牙模块装到控制板上之后进入手机蓝牙设置,进行匹配,匹配完成之后进入调试助手开始配置软件
进入之后会自动搜索出你的蓝牙模块名称
在这里插入图片描述
单击一下进入下面这里,点击连接设备
在这里插入图片描述
连接成功,点击键盘模式,咱们主要用这个模式,其他模式可以做测试用
在这里插入图片描述
点击右上角的三个点,再点击配置键盘值
在这里插入图片描述
然后点你要用的键盘位置,进行相应的设置,比如这里设置蓝牙模式选择,表示点一下就选择了蓝牙模式
在这里插入图片描述
然后设置START键表示确认模式选择,这是蓝牙模式就生效啦,当然这些都要在程序中体现的,我在MERGE处总结了
在这里插入图片描述
设置前进按钮,表示按下前进,松开停车,后退、左转、右转和这里设置是一样的
在这里插入图片描述
停车
在这里插入图片描述
急停
在这里插入图片描述
到这里调试助手就配置完成了

MERGE——遥控&&蓝牙

这里总结下如何将遥控和蓝牙的控制功能汇总到一起,实现可以同时用遥控和蓝牙控制的功能。同时里面也内置了软急停功能

/*Mode config-----------------------------------------------------------------*/
/**
 * @brief: 模式选择初始化函数,用于各个模式的初始化
 * @param: 按键值,遥控和蓝牙模式通用
 * @retval:NONE 
 * @Others: 由于主函数设置为直接用遥控和蓝牙选择模式,
						所以遥控蓝牙模式的初始化在主函数进行,此处不做设置
**/
void Mode_select(u8 key)
{
	switch(key)
	{
		case 13://REMOTE_CTR_MODE

			break;
		case 15://BLUETOOTH_MODE

			break;
		case 16://TRACE_MODE
				Trace_Init();	
			break;
		case 14://OBSTACLE_AVOID_MODE
				HCSR04_Init();
			break;
		
		case 66://REMOTE_CTR_MODE

			break;
		case 65://BLUETOOTH_MODE

			break;
		case 67://TRACE_MODE
				Trace_Init();	
			break;
		case 68://OBSTACLE_AVOID_MODE
				HCSR04_Init();
			break;
		default:
			break;
		
	}
}

/**
 * @brief: 模式运行功能函数
 * @param: 模式选择按键值,遥控和蓝牙模式通用
 * @retval:NONE
 * @Others: NONE
**/
void Mode_run(u8 mode)
{
	switch(mode)
	{
		case 13://REMOTE_CTR_MODE
				Remote_Ctr();
			break;
		case 15://BLUETOOTH_MODE
				Bluetooth_Ctr();
			break;
		case 16://TRACE_MODE
				TRACE_Implement();
			break;
		case 14://OBSTACLE_AVOID_MODE
				Obstacle_avoid();
			break;
		
		case 66://REMOTE_CTR_MODE
				Remote_Ctr();
			break;
		case 65://BLUETOOTH_MODE
				Bluetooth_Ctr();
			break;
		case 67://TRACE_MODE
				TRACE_Implement();
			break;
		case 68://OBSTACLE_AVOID_MODE
				Obstacle_avoid();
		
			break;
		default:
			break;
	}
}


/**
 * @brief: 模式选择扫描函数,用于扫描按下的键值从而进行相应的操作
 * @param: NONE
 * @retval:NONE
 * @Others: NONE
**/
void Mode_Scan(void)
{
		static int Start_flag=0;//开始运行标志位,非0时小车开始运行
		static u8 key1;//遥控模式下的选择键值  
		static u8 mode1;//遥控模式下的运行键值  
		static u8 key2;//蓝牙模式下的选择键值    
		static u8 mode2;//蓝牙模式下的运行键值  
		
		//遥控模式扫描
		key1=PS2_DataKey();
		if(key1==13|key1==14|key1==15|key1==16)//模式选择功能有按键按下
		{
		printf("  \r\n   %d  is  light  \r\n",Data[1]);//ID
		printf("  \r\n   %d  is  pressed  \r\n",key1);
		Mode_select(key1);
		mode1=key1;
		Start_flag=0;
		if(key1 == 11)
		{
			PS2_Vibration(0xFF,0x00); //发出震动后必须有延时  delay_ms(1000);
			delay_ms(500);
		}
		else if(key1 == 12)
		{
			PS2_Vibration(0x00,0xFF); //发出震动后必须有延时  delay_ms(1000);
			delay_ms(500);
		}
		else
			 PS2_Vibration(0x00,0x00); 
		}
		//按下start键,标志位置1,准备进入执行状态
		if(key1==4)   
		{
			Start_flag=1;
		}
		//start键按下,标志位置1,进入执行状态
		if(Start_flag==1)
		{
			Mode_run(mode1);
		}
		printf(" %5d %5d %5d %5d\r\n",PS2_AnologData(PSS_LX),PS2_AnologData(PSS_LY),
																	PS2_AnologData(PSS_RX),PS2_AnologData(PSS_RY) );
		
		//蓝牙模式扫描
		if(USART_RX_STA&0x8000)
		{					   
			printf("\r\n您发送的消息为:\r\n");		
			USART_SendData(USART1, USART_RX_BUF[0]);//按键值发送至电脑串口调试助手
			USART_SendData(USART2, USART_RX_BUF[0]); //按键值发送至手机蓝牙串口调试助手
			//模式选择功能有按键按下
			if(USART_RX_BUF[0]==0x41|USART_RX_BUF[0]==0x42|USART_RX_BUF[0]==0x43|USART_RX_BUF[0]==0x44)
			{
				key2=USART_RX_BUF[0];
				Mode_select(key2);
				Start_flag=0;
			}
			mode2=USART_RX_BUF[0];
			//按下start键,标志位置2,准备进入执行状态
			if(mode2==0x46)   
			{
				Start_flag=2;
			}
			
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;

		}
		//start键按下,标志位置2,进入执行状态
		if(Start_flag==2)
		{
			Mode_run(key2);
		}
		
		
		//软急停
		if(key1==1||mode2==83)
		{
			stop();
			Start_flag=0;
		}

}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!