ROS学习笔记-使用C++类用以编程(以机器人语音交互为例)
生活随笔
收集整理的這篇文章主要介紹了
ROS学习笔记-使用C++类用以编程(以机器人语音交互为例)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
voice_control_class.h 頭文件:
使用到的文本合成等函數(shù)以及相關(guān)數(shù)據(jù)結(jié)構(gòu),以及定義一個(gè)類,定義了類的成員變量和方法
#ifndef EXAMPLE_ROS_CLASS_H_ #define EXAMPLE_ROS_CLASS_H_#include <math.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <string> #include <vector>#include <ros/ros.h> #include <std_msgs/String.h> #include <std_msgs/Float32.h> #include <std_srvs/Trigger.h> #include <geometry_msgs/Twist.h>#include "robot_voice/qtts.h" #include "robot_voice/msp_cmn.h" #include "robot_voice/msp_errors.h"class voice_control_class { public:voice_control_class(ros::NodeHandle* nodehandle); private:ros::NodeHandle nh_; ros::Subscriber minimal_subscriber_; ros::ServiceServer minimal_service_;ros::Publisher minimal_publisher_;std_msgs::String::ConstPtr val_from_subscriber_; void initializeSubscribers(); void initializePublishers();void initializeServices();void subscriberCallback(const std_msgs::String::ConstPtr& msg); bool serviceCallback(std_srvs::TriggerRequest& request, std_srvs::TriggerResponse& response); }; /* 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; // = 下一個(gè)結(jié)構(gòu)體的大小 : 16short int format_tag; // = PCM : 1short int channels; // = 通道數(shù) : 1int samples_per_sec; // = 采樣率 : 8000 | 6000 | 11025 | 16000int avg_bytes_per_sec; // = 每秒字節(jié)數(shù) : samples_per_sec * bits_per_sample / 8short int block_align; // = 每采樣點(diǎn)字節(jié)數(shù) : wBitsPerSample / 8short int bits_per_sample; // = 量化比特?cái)?shù): 8 | 16char data[4]; // = "data";int data_size; // = 純數(shù)據(jù)長度 : FileSize - 44 } wave_pcm_hdr;/* 默認(rèn)wav音頻頭部數(shù)據(jù) */ 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 }; std::string to_string(int val) {char buf[20];sprintf(buf, "%d", val);return std::string(buf); }/* 文本合成 */ 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; //計(jì)算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文件頭數(shù)據(jù)的大小 */wav_hdr.size_8 += wav_hdr.data_size + (sizeof(wav_hdr) - 8);/* 將修正過的數(shù)據(jù)寫回文件頭部,音頻文件為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; }void toExit() {printf("按任意鍵退出 ...\n");getchar();MSPLogout(); //退出登錄 }#endifvoice_control_class.c 類的實(shí)現(xiàn):
包含了上述頭文件,在構(gòu)造函數(shù)中封裝必要的初始化代碼,以及編寫成員函數(shù),專注于實(shí)現(xiàn)語音控制相關(guān)的ROS控制
#include "voice_control_class.h"voice_control_class::voice_control_class(ros::NodeHandle* nodehandle):nh_(*nodehandle) { ROS_INFO("in class constructor of voice_control_class");initializeSubscribers(); initializePublishers();initializeServices();// val_to_remember_=0.0; }void voice_control_class::initializeSubscribers() {ROS_INFO("Initializing Subscribers");minimal_subscriber_ = nh_.subscribe("voiceWords", 1000, &voice_control_class::subscriberCallback,this); } void voice_control_class::initializeServices() {ROS_INFO("Initializing Services"); } void voice_control_class::initializePublishers() {ROS_INFO("Initializing Publishers");minimal_publisher_ = nh_.advertise<geometry_msgs::Twist>("/cmd_vel", 1, true); } void voice_control_class::subscriberCallback(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;geometry_msgs::Twist output_msg;output_msg.linear.x=0; output_msg.linear.y=0;output_msg.linear.z=0;output_msg.angular.x=0;output_msg.angular.y=0;output_msg.angular.z=0;double speed = 0.0; // 0m/s speed commanddouble yaw_rate = 0.0; //0.0 rad/sec yaw rate commandstd::string dataString = msg->data;if(dataString.find("你是誰") != std::string::npos || dataString.find("名字") != std::string::npos){char nameString[100] = "我是mobot機(jī)器人";text = nameString;std::cout<<text<<std::endl;}else if(dataString.find("前") != std::string::npos ){char eageString[100] = "前進(jìn)";text = eageString;std::cout<<text<<std::endl;speed = 1.0; yaw_rate = 0.0;} else if(dataString.find("后") != std::string::npos ){char eageString[100] = "后退";text = eageString;std::cout<<text<<std::endl;speed = -1.0; yaw_rate = 0.0;} else if(dataString.find("左") != std::string::npos ){char eageString[100] = "向左";text = eageString;std::cout<<text<<std::endl;speed = 1.0; yaw_rate = 0.33;} else if(dataString.find("右") != std::string::npos ){char eageString[100] = "向右";text = eageString;std::cout<<text<<std::endl;speed = 1.0; yaw_rate = -0.5; }else if(dataString.find("停") != std::string::npos ){char eageString[100] = "停止";text = eageString;std::cout<<text<<std::endl;speed = 0.0; yaw_rate = 0.0; }else if(dataString.find("時(shí)間") != std::string::npos){//獲取當(dāng)前時(shí)間struct tm *ptm; long ts; ts = time(NULL); ptm = localtime(&ts); std::string string = "現(xiàn)在時(shí)間" + to_string(ptm-> tm_hour) + "點(diǎn)" + to_string(ptm-> tm_min) + "分";char timeString[40] = {0};string.copy(timeString, sizeof(string), 0);text = timeString;std::cout<<text<<std::endl;}else{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");output_msg.linear.x=speed; output_msg.angular.z=yaw_rate;int i=10;while(i--){minimal_publisher_.publish(output_msg); usleep(5000); //防止頻繁占用CPU}}bool voice_control_class::serviceCallback(std_srvs::TriggerRequest& request, std_srvs::TriggerResponse& response) {ROS_INFO("service callback activated");response.success = true; // boring, but valid response inforesponse.message = "here is a response string";return true; }int main(int argc, char* argv[]) {int ret = MSP_SUCCESS;const char* login_params = "appid = 594a7b46, work_dir = .";ret = MSPLogin(NULL, NULL, login_params);if (MSP_SUCCESS != ret){printf("MSPLogin failed, error code: %d.\n", ret);toExit();}printf("\n###########################################################################\n");printf("## 語音合成(Text To Speech,TTS)技術(shù)能夠自動將任意文字實(shí)時(shí)轉(zhuǎn)換為連續(xù)的 ##\n");printf("## 自然語音,是一種能夠在任何時(shí)間、任何地點(diǎn),向任何人提供語音信息服務(wù)的 ##\n");printf("## 高效便捷手段,非常符合信息時(shí)代海量數(shù)據(jù)、動態(tài)更新和個(gè)性化查詢的需求。 ##\n");printf("###########################################################################\n\n");ros::init(argc, argv, "voiceControl"); //node nameros::NodeHandle nh;ROS_INFO("main: instantiating an object of type voiceControl");voice_control_class voice_control_class(&nh); ROS_INFO("main: going into spin; let the callbacks do all the work");ros::spin();exit:printf("按任意鍵退出 ...\n");getchar();MSPLogout(); //退出登錄return 0; }后記:
關(guān)于使用C++類用于ROS通信的編程方式帶來的好處就不細(xì)講了,具體可參照官方wiki:
http://wiki.ros.org/roscpp/Overview/Publishers and Subscribers
總結(jié)
以上是生活随笔為你收集整理的ROS学习笔记-使用C++类用以编程(以机器人语音交互为例)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转] c++的多态(一个接口,多种实现
- 下一篇: [转]使用gazebo中的buildin