发作品签到
专业版

【立创开发板】基于梁山派的多功能语音播报车

工程标签

3.4k
0
0
1

简介

1、蓝牙控制、WIFI控制、自制摇杆控制、自动追光、循迹避障、语音播报等功能; 2、使用0.96寸IIC接口的OLED屏移植u8g2图形库,实现高刷新率和和精美UI显示。

简介:1、蓝牙控制、WIFI控制、自制摇杆控制、自动追光、循迹避障、语音播报等功能; 2、使用0.96寸IIC接口的OLED屏移植u8g2图形库,实现高刷新率和和精美UI显示。

开源协议

GPL 3.0

创建时间:2023-01-04 11:33:35更新时间:2023-03-01 06:30:09

描述

做为一个电子人,怎么能没有自己的小车?(doge)

本来想做一个平衡小车车,但是看到教程这么丰富,忍不住跟着一起做了一个飞法法的4轮车。(弟弟说不喜欢两轮,哭唧唧)

项目介绍

该项目为立创开发板寒假训练营项目,跟着学习下来,一共掌握了:
  • 对常用电机驱动有一定了解,并自己画电路实现了功能;
    
  • 掌握循迹电路原理,并实现了小车循迹功能;
    
  •  掌握SR04超声波模块测距原理,并完成了测距功能,实现避障;
    
  • 整个小车的电源部分,采用3节18650电池并联,并实现充电功能;
    
  • 使用便宜又常用的0.96IIC接口的OLED屏进行显示,认识到一个单色GUI库,并移植成功显示比较好看的界面;
    
  • 使用蓝牙模块HC05做无线控制,实现手机APP通过蓝牙控制小车;
    
  • 使用WIFI模块ESP8266做局域网控制,实现手机APP通过WIFI控制小车;
    
  • 使用2.4G模块NRF24L01做摇杆控制,设计了一个遥控杆,摇杆通过NRF控制小车;
    
  • 使用3个光敏电阻,放在3个方向,实现追光模式(就是那一边比较亮,就往哪一个开)
    

还加了一个语音播报功能。在开源平台上看到,非常想实现这个功能。试着按照数据手册设计,结果一次就过了,可喜可贺。就是声音太生硬成本也高。

硬件实现

电源部分

为了电池能够稳固的定在小车上,我选择了贴片类型的电池盒,这个有点贵。。
图片.png
如果可以,我建议是使用下面这个,这个也可以固定在板子上。但是它是插件,如果电路板很紧凑,一个通孔都没有位置放还是不要用了。
图片.png
因为要用到5V和3.3V和电机的8V,并且是3.7V的电池供电。所以我的供电方式是有三种。
1、电池电压->升压->5V

图片.png

2、电池电压->升压->8V
我之前购买的电机是6V300转的,所以我为什么用8V供电?因为我算了一下的电阻分配,我24K电阻都没有用过多少,就搞了进去,实测确实是7.8V左右,并且电机也没有发生什么问题。
图片.png
图片.png

3、5V -> 3.3V
直接使用升压后的5V再降压到3.3V给一些模块供电。(这个方案我不太喜欢,元件太大了,但是我在学习硬件的时候,买了这个方案的物料很多)
图片.png
4、电源开关
小车肯定要有开关功能啊,是吧?本来开关有个长按开机电路的,但是想到如果搞长按开机,调试小车估计按键都给整坏,就放弃了长按开机的想法。
图片.png
5、电池充电
使用的是老生常谈的TC4056,通过TYPE-C充电。
图片.png
电源部分完结!!

控制部分

控制部分大多是使用的模块,有蓝牙控制,WIFI控制、NRF控制。还要控制屏幕,控制语音播报这些。

1、电机控制
使用的是DRV8833进行驱动,挺好用,就是4个电机需要8个PWM。那个VM引脚是电机供电引脚,建议加个大电容,防止电机偷电太多。
图片.png
2、WIFI、蓝牙和屏幕控制
这个WIFI模块也是一个吃电大户,被它坑过一次,所以我单独给WiFi模块一个1117供电。屏幕的通信方式是IIC,我使用的是软件IIC方式,所以引脚就随便放啦。我还写了关于GD32F450如何移植0.96屏幕代码,见链接:立创梁山派GD32F450ZGT6--移植4针0.96寸OLED显示屏
WIFI模块使用的是ESP8266,蓝牙模块使用的是HC05(蓝牙模块这里我忘记连接一个手机连接成功指示引脚了,该打)。
图片.png
3、NRF控制
NRF模块是采购的泽耀科技的NRF24L01模块,他家的模块资料比较丰富,我买的这个只要会SPI就可以移植了。
图片.png
图片.png
4、语音播报
它是通过串口进行控制,比如发送一串字符串"嘉立创天长地久",通过特定的帧格式,它就会播报语音"嘉立创天长地久"。
这个画的比较乱,这里在VDD上都加了100nF和10uF,说是能够让音质好点,可能是我PCB布局有问题,声音能听懂,但是很沙哑。
图片.png
5、其他控制
蜂鸣器我模拟为汽车的喇叭;
左右转灯使用LED代替;
关于语音播报的电源门控,我的想法是,有人比较喜欢安静,所以搞了一个可以通过软件控制语音播报电路的电源,关了电源,它就不能播报啦。
图片.png

