基于树莓派的语音机器人

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/telrob/article/details/80089684

      近年来语音识别发展迅速也带动了人工智能的发展。曾经渴望自己做一个机器人,但是无奈,心有余而力不足,经过多年的积累,小白的我也能用站着巨人的肩膀上玩下机器人了。

     准备工作:树莓派,音频模块,stm32单片机,百度语音识别接口,喇叭。

    整体思路:

                1. 由于树莓派没有ADC模块,所以这里借助于stm32的ADC模块来实现将语音信号转换成数字信号,然后通过串口传 输 到树莓派你中,树莓派你将数据组装成wave文件,便于语音识别。

                 2. 通过http协议将组装的语音文件上传到百度语音识别平台进行识别。文档说明(免费调用)

                 3. 根据识别结果做出相应的处理。

                4. 对于需要播放语音时,根据百度语音合成接口合成语音然后使用mplayer播放出来。mplayer安装参考 博客

   部分代码:

    将音频转换成wave文件

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <wiringPi.h>
#include <wiringSerial.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "listen.h"
//gcc -o uart uart.c -lwiringPi
typedef struct WAV_Format WAVHEADER;

#define MAX_LISTEN_SIZES  1024*70 //定义接收数据的大小
#define bty  460800//串口的波特率
struct listen*listenUart()
{
    int fd,file;
    char buff,buff2;
	struct listen*liste=(struct listen*)malloc(sizeof(struct listen));
	
    unsigned short size;
    unsigned short*music,temp=0;
    unsigned short max=0,min=0;
	char*result=NULL;//存储最后的返回值
    int index=0,i=0;
    char stop=1;
    WAVHEADER wavHead;
    music=(unsigned short*)malloc(MAX_LISTEN_SIZES*2);
	result=(char*)malloc(MAX_LISTEN_SIZES*2+sizeof(WAVHEADER));
    if(wiringPiSetup() < 0)return NULL;
    if((fd = serialOpen ("/dev/ttyAMA0",bty))<0)
    {
		return NULL;
        printf("serial err\n");
    }
    //file=open("abc.wav", O_RDWR|O_CREAT);
    printf("oepn success\n");
    //serialPrintf(fd,"Hello World!!!");
    
    //需要对音频信号作出处理,当大于或者阈值时开始统计,知道录制完成
    int countTotal=0;
    int countNumber= 1000;//统计个数
    int countMax=2860;//最大值
    int countMin=2840;//最小值
    int startCount=1;
    while(1)
    {
      if(index==MAX_LISTEN_SIZES)
      {
        break;
      }
        buff=serialGetchar(fd);
        buff2=serialGetchar(fd);
        if((buff2&0x0F0)!=0)
        {
          buff2=serialGetchar(fd);
        }
        else
        {
          size=buff2;
          size=size<<8;
          size=(size&0xFF00)|(buff&0xFF);
          music[index]=size;
          if(startCount==1)
          {
            countTotal=countTotal+size;
            if(index>=countNumber)
            {
              int temp=countTotal/(countNumber+1);
              if(temp>countMax||temp<countMin)
              {
                startCount=0;
                //开始录音
                printf(":::::%d\n",temp);
                index++;
              }
              else
              {
                printf("temp:%d\n",temp);
                index=0;
              }
              countTotal=0;
            }
            else
            {
              index++;
            }
          }
          else
          {
             index++;
          }
        }
    }
    serialClose(fd);
    printf("end\n");
    //对音频进行放大处理
    max=music[0];
    min=music[0];
    for(i=i;i<MAX_LISTEN_SIZES;i++){
      temp=music[i];
      if(temp>max)
      {
        max=temp;
      }
      if(temp<min)
      {
        min=temp;
      }
    }
    
    size=max-min;
    
    for(i=0;i<MAX_LISTEN_SIZES;i++)
    {
        music[i]=(unsigned short)((music[i]-min)*1.0*6000/size);
    }
    wavHead.ChunkID=0x46464952;   /* "RIFF" */  
    wavHead.ChunkSize=sizeof(wavHead)+MAX_LISTEN_SIZES*2 -8; /* 36 + Subchunk2Size */  
    wavHead.Format=0x45564157;    /* "WAVE" */  
    wavHead.Subchunk1ID=0x20746D66;   /* "fmt " */  
    wavHead.Subchunk1Size=0x10; /* 16 for PCM */  
    wavHead.AudioFormat=0x01;   /* PCM = 1*/  
    wavHead.NumChannels=0x01;   /* Mono = 1, Stereo = 2, etc. */  
    wavHead.SampleRate=0x3E80;    /* 8000, 44100, etc. */  
    wavHead.ByteRate=0x7D00;  /* = SampleRate * NumChannels * BitsPerSample/8 */  
    wavHead.BlockAlign=0x02;    /* = NumChannels * BitsPerSample/8 */     
    wavHead.BitsPerSample=0x10; /* 8bits, 16bits, etc. */  
    wavHead.Subchunk2ID=0x61746164;   /* "data" */  
    wavHead.Subchunk2Size=MAX_LISTEN_SIZES*2; /* data size */  
	//返回数据赋值
	memcpy(result,(char*)&wavHead,sizeof(WAVHEADER));
	memcpy(result+sizeof(WAVHEADER),(char*)music,MAX_LISTEN_SIZES*2);
	liste->length=sizeof(WAVHEADER)+MAX_LISTEN_SIZES*2;
	liste->data=result;
    return liste;
}

将音频识别成文字

