以前也用单片机做过WIFI小车,但是单片机没有自带WIFI,仍然需要用到小路由器作为图传和控制信号传输。既然肯定要用到路由器,那何不直接用路由器作为主控呢,这样就省掉了单片机。这次作为主控的GL-inet迷你路由,64M内存,16M Flash,支持OPENWRT系统,自带刷不死Uboot,Uart调试接口已焊好,另预留5个GPIO接口,可以充分满足DIY爱好者的需要。5个GPIO制作WIFI小车勉强够用。首先来一张完成图。

一、需要用到的材料

  1. Gl-inet路由器(有TPLink WR703n应该也可以);
  2. L298N电机驱动模块;
  3. 2节18650电池;
  4. 小车底盘(带电机);
  5. LM2596S降压模块(输出5V电压)。

二、硬件组装

一个最基本的WIFI小车至少需要2路电机控制前进、后退、左转、右转。GL-inet的5个gpio需要用其中4个来控制两路电机。以下是电路连接说明。

路由器GPIO接口,从左到右依次是21、22、18、19、20、GND,其中22、18、19、20分别连接电机驱动板IN1、IN2、IN3、IN4。

三、程序代码

GL-inet路由需要刷openwrt-gl-ser2net.bin,因为原版的固件,打开摄像头图像连接要进行登录管理后台,刷完这个固件就可以直接打开。

  1. 主控(/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
  1. 需要用到一个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
  1. /www/cgi-bin/xc文件代码如下。
#!/usr/bin/lua
local Webservice = require 'xiaoche'
Webservice.Run()
  1. 控制面板/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%">&nbsp;</td>
<td width="15%"><input type="button" class="button_fx" value="前进" id="forward"></td>
<td width="15%">&nbsp;</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%">&nbsp;</td>
<td width="15%"><input type="button" class="button_fx" value="右转" id="right"></td>
<td width="20%">&nbsp;</td>
<td width="35%"><input type="button" class="button_fx" value="向上" id="gpio21s"></td>
</tr>
<tr>
<td width="15%" height="30%">&nbsp;</td>
<td width="15%"><input type="button" class="button_fx" value="后退" id="backward"></td>
<td width="15%">&nbsp;</td>
<td width="20%">&nbsp;</td>
<td width="35%"><input type="button" class="button_fx" value="向下" id="gpio21x"></td>
</tr>
</table>
</div>
</body>
</html>

此外需要用到的/www/jquery-1.9.1.min.js不要忘了下载到相应目录,别的jquery版本也可。

控制小车只要用手机连接路由器,浏览器打开http://路由器IP/xiaoche.html,建议用via浏览器,长按不会跳出菜单影响操作。把路由器设置位中继模式配合内网穿透,还可以在外网远程控制。最后来一段小车演示视频:

GL-inet路由器当主控制作WIFI视频小车的更多相关文章

  1. 树莓派小车By 树莓派爱好者ITJoker(通过python socket通信实现树莓派视频小车)(一)

    本文由树莓派爱好者ITJoker 编辑,转载请注明出处.本人也有新浪博客同样是树莓派爱好者ITJoker 所需材料:树莓派2B或者2B以上,L2985n驱动板,若干排线,电池及电池盒,usb无线网卡( ...

  2. 制作Wi-Fi Ducky远程HID攻击设备

    1.介绍WIFI DUCKY 它是一个Wi-Fi控制的BadUSB设备来远程执行Ducky Scripts. 使用充当键盘的USB设备来注入攻击,Hak5 的 USB Rubber Ducky 是这种 ...

  3. 手把手教你制作AppPreview视频并上传到appStore进行审核

    手把手教你制作AppPreview视频并上传到appStore进行审核 注意,你需要使用iMovie才能够制作AppPreview视频文件,用QuickTime录制的无效! 最终效果 1. 新建一个事 ...

  4. 基于Qt的wifi智能小车的制作(一)

     基于Qt的wifi智能小车的制作(一) 好久不写博客了,真的是有点惭愧了.翻开上一次的博客,到现在已经2个多月了,只能说是自己太懒惰了!忙是另一回事!趁今天晚上有点时间回顾下这一段时间的收获以及做的 ...

  5. 追星女孩必备!使用Camtasia制作爱豆视频

    制作爱豆视频,我用得比较多的是Camtasia(Windows)教程录制.因为这款软件操作简单,功能强大,用起来相当顺手呢.而且更重要的是,Camtasia有录屏功能,电脑存量不足的情况下,真的很好用 ...

  6. 使用Camtasia制作冰雪奇缘视频

    冰雪奇缘的精良制作,以及场景的华丽,让很多女孩子都很喜欢.对于其中美丽的冰雪场景,我们还可以使用Camtasia(Windows系统)教程录制软件来做冰雪奇缘视频. Camtasia教程录制软件是一款 ...

  7. 通过Camtasia来制作画中画视频效果的方法

    随着全民娱乐化的发展,视频的形式也更加多种多样了.视频形式的多样化能让观众从不同形式的视频中观赏到更有趣味的内容.比如像画中画的视频形式,让视频中的人物看起来像与观众一同观看视频,或者形成两个视频的对 ...

  8. 通过本地IIS服务器+路由器==实现本地局域网WIFI覆盖

    这是一张手机连接wifi局域网下载视频的图片,速度可以达到10M/S左右,下面让我们来看一下,本地服务器是如何建立的. 1.启动本地IIS服务 步骤如下 一.电脑右键-属性-控制面板-程序和功能-打开 ...

  9. 使用 ESP8266 制作 WiFi 干扰器 - 无需密码即可使用任何 WiFi

    嘿,朋友,我是 Kedar,你有没有想阻止所有的 WiFi信号?或者只是想从 WiFi 踢某人或邻居 WiFi .那么,本玩法是你等待结束的时刻了.这是为你提供的.仅需 $8 的 DIY Wifi 干 ...

随机推荐

  1. ThinkPHP5.1 + tufanbarisyildirim 解析apk

    摘要 对于apk,我可以说只会安装,并不知道其中有什么内容需要记录下来.这次公司做一个关于电视机顶盒的项目.对于这个陌生的项目,刚开始真是一脸懵逼,完全不知道如何下手. 因为这类的项目完全没有接触过, ...

  2. 试试自行封装AJAX和jQuery中的ajax封装的基本使用

    封装的套路: 1.写一个相对比较完善的用例2.写一个空函数,没有形参,将刚刚的用例直接作为函数的函数体3.根据使用过程中的需求抽象函数 代码记录如下: <script> function ...

  3. ajax的请求步骤!每个状态值表示什么?

    什么是是ajax ! AJAX即"Asynchronous JavaScript and XML"(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页 ...

  4. 为什么不要使用 async void?

    问题 在使用 Abp 框架的后台作业时,当后台作业抛出异常,会导致整个程序崩溃.在 Abp 框架的底层执行后台作业的时候,有 try/catch 语句块用来捕获后台任务执行时的异常,但是在这里没有生效 ...

  5. mysql的学习笔记(一)

    前言 开发中经常用mysql和SQL server交替使用,自己都产生知识的混乱.在这里重新整理下mysql的知识,也是梳理自己知识点,因为是学习笔记,所以并不会使用到图形化管理工具.mysql的安装 ...

  6. C#反射调用方法实例

    下面是两个反射的实例 案例1: 动态调用类中的方法.传入参数,并获得返回值. xxxx:类名 Event:类中的方法 pra1,pra2,pra3:方法对应的入参 DoRet:方法返回的执行结果 Ty ...

  7. rabbitmq高级消息队列

    rabbitmq使用 什么是消息队列 消息(Message)是指在应用间传送的数据.消息可以非常简单,比如只包含文本字符串,也可以很复杂,可以包含嵌入对象. 消息队列是一种应用间的通信方式,消息发送后 ...

  8. JavaScript小记二则:接上一节:用.net写Textbox控件关于数字的判断的另一则方法

    方法二.通过写JS进行判断控制输入的只能为数字,源码如下: <!DOCTYPE html> <html> <body> <h1></h1> ...

  9. 史上最全office2016 激活码

    现在office版本已经更新到2016了,现在给大家分享Office 2016 各个版本的激活码,记得断网激活哈.(本人使用的是家庭版) Office 2016 Pro Retail 版激活密钥: [ ...

  10. 将Xml文件递归加载到TreeView中

    #region [通过XDocument的方式将Xml文件递归到TreeView控件中] //读取Xml文件(XDocument) //1.加载Xml文件 XDocument  document=XD ...