采集部分

采集部分,分别有温湿度采集、电量采集、光照度采集、超声波测距采集、5路循迹采集;
1、电量采集和温湿度采集
电量采集是以前刚学硬件时,自己想的。就欧姆定律计算出两点的电压最高3.3V,对它进行采集换算等到实际电量。
后面发现很多大佬都是使用10K这样的多路分压读取对应比例的电量(我又是一个固步自封的例子,哭唧唧)
不过我这里已经完善了这个电量方面的代码,所以无所谓了。
温湿度方面,本来想使用SHT30这种小型高精度的温湿度模块,但是看到它的价格,选了又选,看了又看,最后买了DHT11(我真的穷疯了doge)
温湿度也吃过亏,我之前以为数据口可以通过内部电阻的上拉就可以,但是实际使用发现外部最好要加一个4.7K的上拉电阻,不然读出的数据不准,其在数据手册上也有说明。
图片.png
图片.png
2、超声波与光敏采集
光敏是想用作追光设计的,把3个光敏分别放在3个方向,哪一个方向比较亮就往哪一边跑(其实是想多实践一下PID)。
超声波使用的是常用的SR04模块,原理就不说啦,在百度上都很详细了。
图片.png
3、循迹电路
循迹是通过电压比较实现的高低电平变化,采集这些变化就知道当前是否走在特定的轨迹上了。
图片.png

PCB方面我就不说了,谁教谁还不一定呢。。我只能说 我还有很大的进步空间,哈哈

软件实现

1、蓝牙控制

使用的是HC05蓝牙模块,使用之前需要对模块进行一下配置。(在附件有资料)
按住模块上的按键或EN脚拉高,此时灯是慢闪,HC-05进入AT命令模式,默认波特率是38400;此模式我们叫原始模式。原始模式下一直处于AT命令模式状态。记住!!每一条指令都要加上\r\n,不然是识别不到命令的,可以发送: AT 测试一下是否返回OK
图片.png
最主要的是设置模式为从机控制,即等待手机去连接我们蓝牙模块的蓝牙,主要由手机控制。发送:AT+ROLE0
图片.png
我这里还修改了波特率,改为了115200, 发送:AT+UART=115200,0,0
图片.png
还可以修改蓝牙名称, 发送: AT+NAME=智能车
图片.png
这里如果你发现你的手机APP连接不上你的蓝牙模块的话,应该是配对密码错误的问题。大多APP的蓝牙配对密码是1234,
所以发送:AT+PSWD=1234
也可以发送 AT+PSWD? 查询密码
图片.png
这样就配置完成了,给蓝牙模块断电再通电,它的名称就是智能车,通信波特率是115200。并且当手机连接成功后,模块上狂闪的灯就长亮,表示连接成功。

看一下我所实现的代码:

我手机上发送特定的指令去控制小车动作

