ROS学习笔记-ROS语音识别与语音输出[1]
生活随笔
收集整理的這篇文章主要介紹了
ROS学习笔记-ROS语音识别与语音输出[1]
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
說明:代碼部分是基于古月居前輩的例程,在此對胡老師表示感謝!!
語音識別功能框圖:
調用過程:
roscore rosrun robot_voice iat_publish rostopic pub /voiceWakeup std_msgs/String "data: '123'"代碼描述:
// 聲明Publisher和Subscriber // 訂閱喚醒語音識別的信號 ros::Subscriber wakeUpSub = n.subscribe("voiceWakeup", 1000, WakeUp); // 訂閱喚醒語音識別的信號 ros::Publisher voiceWordsPub = n.advertise<std_msgs::String>("voiceWords", 1000);訂閱話題后執行的回調函數:
void WakeUp(const std_msgs::String::ConstPtr& msg) {printf("waking up\r\n");usleep(700*1000);wakeupFlag=1; }main()函數框架
int main(int argc, char* argv[]) {// 初始化ROSros::init(argc, argv, "voiceRecognition");ros::NodeHandle n;ros::Rate loop_rate(10);// 聲明Publisher和Subscriber// 訂閱喚醒語音識別的信號ros::Subscriber wakeUpSub = n.subscribe("voiceWakeup", 1000, WakeUp); // 訂閱喚醒語音識別的信號 ros::Publisher voiceWordsPub = n.advertise<std_msgs::String>("voiceWords", 1000); ROS_INFO("Sleeping...");int count=0;int ret = MSP_SUCCESS;/* login params, please do keep the appid correct */const char* login_params = "appid = 594a7b46, work_dir = .";int aud_src = 0; /* from mic or file *//** See "iFlytek MSC Reference Manual"*/const char* session_begin_params ="sub = iat, domain = iat, language = zh_cn, ""accent = mandarin, sample_rate = 16000, ""result_type = plain, result_encoding = utf8";/* Login first. the 1st arg is username, the 2nd arg is password* just set them as NULL. the 3rd arg is login paramertes * */ret = MSPLogin(NULL, NULL, login_params);if (MSP_SUCCESS != ret) {printf("MSPLogin failed , Error code %d.\n",ret);goto exit; // login fail, exit the program}while(ros::ok()){// 語音識別喚醒 if(wakeupFlag){ROS_INFO("Wakeup...");printf("Demo recognizing the speech from microphone\n");printf("Speak in 8 seconds\n");demo_mic(session_begin_params);printf("8 sec passed\n");wakeupFlag=0;}// 語音識別完成if(resultFlag){resultFlag=0;std_msgs::String msg;msg.data = g_result;voiceWordsPub.publish(msg);}ros::spinOnce();loop_rate.sleep();count++;} exit:MSPLogout(); // Logout...return 0; }demo_mic()函數
/* demo recognize the audio from microphone */ static void demo_mic(const char* session_begin_params) {int errcode;int i = 0;struct speech_rec iat;struct speech_rec_notifier recnotifier = {on_result,on_speech_begin,on_speech_end};errcode = sr_init(&iat, session_begin_params, SR_MIC, &recnotifier);if (errcode) {printf("speech recognizer init failed\n");return;}errcode = sr_start_listening(&iat);if (errcode) {printf("start listen failed %d\n", errcode);}/* demo 8 seconds recording */while(i++ < 8)sleep(1); //停頓一秒鐘errcode = sr_stop_listening(&iat);if (errcode) {printf("stop listening failed %d\n", errcode);}sr_uninit(&iat); }關于 sleep() 函數,可以參考這篇:
https://blog.csdn.net/cxs5534/article/details/105759883
這里使用了自定義的Sleep()
c static void Sleep(size_t ms) { usleep(ms*1000); }
語音輸出:
源碼閱讀:
int main(int argc, char* argv[]) {int ret = MSP_SUCCESS;const char* login_params = "appid = 594a7b46, work_dir = .";//登錄參數,appid與msc庫綁定,請勿隨意改動/** rdn: 合成音頻數字發音方式* volume: 合成音頻的音量* pitch: 合成音頻的音調* speed: 合成音頻對應的語速* voice_name: 合成發音人* sample_rate: 合成音頻采樣率* text_encoding: 合成文本編碼格式**///const char* session_begin_params = "voice_name = xiaoyan, text_encoding = utf8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2";//const char* filename = "tts_sample.wav"; //合成的語音文件名稱//const char* text = "親愛的用戶,您好,這是一個語音合成示例,感謝您對科大訊飛語音技術的支持!科大訊飛是亞太地區最大的語音上市公司,股票代碼:002230"; //合成文本/* 用戶登錄 */ret = MSPLogin(NULL, NULL, login_params);//第一個參數是用戶名,第二個參數是密碼,第三個參數是登錄參數,用戶名和密碼可在http://www.xfyun.cn注冊獲取if (MSP_SUCCESS != ret){printf("MSPLogin failed, error code: %d.\n", ret);//goto exit ;//登錄失敗,退出登錄toExit();}printf("\n###########################################################################\n");printf("## 語音合成(Text To Speech,TTS)技術能夠自動將任意文字實時轉換為連續的 ##\n");printf("## 自然語音,是一種能夠在任何時間、任何地點,向任何人提供語音信息服務的 ##\n");printf("## 高效便捷手段,非常符合信息時代海量數據、動態更新和個性化查詢的需求。 ##\n");printf("###########################################################################\n\n");ros::init(argc,argv,"TextToSpeech");ros::NodeHandle n;ros::Subscriber sub =n.subscribe("voiceWords", 1000, voiceWordsCallback);ros::spin();exit:printf("按任意鍵退出 ...\n");getchar();MSPLogout(); //退出登錄return 0; }voiceWordsCallback()函數:
void voiceWordsCallback(const std_msgs::String::ConstPtr& msg) {char cmd[2000];const char* text;int ret = MSP_SUCCESS;const char* session_begin_params = "voice_name = xiaoyan, text_encoding = utf8, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2";const char* filename = "tts_sample.wav"; //合成的語音文件名稱std::cout<<"I heard :"<<msg->data.c_str()<<std::endl;text = msg->data.c_str(); /* 文本合成 */printf("開始合成 ...\n");ret = text_to_speech(text, filename, session_begin_params);if (MSP_SUCCESS != ret){printf("text_to_speech failed, error code: %d.\n", ret);}printf("合成完畢\n");//在終端調用輸出語音popen("play tts_sample.wav","r");sleep(1); }文本合成函數 text_to_speech()
/* 文本合成 */ int text_to_speech(const char* src_text, const char* des_path, const char* params) {int ret = -1;FILE* fp = NULL;const char* sessionID = NULL;unsigned int audio_len = 0;wave_pcm_hdr wav_hdr = default_wav_hdr;int synth_status = MSP_TTS_FLAG_STILL_HAVE_DATA;if (NULL == src_text || NULL == des_path){printf("params is error!\n");return ret;}fp = fopen(des_path, "wb");if (NULL == fp){printf("open %s error.\n", des_path);return ret;}/* 開始合成 */sessionID = QTTSSessionBegin(params, &ret);if (MSP_SUCCESS != ret){printf("QTTSSessionBegin failed, error code: %d.\n", ret);fclose(fp);return ret;}ret = QTTSTextPut(sessionID, src_text, (unsigned int)strlen(src_text), NULL);if (MSP_SUCCESS != ret){printf("QTTSTextPut failed, error code: %d.\n",ret);QTTSSessionEnd(sessionID, "TextPutError");fclose(fp);return ret;}printf("正在合成 ...\n");fwrite(&wav_hdr, sizeof(wav_hdr) ,1, fp); //添加wav音頻頭,使用采樣率為16000while (1) {/* 獲取合成音頻 */const void* data = QTTSAudioGet(sessionID, &audio_len, &synth_status, &ret);if (MSP_SUCCESS != ret)break;if (NULL != data){fwrite(data, audio_len, 1, fp);wav_hdr.data_size += audio_len; //計算data_size大小}if (MSP_TTS_FLAG_DATA_END == synth_status)break;printf(">");usleep(150*1000); //防止頻繁占用CPU}printf("\n");if (MSP_SUCCESS != ret){printf("QTTSAudioGet failed, error code: %d.\n",ret);QTTSSessionEnd(sessionID, "AudioGetError");fclose(fp);return ret;}/* 修正wav文件頭數據的大小 */wav_hdr.size_8 += wav_hdr.data_size + (sizeof(wav_hdr) - 8);/* 將修正過的數據寫回文件頭部,音頻文件為wav格式 */fseek(fp, 4, 0);fwrite(&wav_hdr.size_8,sizeof(wav_hdr.size_8), 1, fp); //寫入size_8的值fseek(fp, 40, 0); //將文件指針偏移到存儲data_size值的位置fwrite(&wav_hdr.data_size,sizeof(wav_hdr.data_size), 1, fp); //寫入data_size的值fclose(fp);fp = NULL;/* 合成完畢 */ret = QTTSSessionEnd(sessionID, "Normal");if (MSP_SUCCESS != ret){printf("QTTSSessionEnd failed, error code: %d.\n",ret);}return ret; }數據結構:
/* wav音頻頭部格式 */ typedef struct _wave_pcm_hdr {char riff[4]; // = "RIFF"int size_8; // = FileSize - 8char wave[4]; // = "WAVE"char fmt[4]; // = "fmt "int fmt_size; // = 下一個結構體的大小 : 16short int format_tag; // = PCM : 1short int channels; // = 通道數 : 1int samples_per_sec; // = 采樣率 : 8000 | 6000 | 11025 | 16000int avg_bytes_per_sec; // = 每秒字節數 : samples_per_sec * bits_per_sample / 8short int block_align; // = 每采樣點字節數 : wBitsPerSample / 8short int bits_per_sample; // = 量化比特數: 8 | 16char data[4]; // = "data";int data_size; // = 純數據長度 : FileSize - 44 } wave_pcm_hdr;/* 默認wav音頻頭部數據 */ wave_pcm_hdr default_wav_hdr = {{ 'R', 'I', 'F', 'F' },0,{'W', 'A', 'V', 'E'},{'f', 'm', 't', ' '},16,1,1,16000,32000,2,16,{'d', 'a', 't', 'a'},0 };總結
以上是生活随笔為你收集整理的ROS学习笔记-ROS语音识别与语音输出[1]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]C++中sleep()函数的使用
- 下一篇: [转]使用gazebo中的buildin