tag 标签: MJPGstreamer

相关博文
  • 热度 16
    2015-2-28 09:46
    1604 次阅读|
    0 个评论
    导读 本设计主要研究基于WIFI网络的可视化无线遥控搬运机器人,利用WIFI网络高速传输实时视频图像采集,通过机器人安装的传感器实现数据采集。采用WIFI网络通讯使得控制端多样化,可用手机,电脑等具备WIFI功能的设备进行控制。此外,还可将机器人接入Internet实现更远距离的控制。本设计在S3C6410平台上移植了Linux操作系统用于接收命令并对硬件设备进行控制,其中移植了MJPGstreamer作为视频服务器,移植了BOA服务器作为WEB服务器。本文将从硬件设计,驱动程序编写,服务器移植,服务程序编写,Android应用程序编写,Web应用程序编写等方面来讲述本设计的功能实现。 功能框图 总体设计及硬件选型和电路部分: 可视化WIFI遥控搬运机器人(1):硬件部分 驱动程序编写,服务器移植,服务程序编写部分: 可视化WIFI遥控搬运机器人(2):服务器搭建 4 客户端程序设计 4.1 Android客户端设计 4.1.1 Android客户端软件流程图 图 4-1 Android应用程序流程图 如图4-1所示,Android端的应用程序采用多线程技术,其中一个子线程每60S向服务器发送一个获取电量的命令并根据收到的数据进行更新显示,另一个线程根据MJPEG协议来解析出图像数据并更新显示,主线程主要完成用户操控事件的监听,并根据用户的实际操控发送相应的命令给服务器并从服务器获得机器人的最新数据来实时更新。其命令的发送方式采用HTTP协议中的GET方法。 4.1.2 HTTP GET方法简介 GET方法是HTTP协议中定义的多种与服务器进行交互的方法之一,它一般用于获取/查询资源信息。该方法请求的数据会附在URL之后,并且提交的数据最多只能是1024字节,但是本设计中只需要传送命令字即可,因此采用GET方法来传送命令字与获取机器人数据信息。使用该方法来发送命令,服务器端的CGI程序可以在QUERY-STRING环境变量中非常方便的获取到客户端传送给服务器的数据,并且客户端应用程序可以在HttpResponse中获得服务器端返回的数据。 4.1.3 HTTP GET方法实现 Android应用中HTTP GET方法实现部分代码如下: public String doGet(String url){ //参数设置 ... //创建 HttpClient 的实例 HttpClient httpClient = new DefaultHttpClient(httpParams); // GET HttpGet httpGet = new HttpGet(url); try { HttpResponse response = httpClient.execute(httpGet); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ // 使用getEntity方法获得返回结果 return EntityUtils.toString(response.getEntity()); } ... } 4.1.4 Mjpeg协议介绍 Mjpeg即Motion JPEG。MJPEG将服务器端发送来的一张张JPG图像数据发送给客户端,客户端不断的接收图像数据并显示更新即形成了动态的图像。MJPEG在HTTP中mjpg的在http的mime type是"x-mixed-replace"。获取视频图像数据时,客户端首先发一个GET方法,如果服务器接收响应则会设置context type的boundary子属性来指明。然后服务器端开始发送图片数据,在数据头部会有图片类型以及大小信息,其中Content-Length字段指明图像数据的长度,Content-Type字段指明图像的类型其值为image/jpeg。当一帧图像数据发送完毕后,服务器端将会发送边界字符串来表示一帧图像发送结束。 4.1.5 Mjpeg解析图像数据流程图 图 4-2 Mjpeg解析图像流程图 4.1.6 Mjpeg解析图像数据代码 在Android客户端需要根据Mjpeg协议来编写代码实现图像数据的解析,其中部分代码如下: Socket server = new Socket(url.getHost(), url.getPort()); OutputStream os = server.getOutputStream(); InputStream is = server.getInputStream(); StringBuffer request = new StringBuffer(); request.append("GET " + url.getFile() + " HTTP/1.0\r\n"); request.append("Host: " + url.getHost() + "\r\n"); request.append("\r\n"); os.write(request.toString().getBytes(), 0, request.length());//请求返回File StreamSplit localStreamSplit = new StreamSplit(new DataInputStream(new BufferedInputStream(is))); Hashtable localHashtable = localStreamSplit.readHeaders();//获得文件的信息头 String str3 = (String)localHashtable.get("content-type");//获得content-type以后的数据 int n = str3.indexOf("boundary=");//定位边界字符串 Object localObject2 = "--"; if (n != -1){ localObject2 = str3.substring(n + 9);//指定到boundary子属性 str3 = str3.substring(0, n); if (!((String)localObject2).startsWith("--")) localObject2 = "--" + (String)localObject2;} if (str3.startsWith("multipart/x-mixed-replace")){//判断MIME类型 localStreamSplit.skipToBoundary((String)localObject2);//定位到图像数据部分 }do{ if (localObject2 != null){ localHashtable = localStreamSplit.readHeaders(); if (localStreamSplit.isAtStreamEnd()) break; str3 = (String)localHashtable.get("content-type"); if (str3 == null) throw new Exception("No part content type"); } if (str3.startsWith("multipart/x-mixed-replace")){ n = str3.indexOf("boundary="); localObject2 = str3.substring(n + 9);//获得 localStreamSplit.skipToBoundary((String)localObject2); }else{ byte[] localObject3 = localStreamSplit.readToBoundary((String)localObject2); if (localObject3.length == 0) break; Message message = Message.obtain(); message.arg1 = 0; message.obj = BitmapFactory.decodeByteArray(localObject3, 0, localObject3.length); messageHandler.sendMessage(message);//显示消息 } fps++; try{ Thread.sleep(10L); }catch (InterruptedException localInterruptedException){ } 【分页导航】 第1页: Android客户端设计 第2页: Web客户端设计 4.2 Web客户端设计 4.2.1 Web客户端程序流程图 如图4-3所示,WEB客户端采用AJAX技术,其功能模块大体上分为3个部分:第一部分主要是监测用户的操作并采用HTTP GET方法来发送控制命令,最后将服务器返回的信息更新显示。第二部分主要为120S定时发送获取电源电量值得命令,并将获得的数据更新显示。第三部分获取图像数据并显示。 图 4-3 WEB客户端流程图 4.2.2 AJAX技术简介 AJAX(Asynchronous Javascript + XML)即异步JavaScript和XML技术的简称,它可以实现网页异步更新。采用该方法来设计WEB应用,可以只对网页的部分内容进行更新,而不需要重新对整个页面进行加载。其工作原理如下图所示: 图 4-4 AJAX工作原理 4.2.3 图像数据显示实现 采用WEB浏览器来显示的时候只需要添加如下代码: img src="http://192.168.2.1:8080/?action=stream" style="width:640px; height:480px;"/ 4.2.4 利用AJAX技术实现命令发送与数据更新 XMLHttpRequest 是 AJAX 的最基础的部分,本设计中的部分代码如下: function SendCmd(cmd) { var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.open("GET","./car.cgi?"+cmd,true); xmlhttp.send(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 xmlhttp.status==200) { var rec=xmlhttp.responseText; if( rec.indexOf("PRE") == 0) { document.getElementById("Pressure").innerHTML="压力:"+rec.substr(4); } if( rec.indexOf("POW") == 0) { var get_power=parseFloat(rec.substr(4)); get_power=9.9*get_power/1024; if(power == 0) power=get_power; if(get_power=power power-get_power0.2) { power=get_power; if(power8.3) document.getElementById("Power").innerHTML="电量:100%"; else if(power8.2) ... } } } } } 5 结束语 本文从硬件选型,硬件电路设计,系统移植,驱动程序移植编写,服务器搭建,服务器程序编写,以及Android客户端和Web客户端应用程序编写方面进行了较为详细的介绍。通过自己的努力,完成了最低层的硬件设计到最上层软件开发,实现了本设计的基本功能。最终用户能够通过Android客户端和Web客户端对机器人进行夹持,运输,摆放动作的控制,并且能够实时地返回机器人采集到的图像数据和传感器数据。 由于本设计基于成本的考虑,并没有采用大功率高精度的硬件设备,所以只能作为一种功能演示以及技术可行性演示。在后续的工作中还可以提升硬件设备,调整应用程序来获得更好的使用价值以及更好的用户体验。 【分页导航】 第1页: Android客户端设计 第2页: Web客户端设计 可视化WIFI遥控搬运机器人(1):硬件部分 可视化WIFI遥控搬运机器人(2):服务器搭建
  • 热度 8
    2015-2-28 09:33
    1648 次阅读|
    0 个评论
    导读 本设计主要研究基于WIFI网络的可视化无线遥控搬运机器人,利用WIFI网络高速传输实时视频图像采集,通过机器人安装的传感器实现数据采集。采用WIFI网络通讯使得控制端多样化,可用手机,电脑等具备WIFI功能的设备进行控制。此外,还可将机器人接入Internet实现更远距离的控制。本设计在S3C6410平台上移植了Linux操作系统用于接收命令并对硬件设备进行控制,其中移植了MJPGstreamer作为视频服务器,移植了BOA服务器作为WEB服务器。本文将从硬件设计,驱动程序编写,服务器移植,服务程序编写,Android应用程序编写,Web应用程序编写等方面来讲述本设计的功能实现。 功能框图 总体设计及硬件选型和电路部分: 可视化WIFI遥控搬运机器人(1):硬件部分 3 服务器搭建 3.1 服务器端功能框图 图3-1 服务器端功能框图 3.2 Linux系统移植 核心板采用友善之臂公司提供的TINY6410,此核心板已提供Bootloader,Linux系统,文件系统。使用时只需要根据实际的需要裁减Linux系统即可,本设计采用的Linux内核版本为Linux2.6.38,编译平台为Ubuntu12.04,交叉编译器为arm-linux-gcc-4.5.1。 【分页导航】 第1页: Linux系统移植 第2页: 驱动编写与移植 第3页: AP热点搭建 第4页: 视频服务器搭建 第5页: BOA服务器搭建 第6页: 服务器端程序设计 3.3 驱动编写与移植 3.3.1 直流电机驱动 由于S3C6410只带有2路PWM输出,而夹持器部分需要两路PWM脉宽调制控制伺服舵机,因此直流电机部分采用定时器2来模拟PWM调制。设置定时器2每100ms进一次中断,在定时器中进行1~100计数,因此PWM周期为10S,并有100个脉宽比可调,满足直流电机调速控制。 3.3.2 伺服电机驱动 伺服电机需要采用脉宽调制,通过调节20ms周期内的占空比可以指定伺服电机的旋转角度,其对应关系如下表: 表3-1 伺服电机占空比与旋转角度的对应关系 由于舵机的控制要求较高,本设计采用S3C6410自带的PWM进行控制.。设置PWM0和PWM1的周期为20ms,通过调节PWM0和PWM1的占空比来控制伺服电机进行工作。 3.3.3 摄像头驱动 ZC301为免驱的UVC视频设备,为了实现视频的采集需要在编译内核时选择上V4L2支持。 3.3.4 USB WIFI 驱动 本设计中采用的这款USB无线网卡采用RTL8188芯片,为使该设备能够正常工作需要进行驱动程序移植。 ①从RTL官网获得RTL8188的最新驱动程序,本文采用的是RTL819xSU_usb_linux_v2.6.6.0.20120405.tar.gz。 ②在Ubuntu中利用命令tar -zxvf 将驱动包解压。 ③进入驱动目录并修改Makefile ④由于驱动默认移植平台是I386_PC,而我们需要将其移植到S3C平台上,故需要做如下修改: 说明目标平台: 将:CONFIG_PLATFORM_I386_PC = y 改为:CONFIG_PLATFORM_I386_PC = n 将:CONFIG_PLATFORM_ARM_S3C = n 改为:CONFIG_PLATFORM_ARM_S3C = y 指定交叉编译器以及内核路径信息: ifeq ($(CONFIG_PLATFORM_ARM_S3C), y) EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN ARCH := arm CROSS_COMPILE := /opt/FriendlyARM/toolschain/4.5.1/bin/arm-linux- KVER := 2.6.48_$(ARCH) KSRC := /root/tiny6410/linux-2.6.38 Endif ⑤执行Make命令得到8712u.ko即为所需驱动,将该文件移动到目标平台加载即完成了USB WIFI驱动程序的移植。 3.3.5 ADC驱动 电源电量以及FSR压力传感器数据测量需要ADC驱动的支持。由于系统中已含有该驱动,故只需要在编译内核时选择上即可。 【分页导航】 第1页: Linux系统移植 第2页: 驱动编写与移植 第3页: AP热点搭建 第4页: 视频服务器搭建 第5页: BOA服务器搭建 第6页: 服务器端程序设计 3.4 AP热点搭建 3.4.1 AP热点简介 AP是(Wireless) Access Point的缩写,即(无线)访问接入点。无线设备可以通过它来接入到无线网络。RTL8188支持AP热点模式,采用这种方式可以让机器人成为AP热点,然后用带WIFI功能的设备来进行连接。 3.4.2 Hostapd简介 Hostapd即Host Access Point,其是Linux系统中无线访问接入点的守护进程。它可以将无线网卡设置为AP模式,并且支持多种加密方式,提供了设备接入的身份验证。在实际的使用期间,我们需要对其配置文件进行相应的修改。本设计中采用Hostapd来结合RTL8188网卡完成AP热点的搭建。 3.4.3 DHCP简介 DHCP(Dynamic Host Configuration Protocol)是一种动态主机配置协议。它主要采用UDP协议来为接入到网络中的设备分配IP地址以及进行一些参数配置。本设计中通过配置其配置文件并启用该服务来为接入机器人的WIFI设备分配IP地址,有效的避免了多个设备接入时的地址冲突问题。 3.4.4 Hostapd移植 ①下载最新版的Hostapd源码,本文使用的是Hostapd-2.0。 ②将hostapd-2.0.tar.gz进行解压,并进入到hostapd目录 ③对目录下的.config做如下修改: 注释掉: CONFIG_DRIVER_HOSTAP=y CONFIG_DRIVER_WIRED=y CONFIG_DRIVER_MADWIFI=y 取消下面这项的注释: CONFIG_DRIVER_NL80211=y ④修改Makefile 指定交叉编译器: CC=arm-linux-gcc ⑤执行Make命令,编译得到hostapd及hostapd_cli ⑥将编译得到的可执行文件复制到目标平台,即完成了Hostapd的移植 ⑦按需要更改hostapd.config文件,本设计关键部分配置如下: interface=wlan0 ctrl_interface=/var/run/hostapd ssid=CarControl channel=6 wpa=2 wpa_passphrase=12345678 ... driver=rtl871xdrv beacon_int=100 hw_mode=g ieee80211n=1 wme_enabled=1 ht_capab= wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP max_num_sta=8 wpa_group_rekey=86400 ⑧hostapd -B hostapd.config 启动Hostapd服务 3.4.5 DHCP移植 Linux2.6.38内核中已含有DHCP支持,使用DHCP只需要修改DHCP配置文件udhcpd.conf,其中最关键部分如下: # The start and end of the IP lease block start 192.168.2.2 end 192.168.2.30 即修改了自动分配IP地址的范围,由于采用局域网,需要将IP地址设置为同一网段,机器人采用的IP地址为192.168.2.1,因此将IP地址分配范围作如上设置。启动hostapd后需要执行udhcpd命令启动DHCP服务,从而当WIFI设备接入机器人时能自动获取到IP地址。 【分页导航】 第1页: Linux系统移植 第2页: 驱动编写与移植 第3页: AP热点搭建 第4页: 视频服务器搭建 第5页: BOA服务器搭建 第6页: 服务器端程序设计 3.5 视频服务器搭建 3.5.1 V4L2简介 V4L2(即Video for linux 2)是Linux 内核中针对UVC免驱视频设备的编程框架,它提供了一系列通用的接口来实现Linux中对视频设备的访问,其编程模式如下: 图 3-2 V4L2编程模式 Linux2.6.38内核中自带了该驱动,在使用时只需要在编译内核时将V4L2选项勾选上即可。 3.5.2 LIBJPEG简介 Libjpeg是一个包含了JPEG图像的编码,解码等功能的开源库,其完全采用C语言来进行编写。 3.5.3 Mjpgstreamer简介 MJPGstreamer是主要运行在Linux系统上的一款运用多线程技术的轻量级视频服务器软件。它是一款采用C语言进行开发的开源软件,其代码简洁,注释清晰,组件功能明确,衔接清晰,可以移植到不同的计算机平台。整个程序主要以模块化的方法来进行构建,每个功能模块又被称为组件(plug-in),用户可以根据自己的需要来选择输入组件和输出组件。它可以实现从一个单一的输入组件获取到图像数据来通过多个输出组件将图像进行输出 。下图为Mjpgstreamer的组件: 图 3-3 MJPG-streamer组件 本设计选用input_uvc作为输入组件来使用V4L2从摄像头获取图像数据,经JPEG库对数据进行编码之后,通过选用output_http作为输出组件来输出图像数据。output_http组件实现了一个符合HTTP1.0标准的web服务器,用户可以使用HTTP协议获取视频信息。 3.5.4 libjpeg移植 移植libjpeg库主要是用于Mjpgstreamer采集数据时压缩编码,移植步骤如下: ①下载libjpeg源码,本文采用jpeg-9a。 ②将jpeg-9a.tar.gz解压,并进入源码根目录。 ③执行如下命令配置编译,生成编译时所需要的Makefile文件。 ./configure --prefix=/root/h264/app/jpeg --exec-prefix=/root/h264/app/jpeg --enable-shared --enable-static 命令中prefix是最后安装时库存放的目录,shared是编译成动态库,static是编译成静态库。 ④修改Makefile文件,指定编译时所需要的交叉编译工具和环境: CC = arm-linux-gcc -std=gnu99 AR = arm-linux-ar CPP = arm-linux-gcc -std=gnu99 -E ⑤执行make命令编译代码 ⑥执行make install命令产生libjpeg库,存放于/root/h264/app/jpeg目录下。 ⑦将libjpeg库移动到目标平台,完成libjpeg移植。 3.5.5 Mjpgstreamer移植 MJPGstreamer作为本设计中的视频采集服务器,其移植过程如下: ①下载Mjpgstreamer源代码,本设计采用mjpg-streamer-r63.tar.gz。 ②解压mjpg-streamer-r63.tar.gz,并进入代码根目录。 ③修改plugins/input_uvc/Makefile: 指定交叉编译器: CC = arm-linux-gcc 指定libjpeg库: input_uvc.so: $(OTHER_HEADERS) input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo $(CC) $(CFLAGS) -ljpeg -L/root/h264/app/jpeglib/lib -o $@ input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo ④修改主目录以及plugins目录下所有子目录的Makefile,指定交叉编译器: CC = arm-linux-gcc ⑤执行make命令,生成可执行文件mjpg_streamer。 ⑥将源码目录中的start.sh和目录www拷贝到目标平台完成Mjpgsteramer移植。 ⑦执行如下命令可启用Mjpgstreamer服务: ./mjpg_streamer -i "./input_uvc.so -r 320x240 -f 25 " -o "./output_http.so -w www" 命令中指定输入组件为input_uvc,并且配置采集分辨率为320*240,帧数为25fps。指定输入组件为output_http,并且http服务器目录为www。 【分页导航】 第1页: Linux系统移植 第2页: 驱动编写与移植 第3页: AP热点搭建 第4页: 视频服务器搭建 第5页: BOA服务器搭建 第6页: 服务器端程序设计 3.6 BOA服务器搭建 3.6.1 BOA服务器简介 由于Mjpgstreamer服务器只能传输视频信息,而本设计需要接收客户端的控制命令并且得返回机器人的传感器数据。因此得移植支持CGI应用脚本的服务器。BOA服务器是一个可运行在unix或linux下的非常小巧的单任务Web服务器,并且支持CGI脚本,广泛应用于嵌入式领域 。本设计通过编写CGI脚本来完成服务器与客户端的数据交换。 3.6.2 BOA服务器移植 BOA服务器的移植需要以下步骤: ①下载BOA服务器源码,本文采用boa-0.94.13.tar.gz。 ②解压boa-0.94.13.tar.gz,并进入到源码根目录。 ③执行命令./configure生成Makefile文件。 ④修改Makefile文件,指定编译时所需要的交叉编译器: CC=gcc改成CC = arm-linux-gcc CPP = gcc –E改成CPP = arm-linux-gcc –E ⑤执行make命令生成boa可自行文件 ⑥将boa以及boa.conf移动到目标平台,即可完成BOA服务器移植。 ⑦为了适应本设计的需求,得修改boa.conf文件来配置boa服务器。本设计作出如下修改: Port 80 User root Group root ErrorLog /dev/console AccessLog /dev/null ServerName CarControl DocumentRoot /www DirectoryIndex index.html KeepAliveMax 1000 KeepAliveTimeout 10 MimeTypes /etc/mime.types DefaultType text/plain CGIPath /bin AddType application/x-httpd-cgi cgi 此配置设置了服务器的端口号,权限,服务器目录连接数等参数。 【分页导航】 第1页: Linux系统移植 第2页: 驱动编写与移植 第3页: AP热点搭建 第4页: 视频服务器搭建 第5页: BOA服务器搭建 第6页: 服务器端程序设计 3.7 服务器端程序设计 3.7.1 CGI脚本简介 CGI即公共网关接口(Common GatewayInterface)它是一种WWW技术。CGI实质是运行在WEB服务器上面为客户端HTML页面提供接口的一个脚本程序。它可以通过标准输入(STDIN)来从WEB服务器获得数据,经处理之后可以通过标准输出(STDOUT)来将数据返回给WEB服务器,从而实现对客户端数据的接收处理。本设计采用这种方式实现机器人控制命令的接收,以及返回机器人传感器数据信息。CGI程序应用原理如下图所示: 图 3-4 CGI程序应用原理 3.7.2 命名管道简介 命名管道是一种实现无关进程间通信的通信机制(IPC)。其本质上为一个文件,因此通讯更加稳定。命名管道遵循与先进先出原则,并且是半双工的,数据只能单向传输,若要实现双向传输就得使用两个管道。命名管道含有读端和写端,并且支持阻塞读。本设计中利用命名管道的特性,可以实现CGI程序与命令服务程序之间的数据交换。 3.7.3 控制命令设计 本设计控制命令简单,因此客户端与服务器间数据通讯主要采用HTTP GET方法,服务器CGI应用程序可以在环境变量QUERY_STRING中获取字符串形式的控制命令。本设计中采用“标志+参数”的方式设置控制命令,单个命令字的总长度为5字节,具体如下: 直流电机控制指令: L0000~0200 R0000~0200 其中L,R分别代表左和右,将此命令参数减去100,负数为后退,0为停止,正数为前进。其绝对值越大速度越快。 伺服电机控制命令: C0250~1250 S0250~1250 其中C,S分别代表夹持和旋转命令,参数250~1250代表脉冲宽度用以调整伺服电机旋转位置(0°~180°)。 获取电量命令: POWER 当CGI接收到此命令时将会把电源的电压值返回给客户端。 数据返回格式如下: POW:0~1023 PRE:0~1023 其中POW,PRE分别代表电量,压力,参数0~1023为从ADC中采集到的数据。 3.7.4 CGI程序流程图 CGI程序主要负责从客户端获得命令字然后通过命名管道将控制命令发送给服务程序进行处理,并且调用驱动程序读取机器人传感器数据信息返回给客户端。CGI程序流程图如下: 图 3-5 CGI程序流程图 如图3-5所示,本设计的CGI脚步先判断客户端的命令是否为索取电压值得命令,如果是的话就读取电源电压数据并将数据返回,否则就将命令字写入到命名管道供服务程序来进行读取,并且读取压力传感器的数据将其返回给客户端。 3.7.5 CGI程序编写 CGI脚本的部分代码如下: int main() { ... buff = getenv("QUERY_STRING");//获得指令 sscanf(buff, "%s", cmd); ... /*读取电压值,并返回给客户端*/ if(strcmp(cmd,"POWER")==0) {adc_fd=open("/dev/adc",0);//打开ADC驱动 if(adc_fd0) fprintf(stdout, "open adc_device faile\n"); else {if(ioctl(adc_fd,ADC_SET_CHANNEL,0) 0) fprintf(stdout, "ioctl adc_device faile\n"); else{len = read(adc_fd, adc, 4);//读取ADC if (len 0) {adc = '\0'; fprintf(stdout, "POW:%s",adc);//将电压值返回 } } close(adc_fd); } } else { cmd_fd=open(FIFO_CMD,O_WRONLY|O_NONBLOCK,0);//与服务程序通过命名管道通讯 /* 向管道写入数据 */ if((nwrite=write(cmd_fd,cmd,11))==-1) fprintf(stdout, "write cmd faile\n"); close(cmd_fd); /*读取压力值,并返回给客户端*/ adc_fd=open("/dev/adc",0);//打开ADC驱动 if(adc_fd0) fprintf(stdout, "open adc_device faile\n"); else { if(ioctl(adc_fd,ADC_SET_CHANNEL,1) 0) fprintf(stdout, "ioctl adc_device faile\n"); else { len = read(adc_fd, adc, 4);//读取ADC if (len 0) { adc = '\0'; fprintf(stdout, "PRE:%s",adc);//返回压力值 } } close(adc_fd); } } return 0; } 3.7.6 服务程序流程图 服务程序主要完成机器人初始化,读取电量值并将电量值通过LED来进行提示,读取命名管道获得命令字并将其解析执行。主要的流程图如下: 图 3-6 服务程序流程图 如图3-6所示,本设计中的服务程序采用多进程程序设计方式,其子进程每60S采集一次电源电量信息并更新电量指示灯显示,主进程采用阻塞读的方式读取命名管道来等待客户端发送命令,获得命令之后对命令进行解析并调用驱动程序来执行相应的命令,从而实现对机器人的控制。 3.7.7 服务程序编写 服务程序部分代码如下: /* 创建子进程,用于每60S获取电源电压值 */ if(fork()==0) { while(1) { if(ioctl(adc_fd,ADC_SET_CHANNEL,0) 0) {perror("ioctl ADC device:"); exit(1); } char buffer ; int len = read(adc_fd, buffer, sizeof buffer -1);//读取ADC if (len 0) { buffer = '\0'; printf("POW VALUE:%s\n",buffer); getpower=(float)StrToInt(buffer); getpower=9.9*getpower/1024.0; if(power==0) power=getpower; if(getpower=power power-getpower0.2) { power=getpower; if(power8.1)//根据电量来用LED显示 Show(5); ... } } sleep(60);//1min } } /* 主进程,用于获取命令并处理 */ else{ while(1) { memset(buff,0,sizeof(buff)); cmd_fd=open(FIFO_CMD,O_RDONLY);//readonly 阻塞 if(cmd_fd==-1) { perror("open"); exit(1); } if((nbytes=read(cmd_fd,buff,sizeof(buff)))4)//读取FIFO_CMD管道 { buff ='\0'; //指令处理 receive_do(buff); } close(cmd_fd); } } 上述代码中receive_do函数主要负责解析命令,并进行处理。其代码如下: void receive_do(char buffer[]) { int c,i; int tmp=0; c = (int)(nbytes+1)/5; for(i=0;i 第1页: Linux系统移植 第2页: 驱动编写与移植 第3页: AP热点搭建 第4页: 视频服务器搭建 第5页: BOA服务器搭建 第6页: 服务器端程序设计 可视化WIFI遥控搬运机器人(1):硬件部分 可视化WIFI遥控搬运机器人(3):客户端设计
相关资源