【立创开发板】基于梁山派的多功能语音播报车 - 嘉立创EDA开源硬件平台

编辑器版本 ×
标准版 Standard

1、简单易用,可快速上手

2、流畅支持300个器件或1000个焊盘以下的设计规模

3、支持简单的电路仿真

4、面向学生、老师、创客

专业版 professional

1、全新的交互和界面

2、流畅支持超过3w器件或10w焊盘的设计规模,支持面板和外壳设计

3、更严谨的设计约束,更规范的流程

4、面向企业、更专业的用户

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

  • 2.8k
  • 1
  • 7

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

开源协议: GPL 3.0

(未经作者授权,禁止转载)

创建时间: 2023-01-04 19:33:35
更新时间: 2024-01-23 19:49:57
描述
做为一个电子人,怎么能没有自己的小车?(doge) 本来想做一个平衡小车车,但是看到教程这么丰富,忍不住跟着一起做了一个飞法法的4轮车。(弟弟说不喜欢两轮,哭唧唧) # 项目介绍 ##### **该项目为立创开发板寒假训练营项目,跟着学习下来,一共掌握了:** >* 对常用电机驱动有一定了解,并自己画电路实现了功能; >* 掌握循迹电路原理,并实现了小车循迹功能; >* 掌握SR04超声波模块测距原理,并完成了测距功能,实现避障; >* 整个小车的电源部分,采用3节18650电池并联,并实现充电功能; >* 使用便宜又常用的0.96IIC接口的OLED屏进行显示,认识到一个单色GUI库,并移植成功显示比较好看的界面; >* 使用蓝牙模块HC05做无线控制,实现手机APP通过蓝牙控制小车; >* 使用WIFI模块ESP8266做局域网控制,实现手机APP通过WIFI控制小车; >* 使用2.4G模块NRF24L01做摇杆控制,设计了一个遥控杆,摇杆通过NRF控制小车; >* 使用3个光敏电阻,放在3个方向,实现追光模式(就是那一边比较亮,就往哪一个开) 还加了一个语音播报功能。在开源平台上看到,非常想实现这个功能。试着按照数据手册设计,结果一次就过了,可喜可贺。就是声音太生硬成本也高。 # 硬件实现 ##### 电源部分 为了电池能够稳固的定在小车上,我选择了贴片类型的电池盒,这个有点贵。。 ![图片.png](//image.lceda.cn/pullimage/ZBAldVflksrMxoThNC5EPrOIgxXckfl3FUTcLLPX.png) 如果可以,我建议是使用下面这个,这个也可以固定在板子上。但是它是插件,如果电路板很紧凑,一个通孔都没有位置放还是不要用了。 ![图片.png](//image.lceda.cn/pullimage/yqa7aVauQds9wySIVh5kfOFYqj2Wwz78uItKbNg2.png) **因为要用到5V和3.3V和电机的8V,并且是3.7V的电池供电。所以我的供电方式是有三种。 1、电池电压->升压->5V** ![图片.png](//image.lceda.cn/pullimage/n0RUL6xmg6oSyUlhQvKkYQfAoaoLLOqdB0x5BAEs.png) **2、电池电压->升压->8V** 我之前购买的电机是6V300转的,所以我为什么用8V供电?因为我算了一下的电阻分配,我24K电阻都没有用过多少,就搞了进去,实测确实是7.8V左右,并且电机也没有发生什么问题。 ![图片.png](//image.lceda.cn/pullimage/b1G6tu23TjCCmuXyC4KbAwpr2HLzOpXyk4iWQgji.png) ![图片.png](//image.lceda.cn/pullimage/RTsQ9cgAUOiRMw2NwUqFJL7YTjoLfXuIGSuyiJSQ.png) **3、5V -> 3.3V** 直接使用升压后的5V再降压到3.3V给一些模块供电。(这个方案我不太喜欢,元件太大了,但是我在学习硬件的时候,买了这个方案的物料很多) ![图片.png](//image.lceda.cn/pullimage/5yEktAZI0kVLbkGwf4gdtc63PS33jKqjeCw0GD3r.png) **4、电源开关** 小车肯定要有开关功能啊,是吧?本来开关有个长按开机电路的,但是想到如果搞长按开机,调试小车估计按键都给整坏,就放弃了长按开机的想法。 ![图片.png](//image.lceda.cn/pullimage/stCKYj72y8K3CZUumskLZPjW88FHjFLfct6BCEFi.png) **5、电池充电** 使用的是老生常谈的TC4056,通过TYPE-C充电。 ![图片.png](//image.lceda.cn/pullimage/qlacB2kdcmlECCELWQSUXMtu7EjVeteSBKLBkLqY.png) 电源部分完结!! ##### 控制部分 控制部分大多是使用的模块,有蓝牙控制,WIFI控制、NRF控制。还要控制屏幕,控制语音播报这些。 **1、电机控制** 使用的是DRV8833进行驱动,挺好用,就是4个电机需要8个PWM。那个VM引脚是电机供电引脚,建议加个大电容,防止电机偷电太多。 ![图片.png](//image.lceda.cn/pullimage/QNSusI2zpMVNPBcloAwKgZeaZBt81U5q7eFlc8PC.png) **2、WIFI、蓝牙和屏幕控制** 这个WIFI模块也是一个吃电大户,被它坑过一次,所以我单独给WiFi模块一个1117供电。屏幕的通信方式是IIC,我使用的是软件IIC方式,所以引脚就随便放啦。我还写了关于GD32F450如何移植0.96屏幕代码,见链接:[立创梁山派GD32F450ZGT6--移植4针0.96寸OLED显示屏](https://blog.csdn.net/qq_51930953/article/details/128484797) WIFI模块使用的是ESP8266,蓝牙模块使用的是HC05(蓝牙模块这里我忘记连接一个手机连接成功指示引脚了,该打)。 ![图片.png](//image.lceda.cn/pullimage/4Xs2MmvCPagaJXcNlTDR26UC5em4SCKRA78wzJRC.png) **3、NRF控制** NRF模块是采购的泽耀科技的NRF24L01模块,他家的模块资料比较丰富,我买的这个只要会SPI就可以移植了。 ![图片.png](//image.lceda.cn/pullimage/6lUevDK9Tjhi3zy58pwCT8CVKUHjw78H50dbYFmp.png) ![图片.png](//image.lceda.cn/pullimage/ECXp15wBBpQrPuW0so4g5uQzFDoPf48IxEkfzl40.png) **4、语音播报** 它是通过串口进行控制,比如发送一串字符串"嘉立创天长地久",通过特定的帧格式,它就会播报语音"嘉立创天长地久"。 这个画的比较乱,这里在VDD上都加了100nF和10uF,说是能够让音质好点,可能是我PCB布局有问题,声音能听懂,但是很沙哑。 ![图片.png](//image.lceda.cn/pullimage/9b9wzrPgXB9ysORdnE3ouWmkmJIOtlpQBTXSylMs.png) **5、其他控制** 蜂鸣器我模拟为汽车的喇叭; 左右转灯使用LED代替; 关于语音播报的电源门控,我的想法是,有人比较喜欢安静,所以搞了一个可以通过软件控制语音播报电路的电源,关了电源,它就不能播报啦。 ![图片.png](//image.lceda.cn/pullimage/tnzMJQKmDID77hLblSAx0ip3adufhH6qZU3TibTT.png) ##### 采集部分 采集部分,分别有温湿度采集、电量采集、光照度采集、超声波测距采集、5路循迹采集; **1、电量采集和温湿度采集** 电量采集是以前刚学硬件时,自己想的。就欧姆定律计算出两点的电压最高3.3V,对它进行采集换算等到实际电量。 后面发现很多大佬都是使用10K这样的多路分压读取对应比例的电量(我又是一个固步自封的例子,哭唧唧) 不过我这里已经完善了这个电量方面的代码,所以无所谓了。 温湿度方面,本来想使用SHT30这种小型高精度的温湿度模块,但是看到它的价格,选了又选,看了又看,最后买了DHT11(我真的穷疯了doge) 温湿度也吃过亏,我之前以为数据口可以通过内部电阻的上拉就可以,但是实际使用发现外部最好要加一个4.7K的上拉电阻,不然读出的数据不准,其在数据手册上也有说明。 ![图片.png](//image.lceda.cn/pullimage/IUW6h9H7CXPIcItCeazQ5lvgl0NyRR2KbYzAXhif.png) ![图片.png](//image.lceda.cn/pullimage/dBciRSVcbigZA3S9nq8QYQusE1pS9YEOHKb6Cg2f.png) **2、超声波与光敏采集** 光敏是想用作追光设计的,把3个光敏分别放在3个方向,哪一个方向比较亮就往哪一边跑(其实是想多实践一下PID)。 超声波使用的是常用的SR04模块,原理就不说啦,在百度上都很详细了。 ![图片.png](//image.lceda.cn/pullimage/MYRjWTUeLS1Si1EiEEea35LgIlAyjM8vGdi64hut.png) **3、循迹电路** 循迹是通过电压比较实现的高低电平变化,采集这些变化就知道当前是否走在特定的轨迹上了。 ![图片.png](//image.lceda.cn/pullimage/IeFXBENQApzxXAPGI5v3s7uAi9VdI27uks8XxH18.png) PCB方面我就不说了,谁教谁还不一定呢。。我只能说 我还有很大的进步空间,哈哈 # 软件实现 ##### 1、蓝牙控制 使用的是HC05蓝牙模块,使用之前需要对模块进行一下配置。(在附件有资料) 按住模块上的按键或EN脚拉高,此时灯是慢闪,HC-05进入AT命令模式,默认波特率是38400;此模式我们叫原始模式。原始模式下一直处于AT命令模式状态。记住!!每一条指令都要加上\r\n,不然是识别不到命令的,可以发送: AT 测试一下是否返回OK ![图片.png](//image.lceda.cn/pullimage/9Y13GBSXo48TbC6FH69SUt3z2tr4THzjK8iGK4Cm.png) 最主要的是设置模式为从机控制,即等待手机去连接我们蓝牙模块的蓝牙,主要由手机控制。**发送:AT+ROLE0** ![图片.png](//image.lceda.cn/pullimage/5sEdfexd9xbXlHrfFSRKCo7hxowLIRYj8jSMIekv.png) 我这里还修改了波特率,改为了115200, **发送:AT+UART=115200,0,0** ![图片.png](//image.lceda.cn/pullimage/XgEooNRugIePpjLlIRb7n3DTIXGN3YR8mq44ZFPD.png) 还可以修改蓝牙名称, 发送: **AT+NAME=智能车** ![图片.png](//image.lceda.cn/pullimage/w1WD3jEBKKap8827yv1XoHE2sLx3CddnuFa3cn20.png) 这里如果你发现你的手机APP连接不上你的蓝牙模块的话,应该是配对密码错误的问题。大多APP的蓝牙配对密码是1234, 所以发送:**AT+PSWD=1234** 也可以发送 **AT+PSWD?** 查询密码 ![图片.png](//image.lceda.cn/pullimage/lkgDGbLiBrbuiUvP4tIdG6N5svxqb6wOdPSy9ss5.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通道输出](https://blog.csdn.net/qq_51930953/article/details/127473463) 虽然文章只写了4个通道并且是同一个定时器,但是具体初始化的方法是一样的,也可以去附件下载我的源码。 ##### 4、语音播报 语音播报控制,只要配置出串口,再根据数据手册要求的命令帧格式发送数据,就能实现播报功能。 ![图片.png](//image.lceda.cn/pullimage/EjmOq5j5oKXM6m7TU9eCcUsLRnh24RNrWyabF3pd.png) ![图片.png](//image.lceda.cn/pullimage/ZSIS0ivzLVjiTD465fiignY4TvJIbb903wxj9H9a.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](//image.lceda.cn/pullimage/rrJWudDg9nHnIoNHPwOE6YO2gahyvxFhmLqLYqc9.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(); } ```
设计图
原理图
1 /
PCB
1 /
未生成预览图,请在编辑器重新保存一次
工程成员
侵权投诉
相关工程
换一批
加载中...
添加到专辑 ×

加载中...

温馨提示 ×

是否需要添加此工程到专辑?

温馨提示
动态内容涉嫌违规
内容:
  • 153 6159 2675

服务时间

周一至周五 9:00~18:00
  • 技术支持

support
  • 开源平台公众号

MP