之前也用單片機作過WIFI小車,可是單片機沒有自帶WIFI,仍然須要用到小路由器做爲圖傳和控制信號傳輸。既然確定要用到路由器,那何不直接用路由器做爲主控呢,這樣就省掉了單片機。此次做爲主控的GL-inet迷你路由,64M內存,16M Flash,支持OPENWRT系統,自帶刷不死Uboot,Uart調試接口已焊好,另預留5個GPIO接口,能夠充分知足DIY愛好者的須要。5個GPIO製做WIFI小車勉強夠用。首先來一張完成圖。javascript
1、須要用到的材料
- Gl-inet路由器(有TPLink WR703n應該也能夠);
- L298N電機驅動模塊;
- 2節18650電池;
- 小車底盤(帶電機);
- LM2596S降壓模塊(輸出5V電壓)。
2、硬件組裝
一個最基本的WIFI小車至少須要2路電機控制前進、後退、左轉、右轉。GL-inet的5個gpio須要用其中4個來控制兩路電機。如下是電路鏈接說明。
路由器GPIO接口,從左到右依次是2一、2二、1八、1九、20、GND,其中2二、1八、1九、20分別鏈接電機驅動板IN一、IN二、IN三、IN4。html
3、程序代碼
GL-inet路由須要刷openwrt-gl-ser2net.bin,由於原版的固件,打開攝像頭圖像鏈接要進行登陸管理後臺,刷完這個固件就能夠直接打開。java
- 主控(/usr/lib/lua/xiaoche.lua)採用LUA腳本編寫,代碼以下。
require("gpio") --分割字符串函數 function Split(szFullString, szSeparator) local nFindStartIndex = 1 local nSplitIndex = 1 local nSplitArray = {} while true do local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex) if not nFindLastIndex then nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString)) break end nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1) nFindStartIndex = nFindLastIndex + string.len(szSeparator) nSplitIndex = nSplitIndex + 1 end return nSplitArray end --小車控制相關GPIO:左電機19,20;右電機18,22 --小車前進 function Forward() writeGPIO(20,0) writeGPIO(19,1) writeGPIO(18,1) writeGPIO(22,0) end --小車後退 function Backward() writeGPIO(20,1) writeGPIO(19,0) writeGPIO(18,0) writeGPIO(22,1) end --小車左轉彎 function Left() writeGPIO(20,0) writeGPIO(19,1) writeGPIO(18,0) writeGPIO(22,1) end --小車右轉彎 function Right() writeGPIO(20,1) writeGPIO(19,0) writeGPIO(18,1) writeGPIO(22,0) end --小車停車 function Stop() writeGPIO(20,0) writeGPIO(19,0) writeGPIO(18,0) writeGPIO(22,0) end local WebService = {} function WebService.Run() local GET = os.getenv("QUERY_STRING") --解析GET數據 local list = Split(GET,'=') local c = list[2] --操做GPIO configureOutGPIO(20) configureOutGPIO(19) configureOutGPIO(18) configureOutGPIO(22) local status="Stop" if(c=="forward") then Forward() status="Forward" elseif(c=="backward") then Backward() status="Backward" elseif(c=="left") then Left() status="Left" elseif(c=="right") then Right() status="Right" else Stop() status="Stop" end --返回數據 io.write("Content-type: text/html\nPragma: no-cache\n\n") io.write(status) end return WebService
- 須要用到一個GPIO操做函數庫(/usr/lib/lua/gpio.lua),代碼以下。
--@author: Ewelina, Rafa, Rafa --GPIO utilities --Writes 'what' to 'where' function writeToFile (where,what) local fileToWrite=io.open(where, 'w') fileToWrite:write(what) fileToWrite:close() end --Reads a character from file 'where' and returns the string function readFromFile (where) local fileToRead=io.open(where, 'r') fileStr = fileToRead:read(1) fileToRead:close() return fileStr end --Returns true if file exists function file_exists(name) local f=io.open(name,"r") if f~=nil then io.close(f) return true else return false end end --Exports gpio ID to use as an output pin function configureOutGPIO (id) if not file_exists('/sys/class/gpio/gpio'..id..'/direction') then writeToFile('/sys/class/gpio/export',id) end writeToFile('/sys/class/gpio/gpio'..id..'/direction','out') end --Exports gpio ID to use as an input pin function configureInGPIO (id) if not file_exists('/sys/class/gpio/gpio'..id..'/direction') then writeToFile('/sys/class/gpio/export',id) end writeToFile('/sys/class/gpio/gpio'..id..'/direction','in') end --Reads GPIO 'id' and returns it's value --@Pre: GPIO 'id' must be exported with configureInGPIO function readGPIO(id) gpioVal = readFromFile('/sys/class/gpio/gpio'..id..'/value') return gpioVal end --Writes a value to GPIO 'id' --@Pre: GPIO 'id' must be exported with configureOutGPIO function writeGPIO(id, val) gpioVal = writeToFile('/sys/class/gpio/gpio'..id..'/value',val) return true end
- /www/cgi-bin/xc文件代碼以下。
#!/usr/bin/lua local Webservice = require 'xiaoche' Webservice.Run()
- 控制面板/www/xiaoche.html代碼。
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=500;target-densitydpi=device-dpi; minimum-scale=0.5; maximum-scale=2,user-scalable=no"> <title>視頻小車控制端</title> <script type="text/javascript" src="jquery-1.9.1.min.js"></script> <script> function Down(){ $.get("cgi-bin/xc?c="+$(this).attr('id'), function(data){ $("#status").html(data); }); } function Up(){ $.get("cgi-bin/xc?c=stop", function(data){ $("#status").html(data); }); } function load (){ document.getElementById("forward").addEventListener("touchstart", Down); document.getElementById("backward").addEventListener("touchstart", Down); document.getElementById("left").addEventListener("touchstart", Down); document.getElementById("right").addEventListener("touchstart", Down); document.getElementById("forward").addEventListener("touchend", Up); document.getElementById("backward").addEventListener("touchend", Up); document.getElementById("left").addEventListener("touchend", Up); document.getElementById("right").addEventListener("touchend", Up); //加載攝像頭圖像 $("#video").html("<img src='http://"+location.hostname+":8083/?action=stream' style='width:100%;'>"); } window.addEventListener('load',load,false); </script> <style> html,body{ margin:0 auto; background:#CCC; } .container{ margin:0 auto; width:100%; max-width:500px; background-color:#CCC; } .video{ width:100%; margin:0 auto; text-align:center; } .control{ width:100%; height:220px; } .button_fx{ width:100%; height:100%; } </style> </head> <body> <div class="container"> <div id="video" class="video"></div> <table class="control" border="0" cellpadding="5"> <tr> <td width="15%" height="30%"> </td> <td width="15%"><input type="button" class="button_fx" value="前進" id="forward"></td> <td width="15%"> </td> <td width="20%" align="center"><div id="status"> </div></td> <td width="35%" align="center">攝像頭控制</td> </tr> <tr> <td width="15%" height="30%"><input type="button" class="button_fx" value="左轉" id="left"></td> <td width="15%"> </td> <td width="15%"><input type="button" class="button_fx" value="右轉" id="right"></td> <