/************************************************************
 * 函数名称:WIFI_control
 * 函数说明:根据手机发送过来的命令,进行相应的控制
 * 型    参:cmd=手机发送过来的命令(具体命令见指令表)
 * 返 回 值:无
 * 备    注:指令与蓝牙模块通用
 * 					  指令表
		             【接收的数据】		【功能】
				0x00		 停止
				0x01		 前进
				0X02		 后退
				0X03		 左转
				0X04		 右转
				0X05		 左转灯亮再按灭
				0X06		 右转灯亮再按灭
				0X07		 速度加
				0X08		 速度减
				0X09		 喇叭响再按灭
*************************************************************/
void WIFI_control(unsigned char cmd)
{
	switch( cmd )
	{
		case 0x00://停止
			MOTOR_stop();
			break;
		
		case 0x01://前进
			MOTOR_forward(CAR_SPEED, CAR_SPEED);
			break;
		
		case 0x02://后退
			MOTOR_back(CAR_SPEED, CAR_SPEED);
			break;	
		
		case 0x03://左转
			MOTOR_left(CAR_SPEED, CAR_SPEED);
			break;	
		
		case 0x04://右转
			MOTOR_right(CAR_SPEED, CAR_SPEED);
			break;	
		
		case 0x05://左转灯亮再按灭
			Turn_Light_Con(LEFT_LED_FLAG=!LEFT_LED_FLAG, SET);
			break;	
		
		case 0x06://右转灯亮再按灭
			Turn_Light_Con(SET, RIGHT_LED_FLAG=!RIGHT_LED_FLAG);
			break;
		
		case 0x07://速度加
			CAR_SPEED = CAR_SPEED + 500;
			if( CAR_SPEED >= 7999 ) CAR_SPEED = 7999;
			break;	
		
		case 0x08://速度减
			CAR_SPEED = CAR_SPEED - 500;
			if( CAR_SPEED <= 500 ) CAR_SPEED = 500;
			break;			
		
		case 0x09://喇叭控制
			BEEP_FLAG = !BEEP_FLAG;
			if( BEEP_FLAG == 1 )
			{
				BEEP_ON();
			}
			else
			{
				BEEP_OFF();
			}
			break;			
		default:break;
	}
}

2、WIFI控制

首先要控制WIFI模块开启WIFI,让我们可以通过连接它的WIFI,去控制它。

/************************************************************
 * 函数名称:ESP12_Send_Cmd
 * 函数说明:向WIFI模块发送指令,并查看WIFI模块是否返回想要的数据
 * 型    参:
 * 【cmd=发送的AT指令	ack=想要的应答	waitms=等待应答的时间	cnt=等待应答多少次】
 * 返 回 值:1=得到了想要的应答		0=没有得到想要的应答
 * 备    注:无
*************************************************************/
char ESP12_Send_Cmd(char *cmd,char *ack,unsigned int waitms,unsigned char cnt)
{	
	UART4_send_String((unsigned char*)cmd);//向WIFI模块发送AT指令
	while(cnt--)
	{
		delay_1ms(waitms);
		//串口中断接收wifi应答
		if(U4RX_FLAG)
		{
			U4RX_FLAG = 0;
			U4RX_LEN = 0;
			if(strstr((char*)U4RX_BUFF,ack)!=NULL)//接收到想要的数据
			{
				return 1;
			}
			memset(U4RX_BUFF,0,sizeof(U4RX_BUFF));//清除接收缓存
		}
	}
	U4RX_FLAG = 0;//清除有串口数据标志
	U4RX_LEN = 0;//清除接收缓存数组长度
	return 0;
}

/************************************************************
 * 函数名称:ESP12_AP_Init
 * 函数说明:设置WIFI模块为AP模式,即开启热点让手机进行连接 
 * 型    参:无
 * 返 回 值:无
 * 备    注: IP=196.168.4.1 	端口=5000   如要修改WIFI名称与密码请修改以下参数
 * 				                      WIFI_SSID
 * 				                      WIFI_PASS
*************************************************************/
void ESP12_AP_Init(void)
{
	char buff[200];
	UART4_Init(115200);
	//发送AT	等待它返回OK  等待10ms  没有返回OK继续等待,一共等待3次 
	ESP12_Send_Cmd("AT\r\n","OK",10,3);
	
	//发送AT+CWMODE=2	等待它返回OK  等待30ms  没有返回OK则继续等待,一共等待3次 
	ESP12_Send_Cmd("AT+CWMODE=2\r\n","OK",30,3);   //配置WIFI AP模式

	sprintf(buff, "AT+CWSAP=\"%s\",\"%s\",11,4\r\n",WIFI_SSID, WIFI_PASS);             
	ESP12_Send_Cmd(buff,"OK",30,3);  //设置wifi账号与密码
	ESP12_Send_Cmd("AT+RST\r\n","ready",800,3); //重启
	ESP12_Send_Cmd("AT+CIPMUX=1\r\n","OK",50,3); //开启多个连接
	ESP12_Send_Cmd("AT+CIPSERVER=1,5000\r\n","OK",50,3); //开启服务器设置端口号
	
	printf("ESP12_AP_Init succeed!\r\n");
}

这里还判断了是否有手机连接,当有手机连接时,才能控制,这样大大增加了CPU的工作效率。

