赞
踩
本次项目是基于Linux环境的交叉编译arm-linux-gcc,在GEC6818arm开发板上运行,通过SOCKET编程,应用基于TCP/IP传输数据的HTTPS协议连接机器人API接口,根据用户输入的问题建立通信,返回数据,通过屏幕显示以及语音播报告知用户,实现聊天功能;通过语音识别或键盘输入选择功能:查询城市天气(API)、切换机器人动态表情(线程滚动)、看视频听音乐查看图片(Apache服务器在线查看)
[1 ] 显示机器人表情(jpg/bmp图像显示)动态
[ 2] 实现基本的聊天功能(在键盘输入问题,就会在开发板的LCD屏幕上显示对应回答信息)HTTP请求
[ 3] 可以根据用户的输入查询不同城市的天气并显示到LCD设备上 JSON数据处理
[ 4] 可以浏览服务器上的图片文件(Apache) 利用HTTP协议下载文件
[5 ] 可以播放网络服务器上的视频文件 mplayer和http协议
[ 6] 自行设计一些新的功能提供用户使用
开发环境:
Linux
开放工具:
arm-linux-gcc、Notepad++
其他工具:
mplayer开源多媒体库、jpeglib库、font库、Apache服务器、讯飞语音、ALSA库
编程实现:
通过开源代码编译器notepad++编写代码,利用arm-linux-gcc交叉编译,再通过LINUX平台的SSH服务器将编译生成的程序文件传输到开发板中,最后执行。
Mplayer开源多媒体库
MPlayer是一款开源的多媒体播放器,以GNU通用公共许可证发布。此款软件可在各主流作业系统使用,例如Linux和其他类Unix作业系统、微软的视窗系统及苹果电脑的Mac OS X系统。
jpeglib库
libjpeg是一个完全用C语言编写的库,包含了被广泛使用的JPEG解码、JPEG编码和其他的JPEG功能的实现。这个库由独立JPEG工作组维护。
font库
通过封装font字库,让开发者能够自定义画板和文字颜色及大小。具体运用代码如下:
struct LcdDevice *init_lcd(const char *device)//初始化LCd { //申请空间 struct LcdDevice* lcd = malloc(sizeof(struct LcdDevice)); if(lcd == NULL) { return NULL; } lcd->fd = open(device, O_RDWR);//1打开设备 if(lcd->fd < 0) { perror("open lcd fail"); free(lcd); return NULL; } lcd->mp = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd->fd,0);//映射 return lcd; } int show_date(char*name)//字库显示字符串 { struct LcdDevice* lcd = init_lcd("/dev/fb0"); //初始化Lcd font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf"); //打开字体 fontSetSize(f,40); //字体大小的设置 bitmap *bm = createBitmapWithInit(400,230,4,getColor(0,0,0,0)); 创建一个画板(点阵图),改变画板颜色 char buf[1024]; strcpy(buf,name); fontPrint(f,bm,0,0,buf,getColor(0,201,174,255),400);//将字体写到点阵图上 show_font_to_lcd(lcd->mp,190,135,bm);//把字体框输出到LCD屏幕上 fontUnload(f);//关闭字体,关闭画板 destroyBitmap(bm); }
Apache阿帕奇服务器
Apache音译为阿帕奇, 是全世界最受欢迎的web服务器,因其快速、可靠并且可通过简单的API扩充,能将Python\Perl等解释器部署在其上面等优势,受到广泛的关注与使用。
此次项目就运用阿帕奇服务器搭建一个WEB服务器,使开发板可以直接连接到WEB服务器下载或显示文件。
讯飞语音
此次项目使用的是科大讯飞识别库(包括了语音合成和识别),开发板通过ALSA库的搭建能够录制语音,通过UDP协议传输到Linux平台,平台再通过识别语音生成文字返还给开发板,从而达到识别的功能。语音播报同样也是通过UDP协议将需要播报的字符串传送至Linux,通过语音合成音频文件,保存到WEB服务器的音频目录下,开发板通过在线播放改音频达到语音播报的功能。
具体项目实例如下:
ALSA库
ALSA是Advanced Linux Sound Architecture,高级Linux声音架构的简称,它在Linux操作系统上提供了音频和MIDI(Musical Instrument Digital Interface,音乐设备数字化接口)的支持。在2.6系列内核中,ALSA已经成为默认的声音子系统,用来替换2.4系列内核中的OSS(Open Sound System,开放声音系统)。
此次项目运用的主要是录音功能。
基本
整体项目框架设计图如下:
实现思路:
1.当用户选择需要显示的GIF表情时,程序通过创建链表、遍历对应表情目录所有图片存进节点,再创建线程循环滚动图片(记得加延迟时间);
2.当需要切换表情或者选择其他功能的时候,程序会清空该表情的链表节点、结束线程,然后再重新存新的表情包进链表节点,重复步骤1…
具体效果和代码如下:
3.项目中添加了11种动态表情:wink、笑、哭、怒、喜欢、困、爱心、发呆、疑问、音乐
实体效果:
具体部分代码:
int main() { head = malloc(sizeof(struct double_list)); //gif表情头节点 head->next = head; head->prev = head; head->pic_name[200]=0; char http[1024]; char word[1024]; char buf[1024] = {0}; printf("\n"); show_pohoto("pingmu.bmp"); while(1) { printf("选择小白表情:wink、笑、哭、怒、喜欢、困、爱心、发呆、疑问 \n"); scanf("%s",num); if(strcmp(num,"wink") == 0)//显示wink表情 { if(i==0) { show_face(num,head);//显示表情 i=1; } if(i==1) { pthread_cancel(tid);//取消线程 delete_list(head);//删除所有节点 show_face(num,head);//显示表情 } } else if(strcmp(num,"笑") == 0)//显示笑表情 { if(i==0) { show_face(num,head);//显示表情 i=1; } if(i==1) { pthread_cancel(tid);//取消线程 delete_list(head);//删除所有节点 show_face(num,head);//显示表情 } } } int show_face(char *face,struct double_list *head)//遍历表情目录存进链表,再用线程滚动链表图片 { char buff[64]="/robot/"; strcat(buff,face); DIR *dir_p=opendir(buff);//打开图片目录 struct dirent *msg; while(msg=readdir(dir_p))//遍历目录内的文件 { if( strstr(msg->d_name,".JPG")!=NULL) { inser_list(head,msg->d_name);//将目录中的视频名字依次保存在节点中 } } show_list(head); usleep(400000); pthread_create(&tid,NULL,roll_wink,NULL); } void *roll_wink(void *arg)//线程滚动链表图片 { struct double_list *tmp=head; char buff[64]; while(1) { tmp=tmp->next; if(tmp==head) { tmp=tmp->next; } bzero(buff,sizeof(buff)); sprintf(buff,"/robot/%s/%s",num,tmp->pic_name); show_jpg(buff,190,135); usleep(300000); } }
实现思路
通过SOCKET编程,使用HTTP协议连接机器人API接口,输入用户问题,客户端处理完返还数据,实现双向传输;将返回的数据经过字符串的一系列处理,通过字库显示至屏幕
具体效果和代码如下:
实体效果:
部分代码:
//使用IPV4的协议,基于TCP int new_socket = socket(AF_INET, SOCK_STREAM, 0); //设置需要链接到的服务器IP地址信息 例如:百度服务器 14.215.177.38 端口8080 struct sockaddr_in sockaddr_i; sockaddr_i.sin_family = AF_INET; sockaddr_i.sin_port = htons(80); sockaddr_i.sin_addr.s_addr = inet_addr("47.107.120.234"); //链接服务器 int ret=connect(new_socket, (struct sockaddr *)&sockaddr_i, sizeof(sockaddr_i)); sprintf(http, "GET /api.php?key=free&appid=0&msg=%s HTTP/1.1\r\nHost:api.qingyunke.com\r\n\r\n", num); write(new_socket,http,strlen(http)); read(new_socket, buf, 1024); //-----------------------------字符串数据处理--------------------------------- char *handle=strstr(buf,"{"); char *handle2=strstr(handle,"content"); char *handle3=strstr(handle2,":"); char xiaobai[1024]="小白"; strcat(xiaobai,handle3); show_date(xiaobai);//显示小白的回答 make_wav(handle3); i=xiaobai_face(xiaobai,head);//判断小白回答是否产生表情 bzero(buf,1024);
实现思路:
通过SOCKET编程,使用HTTP协议连接天气API接口,输入查询天气的城市,客户端处理完返还数据,实现双向传输;将返回的数据经过JOSN数据处理提取所需要的信息,再通过字库显示至屏幕。
具体效果和代码如下:
实体效果:
部分代码:
int answer_weather()//回答城市的天气 { while(1) { printf("请输入你要查询的城市:广州、深圳、惠州、肇庆、东莞、梅州、湛江、珠海 或 退出\n"); scanf("%s",num); if(strcmp(num,"1") == 0)//语音识别 { speech_recognition(); } printf("date=%s\n",num); if(strcmp(num,"广州") == 0)//显示广州天气 { char city_id[64]="101280101"; show_weather(city_id); } else if(strcmp(num,"深圳") == 0)//显示深圳天气 { char city_id[64]="101280601"; show_weather(city_id); } //省略其他城市天气 else if(strcmp(num,"退出") == 0)//退出 { printf("\n"); show_pohoto("pingmu.bmp"); show_jpg("待机.JPG",190,135); break; } else { printf("没有找到 %s 的天气\n",num); } } } int show_weather(char *city_id)//显示城市天气情况 { //1.使用IPV4的协议,基于TCP int new_socket = socket(AF_INET, SOCK_STREAM, 0); //设置需要链接到的服务器IP地址信息 链接到自己的HTTP 服务器 struct sockaddr_in sockaddr_i; sockaddr_i.sin_family = AF_INET; sockaddr_i.sin_port = htons(80); sockaddr_i.sin_addr.s_addr = inet_addr("58.222.18.2"); //链接服务器 int ret=connect(new_socket, (struct sockaddr *)&sockaddr_i, sizeof(sockaddr_i)); char http[1024]; sprintf(http,"GET /api/weather/city/%s HTTP/1.1\r\nHost:t.weather.itboy.net\r\n\r\n",city_id); write(new_socket,http,strlen(http)); sleep(2); char buf[4096*2] = {0}; read(new_socket, buf, 4096*2); char *handle=strstr(buf,"{"); //把数据转换成 JSON 对象 cJSON *obj=cJSON_Parse(handle); char date[64];//日期 char city[64];//城市 char week[64];//星期 char weather[64];//天气 char low[64];//低温 char high[64];//高温 char notice[64];//建议 cJSON *new_obj=cJSON_GetObjectItem(obj,"cityInfo"); cJSON *value=cJSON_GetObjectItem(new_obj,"city"); strcpy(city,cJSON_Print(value)); cJSON *obj_1=cJSON_GetObjectItem(obj,"data"); cJSON *obj_arry=cJSON_GetObjectItem(obj_1,"forecast"); cJSON *obj_arry_0=cJSON_GetArrayItem(obj_arry,0); //日期 value=cJSON_GetObjectItem(obj_arry_0,"ymd"); strcpy(date,cJSON_Print(value)); //星期 value=cJSON_GetObjectItem(obj_arry_0,"week"); strcpy(week,cJSON_Print(value)); //天气 value=cJSON_GetObjectItem(obj_arry_0,"type"); strcpy(weather,cJSON_Print(value)); //低温 value=cJSON_GetObjectItem(obj_arry_0,"low"); strcpy(low,cJSON_Print(value)); //高温 value=cJSON_GetObjectItem(obj_arry_0,"high"); strcpy(high,cJSON_Print(value)); //建议 value=cJSON_GetObjectItem(obj_arry_0,"notice"); strcpy(notice,cJSON_Print(value)); char word_weather[256]; sprintf(word_weather,"日期:%s\n 城市:%s\n 星期:%s\n 天气:%s\n %s %s\n %s\n",date,city,week,weather,low,high,notice); show_date(word_weather);//字库显示 make_wav(word_weather);//语音播报 }
实现思路:
通过system指令直接连接Apache服务器上音乐目录下的相应歌曲(实现在线播放,再通过管道实现歌曲调节功能);通过线程滚动显示“音乐”GIF表情以及字库显示歌曲名字。
具体效果和代码如下:
实体效果:
部分代码:
int interweb_music(char *num)//音乐功能菜单 { char buff[128]; char buf[64]; int music_fd = open("/robot/pipe2",O_RDWR);//打开通信的管道文件 sprintf(buff,"mplayer -slave -quiet -input file=/robot/pipe2 http://192.168.8.72/music/%s.mp3 &",num);//将音乐指令拼接到BUFF中 system(buff); usleep(400000); system("echo volume 10 1 > /robot/pipe2"); //降低初始音量 music_name(num);//显示歌曲名字 strcpy(num,"音乐"); show_face(num,head);//显示音乐表情 while(1) { printf("请选择播放功能:1、暂停or播放 ; 2、放大音量 ; 3、降低音量 ; 4、退出播放\n"); scanf("%s",buf); if(strcmp(buf,"1") == 0)//暂停or播放 { write(music_fd,"pause\n",strlen("pause\n")); } else if(strcmp(buf,"2") == 0)//放大音量 { write(music_fd,"volume +20\n",strlen("volume +20\n")); } else if(strcmp(buf,"3") == 0)//降低音量 { write(music_fd,"volume -20\n",strlen("volume -20\n")); } else if(strcmp(buf,"4") == 0)//停止播放 { write(music_fd,"quit\n",strlen("quit\n"));//停止播放 pthread_cancel(tid); delete_list(head); return 1; } } }
实现思路:
http协议连接Apache服务器下的相应视频,下载至开发板,再通过Mplayer播放视频,实现调节功能。
具体效果和代码如下:
实体效果:
部分代码:
int interweb_video(char *movie)//下载并播放视频 { int new_socket = socket(AF_INET, SOCK_STREAM, 0); //设置需要链接到的服务器IP地址信息 链接到自己的HTTP 服务器 struct sockaddr_in sockaddr_i; sockaddr_i.sin_family = AF_INET; sockaddr_i.sin_port = htons(80); sockaddr_i.sin_addr.s_addr = inet_addr("192.168.8.72"); //链接服务器 int ret=connect(new_socket, (struct sockaddr *)&sockaddr_i, sizeof(sockaddr_i)); char http[1024]; sprintf(http,"GET /video/%s.avi HTTP/1.1\r\nHost:192.168.8.72\r\n\r\n",movie); write(new_socket,http,strlen(http)); //创建一个本地文件 int fd=open("my.avi",O_RDWR|O_CREAT,0777); int flag=0; //接收服务器的回发数据 while(1) { //读取服务器的数据 char buf[4096]={0}; int ret=read(new_socket,buf,4096); if(flag==0) { char *tmp=strstr(buf,"\r\n\r\n"); int len=tmp-buf+4; write(fd,buf+len,ret-len); flag=1; } else write(fd,buf,ret);//写入到本地文件中 } close(fd); pthread_cancel(tid3); usleep(100000); pid_t pid; pid =fork(); if(pid == 0) //子进程 { char buff[100];//接收拼接好的播放视频指令 printf("\n"); show_pohoto("shiping.bmp"); drw_sound(5); int fd = open("/robot/pipe1",O_RDWR);//打开通信的管道文件 dup2(fd,1);//重定向标准输出设备描述符 //=======刷新进度条======= pthread_t tid; pthread_create(&tid,NULL,func,NULL); pthread_detach(tid); //=======进行触摸屏操作======== pthread_t tid1; pthread_create(&tid1,NULL,finger,NULL); pthread_detach(tid1); //=============退出操作=========== pthread_t tid2; pthread_create(&tid2,NULL,video_exit,NULL); system("mplayer -slave -quiet -input file=/robot/pipe -geometry 0:0 -zoom -x 750 -y 410 /robot/my.avi"); exit(0); } wait(NULL); }
实现思路:
http协议连接Apache服务器下的相应照片下载至开发板,再通过映射显示BMP图片。
具体效果和代码如下:
实体效果:
部分代码:
int down_file(char *file_name,char *http)//下载显示图片 { //使用IPV4的协议,基于TCP int new_socket = socket(AF_INET, SOCK_STREAM, 0); //设置需要链接到的服务器IP地址信息 例如:百度服务器 14.215.177.38 端口8080 struct sockaddr_in sockaddr_i; sockaddr_i.sin_family = AF_INET; sockaddr_i.sin_port = htons(80); sockaddr_i.sin_addr.s_addr = inet_addr("192.168.8.72"); //链接服务器 int ret=connect(new_socket, (struct sockaddr *)&sockaddr_i, sizeof(struct sockaddr_in)); char host[64]; char url[512]; //字符串处理 char tmp_http[1024]={0}; strcpy(tmp_http,http); strcpy(url,strstr(strstr(tmp_http,"//")+2,"/")); //去掉HTTP头 strcpy(host,strtok(strstr(tmp_http,"//"),"/")); //发送HTTP 请求 char http_reques[1024]={0}; sprintf(http_reques,"GET %s HTTP/1.1\r\nHost:%s\r\n\r\n",url,host); write(new_socket,http_reques,strlen(http_reques)); //接收服务器返回的数据 char head[1024] = {0}; ret=read(new_socket,head,1024); //printf("head=%s\n",head); int file_size=0; //获取文件大小 sscanf(strstr(head,"Content-Length: "),"Content-Length: %d\r\n",&file_size); //printf("file_size=%d\n",file_size); //获取头数据的大小 unsigned int head_len = (unsigned int)((strstr(head,"\r\n\r\n")+4)-head); //printf("%d\n",head_len); //写入头数据后的数据 int file_fd=open(file_name,O_RDWR|O_CREAT|O_TRUNC,0777); file_size-=ret-head_len; write(file_fd,(strstr(head,"\r\n\r\n")+4),(ret-head_len)); char buf[4096]={0}; while(1) { bzero(buf,4096); ret=read(new_socket,buf,4096); write(file_fd,buf,ret); file_size-=ret; //计算读取的大小 if(file_size == 0) { printf("下载文件 %s 完毕\n",file_name); close(new_socket); //关闭通信 break; } } show_jpg("my.jpg",0,0);//显示图片 }
此次项目主要运用了网络编程中TCP/IP协议、UDP协议、HTTP协议、Apache服务器的使用、机器人和天气API接口以及科大讯飞语音识别、链表的使用、mplayer指令的选择、触摸屏的坐标处理、进/线程的创建与终止,对文件IO路径的认识。
主要难点在于机器人GIF表情的生成及切换(通过创建链表,节点存取,删除节点,线程滚动节点),天气JSON数据处理(需要对JSON数据处理有一定的了解,处理需要提取的字符串),语音识别和合成(利用UDP协议实现arm与语音识别、arm与语音合成)…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。