项目介绍
此次项目主要是实现 任务一:使用ESP32的WiFi和TTS功能,实现一个语音播报系统,通过联网实现网络天气获取,然后并进行播报
设计思路
整体实现 逻辑见上图
1.上电进入配网状态,通过手机的点灯app 或者微信的小程序进行wifi 配网
2.配网成功后,界面会更新到当前的时间
3.配置esp32s3 实现codec 配置,完成驱动开发
4.点击按键,触发获取天气,通过https 从网上获取到天气数据,
5.将4中的json数据进行解析,然后整理成想要播放的文字
6.通过esp 官网的tts 组件实现语音播报
硬件介绍
ESP32-S3-BOX AI语音开发套件是乐鑫打造的一个智能语音设备开发平台
ESP32-S3-BOX 既可以用于构建智能音箱,也可以赋能更多物联网设备实现人机语音交互。同时,它还集触摸屏控制、传感器、红外控制器和智能网关等多功能于一体,能够作为全屋设备的控制中枢,支持用户通过语音命令控制或触屏控制,轻松实现圈内智能联动。
ESP32-S3-BOX-Lite 是目前对应的 AIoT 应用开发板,搭载支持 AI 加速的 ESP32-S3 Wi-Fi + Bluetooth 5 (LE) SoC。为用户提供了一个基于语音助手、传感器、红外控制器和智能 Wi-Fi 网关等功能开发和控制智能家居设备的平台。开发板出厂支持离线语音交互功能,用户通过乐鑫丰富的 SDK 和解决方案,能够轻松构建在线和离线语音助手、智能语音设备、HMI 人机交互设备、控制面板、多协议网关等多样的应用。
支持特性:
- 双麦克风支持远场语音交互
- 高唤醒率的离线语音唤醒
- 高识别率的离线中英文命令词识别
- 可动态配置 200+ 中英文命令词
- 连续识别和唤醒打断
- 灵活可复用的 GUI 框架
- 端到端一站式接入云平台
- Pmod™ 兼容接口支持多种外设扩展
ESP32-S3-BOX-Lite 轻量级开发套件。它与 ESP32-S3-BOX 拥有类似的离、在线语音功能,取消了电容触摸面板和 Mute 按键,增加了 3 个由客户自定义的功能按键。
此次项目主要使用了 物理按键、屏幕、扬声器 等相关外设
软件流程图及各功能对应的主要代码片段及说明
此次项目的实现主要基于乐鑫的esp-box 和esp-skainet 两个软件库进行功能开发.实际是移植部分驱动到esp-skainet,个人感觉esp-skainet 的代码结构不如esp-box 结构层次分离的好,所以前期移植了 大量的esp-box代码到esp-skainet。注意esp-box注意只有
0.3.0支持 esp-box lite 其他版本不支持,此分支主要基于esp-box lite 相关外设进行初始化,方便进行 mic 扬声器 按键 codec 等相关外设进行控制,同样官网提供了多个例程便于快速上手、入门了解相关功能。
ESP_ERROR_CHECK(esp_board_init(AUDIO_HAL_16K_SAMPLES, 1, 16));
ESP_ERROR_CHECK(lv_port_init());
bsp_lcd_set_backlight(true);
初始化codec 及其他相关硬件配置
codec 配置为16bit 单通道 IIS格式,屏幕背光需要硬件的MOS 管使能,才有背光
esp-skainet 项目中是乐鑫智能语音助手方案,主要有中文文本语音转换,usb mic 录音、语音唤醒等,这里只是用了中文文本语音转换功能。
中文语音转换两种语料这里使用了esp_tts_voice_data_xiaoxin.dat 这个数据,代码编译时,需要指定dat 的存储位置,便于进行tts 相关的初始化
/*** 1. create esp tts handle ***/
// initial voice set from separate voice data partition
const esp_partition_t* part=esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");
if (part==NULL) {
printf("Couldn't find voice data partition!\n");
return 0;
} else {
printf("voice_data paration size:%d\n", part->size);
}
spi_flash_mmap_handle_t mmap;
void* voicedata;
err=esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, &voicedata, &mmap);
if (err != ESP_OK) {
printf("Couldn't map voice data partition!\n");
return 0;
}
voice=esp_tts_voice_set_init(&esp_tts_voice_template, (int16_t*)voicedata);
tts_handle=esp_tts_create(voice);
首先先虚招voice data 的数据位置,让后进行voice data 的map
然后初始化voice 语音播放的相关设置,创建语音播放的handle
实际播放时调用也比较简单
void play_tts(char*prompt1)
{
if (esp_tts_parse_chinese(tts_handle, prompt1)) {
playing=true;
int len[1]={0};
do {
short *pcm_data=esp_tts_stream_play(tts_handle, len, 1);
my_audio_play(pcm_data, len[0]*2, portMAX_DELAY);
//i2s_zero_dma_buffer(I2S_NUM_0);
} while(len[0]>0);
playing=false;
}
esp_tts_stream_reset(tts_handle);
}
esp_err_t bsp_audio_play(const int16_t* data, int length, TickType_t ticks_to_wait)
{
size_t bytes_write = 0;
esp_err_t ret = ESP_OK;
int out_length= length;
int audio_time = 1;
audio_time *= (16000 / s_play_sample_rate);
audio_time *= (2 / s_play_channel_format);
//printf("fs:%d playch%d\n",s_play_sample_rate,s_play_channel_format);
uint8_t *data_out_1 = NULL;
data_out_1 = malloc(length*2);
for (int i = 0; i < length /2; i++) {
data_out_1[4*i+0]=data[i]&0xff;
data_out_1[4*i+1]=(data[i]>>8)&0xff;
data_out_1[4*i+2]=data[i]&0xff;
data_out_1[4*i+3]=(data[i]>>8)&0xff;
}
if (data_out_1 != NULL) {
//i2s_zero_dma_buffer(I2S_NUM_0);
//vTaskDelay(pdMS_TO_TICKS(50));
ret = i2s_write(I2S_NUM_0, (const char*) data_out_1, length*2, &bytes_write, ticks_to_wait);
free(data_out_1);
//i2s_zero_dma_buffer(I2S_NUM_0);
//vTaskDelay(pdMS_TO_TICKS(20));
}
return ret;
}
wifi 配网使用乐鑫的smartconfig,注意需要开启NVS ,之前调试总会报错,后来查了好多资料才等位到,需要通过meunconfig 进行初始化设置。
wifi 配网完成后,自动进行sntp设置,同步更新显示界面的时钟设置(时分秒)
获取天气通过按键回调进行触发
bsp_btn_register_callback(BOARD_BTN_ID_ENTER,BUTTON_SINGLE_CLICK,weather_get_cb,NULL);
天气的获取通过https client 进行获取,api 使用和风的api
int data_read = esp_http_client_read_response(client, client_data, MAX_HTTP_OUTPUT_BUFFER);
if (data_read >= 0) {
ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
esp_http_client_get_content_length(client));
size_t out_len = 0;
和风获取的json 数据不能直接使用,需要使用gzip进行解码
char *gzip_out_buff = (char *)malloc(MAX_HTTP_OUTPUT_BUFFER * sizeof(char));
memset(gzip_out_buff, 0x0, MAX_HTTP_OUTPUT_BUFFER);
err=network_gzip_decompress(client_data,data_read,gzip_out_buff,&out_len,MAX_HTTP_OUTPUT_BUFFER);
if(err!= ESP_OK) {
ESP_LOGE(TAG, "gzip data decompression failed, code=%d\n",err);
}
memcpy(client_data,gzip_out_buff,out_len);
free(gzip_out_buff);
//printf("%s\n",&client_data[0]);
cJSON *pJsonRoot = cJSON_Parse(client_data);
if (pJsonRoot ==NULL)
{
return;
}
解码后就可获取到json 字符串,然后通过cjson 进行json 解码
功能展示及说明
联网后,通过界面进行时间同步设置,
点击中间的按键可以获取天气查询
对本活动的心得体会(包括意见或建议)
1.很高心能有机会参加此次活动,希望多举办各种形式的活动,从中得到技能提升
代码地址
https://gitee.com/xinshuwei/esp32s3_box_lite_feature