//DISCONNECTED  	   AP模式下 手机断开了WIFI连接
//DIST_STA_IP	   开启AP模式后,有手机连接
//0,CONNECT         设备0连接成功
//+IPD,0,4:刚刚     接收到设备0发来的4个字节数据:刚刚
char WIFI_Mode(void)
{
	char ret = 0;
	//没有手机连接的情况下
	if( ConnectFlag == 0 )
	{
		ret = 0;
		if( U4RX_FLAG == 1 )//接收到WIFI数据
		{
			U4RX_FLAG = 0;
			//是否有设备连接
			if( strstr((char*)U4RX_BUFF, "CONNECT") != NULL  )
			{
				printf("手机已连接\r\n");
				ConnectFlag = 1;
			}		
			//清除串口接收缓存
			Clear_U4RX_BUFF();
		}
	}
	// 有手机连接的情况下
	if( ConnectFlag == 1 ) 
	{
		ret = 1;
		if( U4RX_FLAG == 1 )//接收到WIFI数据
		{
			U4RX_FLAG = 0;
			//判断手机是否断开WIFI连接
			if( strstr((char*)U4RX_BUFF, "DISCONNECTED") != NULL  )
			{
				printf("断开连接\r\n");
				BEEP = 0;//蜂鸣器关
				Turn_Light_Con(SET, SET);//左右灯灭
				ConnectFlag = 0;
			}	
			//确定当前是按下什么键(确定当前手机发送过来什么数据)
			WIFI_control( Get_WIFIAPP_Data() );
			//清除串口接收缓存 等待下一次控制命令到来
			Clear_U4RX_BUFF();
		}
			
	}
	return ret; 
}

然后控制方面是和蓝牙一样的,就不贴出来了。

3、电机控制

电机控制方面,我为了连线方便,都是选择的离电机控制引脚最近的PWM控制引脚,分别使用到了

PA15--TIM1-CH0--PWML11		        JTDI		左轮
PB4 --TIM2-CH0--PWML12		        NJTRST
PB3 --TIM1-CH1--PWML21		        JTDO
PB6 --TIM3-CH0--PWML22

PC7 --TIM7-CH1 --PWMR11	                                 右轮
PC6 --TIM7-CH0 --PWMR12
PA7 --TIM13-CH0--PWMR21
PA6 --TIM12_CH0--PWMR22

浪费的定时器比较多,但是够用了。
大致代码,见我之前写的文章,链接:立创梁山派GD32F450ZGT6--定时器3-PWM-4通道输出
虽然文章只写了4个通道并且是同一个定时器,但是具体初始化的方法是一样的,也可以去附件下载我的源码。

4、语音播报

语音播报控制,只要配置出串口,再根据数据手册要求的命令帧格式发送数据,就能实现播报功能。
图片.png
图片.png
具体实现 命令帧封装发送代码


/************************************************************
 * 函数名称:SYN6288_Send_Cmd
 * 函数说明:向SYN6288发送命令
 * 型    参:
 * 【CmdType=命令字】		可使用参数有:
 *				-0x01	语音合成命令
 *				-0x31	设置波特率(默认9600)
 *				-0x02	停止合成命令
 *				-0x03	暂停合成命令
 *				-0x04	恢复合成命令
 *				-0x21	芯片状态查询命令
 *				-0x88	芯片进入低功耗模式
 * 【CmdPar=命令参数】	        可使用参数有:
 *	-字节高5位的十进制为0时,表示不加背景音乐
 *	-字节高5位的十进制为1~15时,表示所选背景音乐的编号
 *	-字节低3位的十进制为0~3,并且命令字为语音合成命令时,分别代表设置文本为BG2312格式、GBK格式、BIG5格式、UNICODE格式;
 *	-字节低3位的十进制为0~2,并且命令字为设置波特率时,分别代表设置波特率为9600、19200、38400;
 * 【text=播报的文本】
 
 * 返 回 值:0=发送成功  
 * 备    注: 
 * 接收到控制命令帧,芯片会向上位机发送1个字节的状态回传,上位机可根据这个回传来判断芯片目前的工作状态
 * 初始化成功回传 		 0X4A
 * 收到正确的命令帧回传		 0x41
 * 收到不能识别命令帧回传		 0x45
 * 芯片播音状态回传		 0x4E
 * 芯片空闲状态回传		 0x4F
*************************************************************/
unsigned char SYN6288_Send_Cmd(u8 CmdType, u8 CmdPar, u8 *text)
{
	unsigned char frame_header = 0XFD;        //帧头
	unsigned int Text_Len = strlen((const char*)text);//待发送文本的长度
	unsigned int Data_Len = Text_Len + 3;	//数据区长度;3=帧头、帧尾和异或校验
	unsigned char Xor_Check = 0;	        //异或校验存储
	unsigned char Send_Buff[210];		//待发送的命令帧,命令帧最大206个字节
	u8 i = 0;
	
	Send_Buff[0] = frame_header;		//帧头
	Send_Buff[1] = Data_Len>>8;	        //高位在前
	Send_Buff[2] = Data_Len&0x00ff;          //低位在前
	Send_Buff[3] = CmdType;			//命令字
	Send_Buff[4] = CmdPar;			//命令数据
	sprintf((char*)Send_Buff+5, "%s", text );
	//发送数据
	for( i = 0; i < Text_Len+5; i++ )
	{
		Xor_Check = Xor_Check ^ Send_Buff[i];//对每一个数据进行异或校验保存
		USART1_Send_Bit( Send_Buff[i] );//发送数据
	}
	USART1_Send_Bit( Xor_Check );//发送最后一位:异或校验数据
	return 0;
}

