導讀 本設計主要研究基于WIFI網(wǎng)絡(luò )的可視化無(wú)線(xiàn)遙控搬運機器人,利用WIFI網(wǎng)絡(luò )高速傳輸實(shí)時(shí)視頻圖像采集,通過(guò)機器人安裝的傳感器實(shí)現數據采集。采用WIFI網(wǎng)絡(luò )通訊使得控制端多樣化,可用手機,電腦等具備WIFI功能的設備進(jìn)行控制。此外,還可將機器人接入Internet實(shí)現更遠距離的控制。本設計在S3C6410平臺上移植了Linux操作系統用于接收命令并對硬件設備進(jìn)行控制,其中移植了MJPGstreamer作為視頻服務(wù)器,移植了BOA服務(wù)器作為WEB服務(wù)器。本文將從硬件設計,驅動(dòng)程序編寫(xiě),服務(wù)器移植,服務(wù)程序編寫(xiě),Android應用程序編寫(xiě),Web應用程序編寫(xiě)等方面來(lái)講述本設計的功能實(shí)現。 功能框圖 總體設計及硬件選型和電路部分:可視化WIFI遙控搬運機器人(1):硬件部分 3 服務(wù)器搭建 3.1 服務(wù)器端功能框圖 圖3-1 服務(wù)器端功能框圖 3.2 Linux系統移植 核心板采用友善之臂公司提供的TINY6410,此核心板已提供Bootloader,Linux系統,文件系統。使用時(shí)只需要根據實(shí)際的需要裁減Linux系統即可,本設計采用的Linux內核版本為L(cháng)inux2.6.38,編譯平臺為Ubuntu12.04,交叉編譯器為arm-linux-gcc-4.5.1。 3.3 驅動(dòng)編寫(xiě)與移植 3.3.1 直流電機驅動(dòng) 由于S3C6410只帶有2路PWM輸出,而夾持器部分需要兩路PWM脈寬調制控制伺服舵機,因此直流電機部分采用定時(shí)器2來(lái)模擬PWM調制。設置定時(shí)器2每100ms進(jìn)一次中斷,在定時(shí)器中進(jìn)行1~100計數,因此PWM周期為10S,并有100個(gè)脈寬比可調,滿(mǎn)足直流電機調速控制。 3.3.2 伺服電機驅動(dòng) 伺服電機需要采用脈寬調制,通過(guò)調節20ms周期內的占空比可以指定伺服電機的旋轉角度,其對應關(guān)系如下表: 表3-1 伺服電機占空比與旋轉角度的對應關(guān)系 由于舵機的控制要求較高,本設計采用S3C6410自帶的PWM進(jìn)行控制.。設置PWM0和PWM1的周期為20ms,通過(guò)調節PWM0和PWM1的占空比來(lái)控制伺服電機進(jìn)行工作。 3.3.3 攝像頭驅動(dòng) ZC301為免驅的UVC視頻設備,為了實(shí)現視頻的采集需要在編譯內核時(shí)選擇上V4L2支持。 3.3.4 USB WIFI 驅動(dòng) 本設計中采用的這款USB無(wú)線(xiàn)網(wǎng)卡采用RTL8188芯片,為使該設備能夠正常工作需要進(jìn)行驅動(dòng)程序移植。 ①從RTL官網(wǎng)獲得RTL8188的最新驅動(dòng)程序,本文采用的是RTL819xSU_usb_linux_v2.6.6.0.20120405.tar.gz。 ②在Ubuntu中利用命令tar -zxvf 將驅動(dòng)包解壓。 ③進(jìn)入驅動(dòng)目錄并修改Makefile ④由于驅動(dòng)默認移植平臺是I386_PC,而我們需要將其移植到S3C平臺上,故需要做如下修改: 說(shuō)明目標平臺: 將: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即為所需驅動(dòng),將該文件移動(dòng)到目標平臺加載即完成了USB WIFI驅動(dòng)程序的移植。 3.3.5 ADC驅動(dòng) 電源電量以及FSR壓力傳感器數據測量需要ADC驅動(dòng)的支持。由于系統中已含有該驅動(dòng),故只需要在編譯內核時(shí)選擇上即可。 3.4 AP熱點(diǎn)搭建 3.4.1 AP熱點(diǎn)簡(jiǎn)介 AP是(Wireless) Access Point的縮寫(xiě),即(無(wú)線(xiàn))訪(fǎng)問(wèn)接入點(diǎn)。無(wú)線(xiàn)設備可以通過(guò)它來(lái)接入到無(wú)線(xiàn)網(wǎng)絡(luò )。RTL8188支持AP熱點(diǎn)模式,采用這種方式可以讓機器人成為AP熱點(diǎn),然后用帶WIFI功能的設備來(lái)進(jìn)行連接。 3.4.2 Hostapd簡(jiǎn)介 Hostapd即Host Access Point,其是Linux系統中無(wú)線(xiàn)訪(fǎng)問(wèn)接入點(diǎn)的守護進(jìn)程。它可以將無(wú)線(xiàn)網(wǎng)卡設置為AP模式,并且支持多種加密方式,提供了設備接入的身份驗證。在實(shí)際的使用期間,我們需要對其配置文件進(jìn)行相應的修改。本設計中采用Hostapd來(lái)結合RTL8188網(wǎng)卡完成AP熱點(diǎn)的搭建。 3.4.3 DHCP簡(jiǎn)介 DHCP(Dynamic Host Configuration Protocol)是一種動(dòng)態(tài)主機配置協(xié)議。它主要采用UDP協(xié)議來(lái)為接入到網(wǎng)絡(luò )中的設備分配IP地址以及進(jìn)行一些參數配置。本設計中通過(guò)配置其配置文件并啟用該服務(wù)來(lái)為接入機器人的WIFI設備分配IP地址,有效的避免了多個(gè)設備接入時(shí)的地址沖突問(wèn)題。 3.4.4 Hostapd移植 ①下載最新版的Hostapd源碼,本文使用的是Hostapd-2.0。 ②將hostapd-2.0.tar.gz進(jìn)行解壓,并進(jìn)入到hostapd目錄 ③對目錄下的.config做如下修改: 注釋掉: CONFIG_DRIVER_HOSTAP=y CONFIG_DRIVER_WIRED=y CONFIG_DRIVER_MADWIFI=y 取消下面這項的注釋?zhuān)?br /> CONFIG_DRIVER_NL80211=y ④修改Makefile 指定交叉編譯器: CC=arm-linux-gcc ⑤執行Make命令,編譯得到hostapd及hostapd_cli ⑥將編譯得到的可執行文件復制到目標平臺,即完成了Hostapd的移植 ⑦按需要更改hostapd.config文件,本設計關(guān)鍵部分配置如下: 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=[SHORT-GI-20][SHORT-GI-40] wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP max_num_sta=8 wpa_group_rekey=86400 ⑧hostapd -B hostapd.config 啟動(dòng)Hostapd服務(wù) 3.4.5 DHCP移植 Linux2.6.38內核中已含有DHCP支持,使用DHCP只需要修改DHCP配置文件udhcpd.conf,其中最關(guān)鍵部分如下: # The start and end of the IP lease block start 192.168.2.2 end 192.168.2.30 即修改了自動(dòng)分配IP地址的范圍,由于采用局域網(wǎng),需要將IP地址設置為同一網(wǎng)段,機器人采用的IP地址為192.168.2.1,因此將IP地址分配范圍作如上設置。啟動(dòng)hostapd后需要執行udhcpd命令啟動(dòng)DHCP服務(wù),從而當WIFI設備接入機器人時(shí)能自動(dòng)獲取到IP地址。 3.5 視頻服務(wù)器搭建 3.5.1 V4L2簡(jiǎn)介 V4L2(即Video for linux 2)是Linux 內核中針對UVC免驅視頻設備的編程框架,它提供了一系列通用的接口來(lái)實(shí)現Linux中對視頻設備的訪(fǎng)問(wèn),其編程模式如下: 圖 3-2 V4L2編程模式 Linux2.6.38內核中自帶了該驅動(dòng),在使用時(shí)只需要在編譯內核時(shí)將V4L2選項勾選上即可。 3.5.2 LIBJPEG簡(jiǎn)介 Libjpeg是一個(gè)包含了JPEG圖像的編碼,解碼等功能的開(kāi)源庫,其完全采用C語(yǔ)言來(lái)進(jìn)行編寫(xiě)。 3.5.3 Mjpgstreamer簡(jiǎn)介 MJPGstreamer是主要運行在Linux系統上的一款運用多線(xiàn)程技術(shù)的輕量級視頻服務(wù)器軟件。它是一款采用C語(yǔ)言進(jìn)行開(kāi)發(fā)的開(kāi)源軟件,其代碼簡(jiǎn)潔,注釋清晰,組件功能明確,銜接清晰,可以移植到不同的計算機平臺。整個(gè)程序主要以模塊化的方法來(lái)進(jìn)行構建,每個(gè)功能模塊又被稱(chēng)為組件(plug-in),用戶(hù)可以根據自己的需要來(lái)選擇輸入組件和輸出組件。它可以實(shí)現從一個(gè)單一的輸入組件獲取到圖像數據來(lái)通過(guò)多個(gè)輸出組件將圖像進(jìn)行輸出[ ]。下圖為Mjpgstreamer的組件: 圖 3-3 MJPG-streamer組件 本設計選用input_uvc作為輸入組件來(lái)使用V4L2從攝像頭獲取圖像數據,經(jīng)JPEG庫對數據進(jìn)行編碼之后,通過(guò)選用output_http作為輸出組件來(lái)輸出圖像數據。output_http組件實(shí)現了一個(gè)符合HTTP1.0標準的web服務(wù)器,用戶(hù)可以使用HTTP協(xié)議獲取視頻信息。 3.5.4 libjpeg移植 移植libjpeg庫主要是用于Mjpgstreamer采集數據時(shí)壓縮編碼,移植步驟如下: ①下載libjpeg源碼,本文采用jpeg-9a。 ②將jpeg-9a.tar.gz解壓,并進(jìn)入源碼根目錄。 ③執行如下命令配置編譯,生成編譯時(shí)所需要的Makefile文件。 ./configure --prefix=/root/h264/app/jpeg --exec-prefix=/root/h264/app/jpeg --enable-shared --enable-static 命令中prefix是最后安裝時(shí)庫存放的目錄,shared是編譯成動(dòng)態(tài)庫,static是編譯成靜態(tài)庫。 ④修改Makefile文件,指定編譯時(shí)所需要的交叉編譯工具和環(huán)境: CC = arm-linux-gcc -std=gnu99 AR = arm-linux-ar CPP = arm-linux-gcc -std=gnu99 -E ⑤執行make命令編譯代碼 ⑥執行make install命令產(chǎn)生libjpeg庫,存放于/root/h264/app/jpeg目錄下。 ⑦將libjpeg庫移動(dòng)到目標平臺,完成libjpeg移植。 3.5.5 Mjpgstreamer移植 MJPGstreamer作為本設計中的視頻采集服務(wù)器,其移植過(guò)程如下: ①下載Mjpgstreamer源代碼,本設計采用mjpg-streamer-r63.tar.gz。 ②解壓mjpg-streamer-r63.tar.gz,并進(jìn)入代碼根目錄。 ③修改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服務(wù): ./mjpg_streamer -i "./input_uvc.so -r 320x240 -f 25 " -o "./output_http.so -w www" 命令中指定輸入組件為input_uvc,并且配置采集分辨率為320*240,幀數為25fps。指定輸入組件為output_http,并且http服務(wù)器目錄為www。 3.6 BOA服務(wù)器搭建 3.6.1 BOA服務(wù)器簡(jiǎn)介 由于Mjpgstreamer服務(wù)器只能傳輸視頻信息,而本設計需要接收客戶(hù)端的控制命令并且得返回機器人的傳感器數據。因此得移植支持CGI應用腳本的服務(wù)器。BOA服務(wù)器是一個(gè)可運行在unix或linux下的非常小巧的單任務(wù)Web服務(wù)器,并且支持CGI腳本,廣泛應用于嵌入式領(lǐng)域[ ]。本設計通過(guò)編寫(xiě)CGI腳本來(lái)完成服務(wù)器與客戶(hù)端的數據交換。 3.6.2 BOA服務(wù)器移植 BOA服務(wù)器的移植需要以下步驟: ①下載BOA服務(wù)器源碼,本文采用boa-0.94.13.tar.gz。 ②解壓boa-0.94.13.tar.gz,并進(jìn)入到源碼根目錄。 ③執行命令./configure生成Makefile文件。 ④修改Makefile文件,指定編譯時(shí)所需要的交叉編譯器: CC=gcc改成CC = arm-linux-gcc CPP = gcc –E改成CPP = arm-linux-gcc –E ⑤執行make命令生成boa可自行文件 ⑥將boa以及boa.conf移動(dòng)到目標平臺,即可完成BOA服務(wù)器移植。 ⑦為了適應本設計的需求,得修改boa.conf文件來(lái)配置boa服務(wù)器。本設計作出如下修改: 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 此配置設置了服務(wù)器的端口號,權限,服務(wù)器目錄連接數等參數。 3.7 服務(wù)器端程序設計 3.7.1 CGI腳本簡(jiǎn)介 CGI即公共網(wǎng)關(guān)接口(Common GatewayInterface)它是一種WWW技術(shù)。CGI實(shí)質(zhì)是運行在WEB服務(wù)器上面為客戶(hù)端HTML頁(yè)面提供接口的一個(gè)腳本程序。它可以通過(guò)標準輸入(STDIN)來(lái)從WEB服務(wù)器獲得數據,經(jīng)處理之后可以通過(guò)標準輸出(STDOUT)來(lái)將數據返回給WEB服務(wù)器,從而實(shí)現對客戶(hù)端數據的接收處理。本設計采用這種方式實(shí)現機器人控制命令的接收,以及返回機器人傳感器數據信息。CGI程序應用原理如下圖所示: 圖 3-4 CGI程序應用原理 3.7.2 命名管道簡(jiǎn)介 命名管道是一種實(shí)現無(wú)關(guān)進(jìn)程間通信的通信機制(IPC)。其本質(zhì)上為一個(gè)文件,因此通訊更加穩定。命名管道遵循與先進(jìn)先出原則,并且是半雙工的,數據只能單向傳輸,若要實(shí)現雙向傳輸就得使用兩個(gè)管道。命名管道含有讀端和寫(xiě)端,并且支持阻塞讀。本設計中利用命名管道的特性,可以實(shí)現CGI程序與命令服務(wù)程序之間的數據交換。 3.7.3 控制命令設計 本設計控制命令簡(jiǎn)單,因此客戶(hù)端與服務(wù)器間數據通訊主要采用HTTP GET方法,服務(wù)器CGI應用程序可以在環(huán)境變量QUERY_STRING中獲取字符串形式的控制命令。本設計中采用“標志+參數”的方式設置控制命令,單個(gè)命令字的總長(cháng)度為5字節,具體如下: 直流電機控制指令: L0000~0200 R0000~0200 其中L,R分別代表左和右,將此命令參數減去100,負數為后退,0為停止,正數為前進(jìn)。其絕對值越大速度越快。 伺服電機控制命令: C0250~1250 S0250~1250 其中C,S分別代表夾持和旋轉命令,參數250~1250代表脈沖寬度用以調整伺服電機旋轉位置(0°~180°)。 獲取電量命令: POWER 當CGI接收到此命令時(shí)將會(huì )把電源的電壓值返回給客戶(hù)端。 數據返回格式如下: POW:0~1023 PRE:0~1023 其中POW,PRE分別代表電量,壓力,參數0~1023為從ADC中采集到的數據。 3.7.4 CGI程序流程圖 CGI程序主要負責從客戶(hù)端獲得命令字然后通過(guò)命名管道將控制命令發(fā)送給服務(wù)程序進(jìn)行處理,并且調用驅動(dòng)程序讀取機器人傳感器數據信息返回給客戶(hù)端。CGI程序流程圖如下: 圖 3-5 CGI程序流程圖 如圖3-5所示,本設計的CGI腳步先判斷客戶(hù)端的命令是否為索取電壓值得命令,如果是的話(huà)就讀取電源電壓數據并將數據返回,否則就將命令字寫(xiě)入到命名管道供服務(wù)程序來(lái)進(jìn)行讀取,并且讀取壓力傳感器的數據將其返回給客戶(hù)端。 3.7.5 CGI程序編寫(xiě) CGI腳本的部分代碼如下: int main() { ... buff = getenv("QUERY_STRING");//獲得指令 sscanf(buff, "%s", cmd); ... /*讀取電壓值,并返回給客戶(hù)端*/ if(strcmp(cmd,"POWER")==0) {adc_fd=open("/dev/adc",0);//打開(kāi)ADC驅動(dòng) if(adc_fd 0) {adc[len] = '\0'; fprintf(stdout, "POW:%s",adc);//將電壓值返回 } } close(adc_fd); } } else { cmd_fd=open(FIFO_CMD,O_WRONLY|O_NONBLOCK,0);//與服務(wù)程序通過(guò)命名管道通訊 /* 向管道寫(xiě)入數據 */ if((nwrite=write(cmd_fd,cmd,11))==-1) fprintf(stdout, "write cmd faile\n"); close(cmd_fd); /*讀取壓力值,并返回給客戶(hù)端*/ adc_fd=open("/dev/adc",0);//打開(kāi)ADC驅動(dòng) if(adc_fd 0) { adc[len] = '\0'; fprintf(stdout, "PRE:%s",adc);//返回壓力值 } } close(adc_fd); } } return 0; } 3.7.6 服務(wù)程序流程圖 服務(wù)程序主要完成機器人初始化,讀取電量值并將電量值通過(guò)LED來(lái)進(jìn)行提示,讀取命名管道獲得命令字并將其解析執行。主要的流程圖如下: 圖 3-6 服務(wù)程序流程圖 如圖3-6所示,本設計中的服務(wù)程序采用多進(jìn)程程序設計方式,其子進(jìn)程每60S采集一次電源電量信息并更新電量指示燈顯示,主進(jìn)程采用阻塞讀的方式讀取命名管道來(lái)等待客戶(hù)端發(fā)送命令,獲得命令之后對命令進(jìn)行解析并調用驅動(dòng)程序來(lái)執行相應的命令,從而實(shí)現對機器人的控制。 3.7.7 服務(wù)程序編寫(xiě) 服務(wù)程序部分代碼如下: /* 創(chuàng )建子進(jìn)程,用于每60S獲取電源電壓值 */ if(fork()==0) { while(1) { if(ioctl(adc_fd,ADC_SET_CHANNEL,0) 0) { buffer[len-1] = '\0'; printf("POW VALUE:%s\n",buffer); getpower=(float)StrToInt(buffer); getpower=9.9*getpower/1024.0; if(power==0) power=getpower; if(getpower8.1)//根據電量來(lái)用LED顯示 Show(5); ... } } sleep(60);//1min } } /* 主進(jìn)程,用于獲取命令并處理 */ 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[nbytes]='\0'; //指令處理 receive_do(buff); } close(cmd_fd); } } 上述代碼中receive_do函數主要負責解析命令,并進(jìn)行處理。其代碼如下: void receive_do(char buffer[]) { int c,i; int tmp=0; c = (int)(nbytes+1)/5; for(i=0;i |