#include "convertText.h"
static Buffer *listen_buff2=NULL;
size_t listen_getData2(void *ptr, size_t size, size_t nmemb, void *stream) 
{
    appendBuffer(listen_buff2,ptr,nmemb);
	return nmemb;
}
int listenText(char*result2)
{
  listen_buff2=initBuffer();
  struct listen*lsn=listenUart();
  char*base;
  int fileLength=lsn->length;
  int result=1;
  int baseSize=(lsn->length/3)*4+(lsn->length%3)*2+1;
  base=(char*)malloc(baseSize);
  base64_encode(lsn->data,lsn->length,base);
  //发送请求
  free(lsn->data);
  free(lsn);
  int code=initToken();
  if(code==1)
  {
	  char*token=getToken();
	   ///开始创建json字符串
	  cJSON * root = cJSON_CreateObject();
	  cJSON_AddItemToObject(root, "format", cJSON_CreateString("wav"));
	  cJSON_AddItemToObject(root, "rate", cJSON_CreateString("16000"));
	  cJSON_AddItemToObject(root, "channel", cJSON_CreateString("1"));
	  cJSON_AddItemToObject(root, "cuid", cJSON_CreateString("34-68-95-91-77-43"));
	  cJSON_AddItemToObject(root, "token", cJSON_CreateString(token));
	  cJSON_AddItemToObject(root, "dev_pid", cJSON_CreateString("1537"));
	  cJSON_AddItemToObject(root, "speech", cJSON_CreateString(base));
	  cJSON_AddItemToObject(root, "len", cJSON_CreateNumber(fileLength));
	  char*jsonParam=cJSON_PrintUnformatted(root);
      char*apiurl="http://vop.baidu.com/server_api";
      CURL* curl;
	  CURLcode res;
      // ptr = curl_easy_escape(NULL, (char *)a, asize);
      curl = curl_easy_init();
	  struct curl_slist* headers = NULL;
	  headers = curl_slist_append(headers, "Content-Type:application/json");
	  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	  curl_easy_setopt(curl, CURLOPT_URL, apiurl);
	  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);
      curl_easy_setopt(curl, CURLOPT_POST, 1);
      //http://vop.baidu.com/server_api
      //CURLOPT_POSTFIELDS,CURLOPT_POSTFIELDSIZE
      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonParam);
      curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(jsonParam));
	  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, listen_getData2);
	  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
	  res = curl_easy_perform(curl);
	 
	  curl_easy_cleanup(curl);
	  cJSON_Delete(root);
      curl_slist_free_all(headers);
	  free(token);
	  free(jsonParam);
	  if (res == CURLE_OK)
      {
		  char*chars;
		  char*tempresult=(char*)malloc(listen_buff2->length+1);
		  memcpy(tempresult,listen_buff2->buff,listen_buff2->length);
		  tempresult[listen_buff2->length]=0;
		  cJSON *json;
		  cJSON * item = NULL;
		  cJSON*errCode;
          json=cJSON_Parse(tempresult);
          item=cJSON_GetObjectItem(json, "result");
		  errCode=cJSON_GetObjectItem(json, "err_no");
		  if(errCode->valueint!=0)
		  {
			  return -3;
		  }
		  chars=cJSON_GetArrayItem(item,0)->valuestring;
		  strcpy(result2,chars);
		  free(tempresult);
		  cJSON_Delete(json);
		 return 0;
      }
	  else
	  {
		  return -3;
	  }

  }
  else
  {
    return -2;
  }
  return -1;
}

主程序

#include<stdio.h>   
#include<string.h>  
#include "convertText.h"
#include "mp3.h"
#include "led.h"
#include "say.h"

//gcc -o robot robot.o mp3.o Buffer.o base64.o token.o cJSON.o listen.o convertText.o led.o say.o -lcurl -lm -lwiringPi -lmad

void sayChina(char*china)
{
	int resp=initSay(china);
	printf("resp:%d\n",resp);
	if(resp==1)
	{
		int tte=playData("temp.mp3");
		printf("tte:%d\n",tte);
	}
}
int main()
{
	char text[100]={0};
	sayChina("你好,我是小志,有什么可以为你服务");
	while(1)
	{
		printf(";;;;;;;;");
		int code= listenText(text);
		if(code==0)
		{
			printf("result:%s\n",text);
			if(strstr(text,"播放音乐,")!=NULL||strstr(text,"打开音乐,")!=NULL)
			{
				sayChina("正在为你打开音乐");
				musicPlayFile("mu.mp3");
			}
			if(strstr(text,"打开灯,")!=NULL||strstr(text,"打开,")!=NULL)
			{
				sayChina("好的");
				printf("正在打开");
				ledOn();
			}
			if(strstr(text,"关闭灯,")!=NULL||strstr(text,"关闭,")!=NULL||strstr(text,"完毕,")!=NULL)
			{
				sayChina("好的");
				printf("正在关闭");
				ledOff();
			}
			if(strstr(text,"你叫什么")!=NULL||strstr(text,"你叫什么名字")!=NULL||strstr(text,"名字")!=NULL)
			{
				sayChina("我叫小志");
			}
			if(strstr(text,"今天天气咋样")!=NULL||strstr(text,"天气")!=NULL)
			{
				sayChina("外面在下雨,有点冷");
			}
			if(strstr(text,"中午好")!=NULL||strstr(text,"中午")!=NULL)
			{
				sayChina("好什么啊,我还没吃饭呢");
			}
			if(strstr(text,"你多大了")!=NULL||strstr(text,"今年几岁")!=NULL||strstr(text,"几岁")!=NULL)
			{
				sayChina("我才出生,还没满月");
			}
		}
		else
		{
			printf("error\n");
		}
	}
	return 0;
}
这里只是贴出来部分程序,所有代码请查看  https://gitee.com/telrobgit/robot 希望能和大家一起交流下心得,QQ:1140756409

猜你喜欢

转载自blog.csdn.net/telrob/article/details/80089684