如果发现其播报的内容和你发送的内容不一致,请确保你发送命令的那个文件的编码格式为ANSI编码格式
使用.txt文本打开再另存为ANSI格式
图 片.png

5、追光模式

追光模式使用PID,随便采用了一个大概的参数。


float Kp = 800, Ki=0, Kd =5;//PID参数
float P = 0, I = 0, D = 0, PID_value = 0;
float error = 0, previous_error = 0;
static int initial_motor_speed = 1000;//基础速度
//PID计算
void calc_pid(void)
{
	P=error;	        //当前误差
	I=I+error;	        //误差累加
	D=error-previous_error;	//当前误差与之前误差的误差
	
	PID_value=(Kp*P)+(Ki*I)+(Kd*D);
	
	previous_error=error;//更新之前误差
}
//电机动作
void  motorsWrite(int speedL,int speedR)
{
	if(speedR > 0) 
	{
              Right_forward(speedR);//右边两个轮向前
	}
	else	
	{
              Right_Back(-speedR);//右边两个轮向后
	}
	
	if(speedL > 0)
	{
              Left_Back(speedL);//左边两个轮向前
	}
	else
	{
              Left_Back(-speedL);//左边两个轮向后	
	}
}

//数值限幅并控制
void motor_cortrol(void)
{
	//基础速度+PID值
	int left_motor_speed = initial_motor_speed+PID_value;
	int right_motor_speed = initial_motor_speed-PID_value;
	
	//左轮限幅
	if(left_motor_speed <= -8000)
	{
		left_motor_speed = -8000;
	}
	if(left_motor_speed >= 8000)
	{
		left_motor_speed = 8000;
	}
	//右轮限幅
	if(right_motor_speed <= -8000)
	{
		right_motor_speed = -8000;
	}
	if(right_motor_speed >= 8000)
	{
		right_motor_speed = 8000;
	}	
	//如果不是中间的光照度最高
	if( error != 0 )
	{
		//左轮因为调试过多,目前速度已经不一致,需要手动调整
		if( left_motor_speed < 0 )
		{
			left_motor_speed  =  left_motor_speed - 2000;
		}
		else
		{
			left_motor_speed  =  left_motor_speed + 2000;
		}
		motorsWrite(left_motor_speed,right_motor_speed);
	}
	else//中间光照度最高,则停车
	{
		motorsWrite(0,0);
	}
}      

//误差获取
void error_estimate(void)
{
	unsigned int left   =  Get_Liium_Val(GM_LEFT);//读取左边光敏滤波后的ADC值
	unsigned int middle = Get_Liium_Val(GM_MIDDLE);//读取中间光敏滤波后的ADC值
	unsigned int right  = Get_Liium_Val(GM_RIGHT);//读取右边光敏滤波后的ADC值
	//设置误差
	if( (left > middle) && (left > right) )//左边最亮
	{
		error = -5;
	}
	if( (middle > left) && (middle > right) )//中间最亮
	{
		error = 0;
	}	
	if( (right > left) && (right > middle) )////右边最亮
	{
		error = 5;
	}		
}
//追光模式
void follow_light(void)
{
	//获取误差
	error_estimate();
	//计算PID值
	calc_pid();
	//控制电机
	motor_cortrol();
}

设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

附件

序号文件名称下载次数
1
蓝牙资料及APP.zip
17
2
WIFI资料及APP.zip
15
3
SYN6288数据手册.pdf
17
4
智能车整体展示.mp4
74
5
小车源码.zip
170
克隆工程
添加到专辑
0
0
分享
侵权投诉

工程成员

评论

全部评论(1)
按时间排序|按热度排序
粉丝0|获赞0
相关工程
暂无相关工程

底部导航