简单WiFi控制小车系统(树莓派+python+web控制界面)

简介: 好丑😂 对不对 ,不过反正可以蛇皮走位就行。 蛇皮走位演示视频: 只需要 一个 index.html 和Index.py 就可以实现 简单WiFi 控制小车。你需要准备的有

网络异常,图片无法展示
|

好丑😂 对不对 ,不过反正可以蛇皮走位就行。

蛇皮走位演示视频: 手机QQ视频_20190105152514.mp4_免费高速下载|百度网盘-分享无限制

只需要 一个 index.html  和Index.py 就可以实现 简单WiFi 控制小车。

你需要准备的有

 python 环境

bottle 库

安装bottle命令

pip install bottle

网络异常,图片无法展示
|

树莓派控制界面(web客户端)

index.html源码

<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>遥控树莓派</title><linkhref="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"rel="stylesheet"media="screen"><scriptsrc="http://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><styletype="text/css">#front {
margin-left: 55px;
margin-bottom: 3px;
        }
#rear{
margin-top: 3px;
margin-left: 55px;
        }
.btn{
background: #62559f;
            }
</style><script>$(function(){
$("button").click(function(){
$.post("/cmd",this.id,function(data,status){});
            });
        });
</script></head><body><divid="container"class="container"><div><buttonid="front"class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-up"></button></div><div><buttonid='leftFront'class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-left"></button><buttonid='stop'class="btn btn-lg btn-primary glyphicon glyphicon-stop"></button><buttonid='rightFront'class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-right"></button></div><div><buttonid='rear'class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down"></button></div><div><buttonid='leftRear'class="btn btn-lg btn-primary glyphicon">左后转</button><buttonid='rightRear'class="btn btn-lg btn-primary glyphicon">右后转</button></div></div><scriptsrc="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script></body></html>

js脚本解释:

<script>$(function(){
$("button").click(function(){
$.post("/cmd",this.id,function(data,status){});
//表示 按钮对应的id值 会被传入树莓派服务器中,就如同 你在树莓派的命令行(cmd)中输入 id 的值            });
        });
</script>

树莓派小车控制程序(web服务端)

index.py 源码

#!/usr/bin/env python3# -*- coding:utf-8 -*-frombottleimportget,post,run,request,templateimportRPi.GPIOasGPIOimporttimeimportsys####  定义Car类classCar(object):
def__init__(self):
self.enab_pin= [5,6,13,19]
####  self.enab_pin是使能端的pinself.inx_pin= [21,22,23,24]
####  self.inx_pin是控制端in的pinself.RightAhead_pin=self.inx_pin[0]
self.RightBack_pin=self.inx_pin[1]
self.LeftAhead_pin=self.inx_pin[2]
self.LeftBack_pin=self.inx_pin[3]
####  分别是右轮前进,右轮退后,左轮前进,左轮退后的pinself.setup()
####  setup函数初始化端口defsetup(self):
print ("begin setup ena enb pin")
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
forpininself.enab_pin: 
GPIO.setup(pin,GPIO.OUT)
GPIO.output(pin,GPIO.HIGH)
####  初始化使能端pin,设置成高电平pin=Noneforpininself.inx_pin:
GPIO.setup(pin,GPIO.OUT)
GPIO.output(pin,GPIO.LOW)
####  初始化控制端pin,设置成低电平print ("setup ena enb pin over")
####  fornt函数,小车前进deffront(self):
self.setup()
GPIO.output(self.RightAhead_pin,GPIO.HIGH)
GPIO.output(self.LeftAhead_pin,GPIO.HIGH)
####  leftFront函数,小车左拐弯defleftFront(self):
self.setup()
GPIO.output(self.RightAhead_pin,GPIO.HIGH)
####  rightFront函数,小车右拐弯defrightFront(self):
self.setup()
GPIO.output(self.LeftAhead_pin,GPIO.HIGH)
####  rear函数,小车后退defrear(self):
self.setup()
GPIO.output(self.RightBack_pin,GPIO.HIGH)
GPIO.output(self.LeftBack_pin,GPIO.HIGH)
####  leftRear函数,小车左退defleftRear(self):
self.setup()
GPIO.output(self.RightBack_pin,GPIO.HIGH)
####  rightRear函数,小车右退defrightRear(self):
self.setup()
GPIO.output(self.LeftBack_pin,GPIO.HIGH)
####  定义main主函数defmain(status):
car=Car()
ifstatus=="front":
car.front()
elifstatus=="leftFront":
car.leftFront()
elifstatus=="rightFront":
car.rightFront()
elifstatus=="rear":
car.rear()
elifstatus=="leftRear":
car.leftRear()
elifstatus=="rightRear":
car.rightRear()
elifstatus=="stop":
car.setup()      
@get("/")
defindex():
returntemplate("index")
@post("/cmd")
defcmd():
adss=request.body.read().decode()
print("按下了按钮:"+adss)
main(adss)
return"OK"run(host="0.0.0.0")

web服务端 实际就这点代码, 主要是 bottle 库的强大,(实际控制的小车的代码 根据自己的需求改就行了)

frombottleimportget,post,run,request,template@get("/")
defindex():
returntemplate("index") 
#### 这个是 客户端请求 服务端就发给一个 index.html 控制界面给客户端@post("/cmd")
defcmd():
adss=request.body.read().decode()#### 接收到 客户端 发过来的数据print("按下了按钮:"+adss)
main(adss)  #### 传值到主函数 实现对应功能return"OK"run(host="0.0.0.0")  #### 开启服务端

运行 index.py 开启服务器:

网络异常,图片无法展示
|

然后打开浏览器(手机浏览器也可以但必须在同一个局域网内) 输入 树莓派的ip

我的是 http://192.168.191.4:8080

有可能 打开比较慢  10分钟内吧 😁(我第一次打开 就用了好久 都以为没有成功)

网络异常,图片无法展示
|

手机端输入ip

网络异常,图片无法展示
|

在后台可以查看到相应的操作日志

网络异常,图片无法展示
|

当然如果你有更为复杂的需求,可以采用 websocket 的方式,下面奉上代码

先运行服务端代码 car.py,然后再 运行 car.html

 car.py 代码

#coding=utf8importstruct, socket, sysimporthashlibimportthreading, randomimporttimefrombase64importb64encode, b64decodeimportRPi.GPIOasGPIOimportsysGPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(17,GPIO.OUT)
p=GPIO.PWM(17,600)
p_pin=35p.start(p_pin)
####  定义Car类classCar(object):
def__init__(self):
self.inx_pin= [19,26,5,6]
####  self.inx_pin是控制端in的pinself.RightAhead_pin=self.inx_pin[0]
self.LeftAhead_pin=self.inx_pin[1]
self.RightBack_pin=self.inx_pin[2]
self.LeftBack_pin=self.inx_pin[3]
####  分别是右轮前进,左轮前进,右轮退后,左轮退后的pinself.RightP_pin=17self.LeftP_pin=27self.setup()
####  setup函数初始化端口defsetup(self):
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
####  初始化使能端pin,设置成高电平pin=Noneforpininself.inx_pin:
GPIO.setup(pin,GPIO.OUT)
GPIO.output(pin,GPIO.LOW)
####  初始化控制端pin,设置成低电平print ("setup ena enb pin over")
####  fornt函数,小车前进deffront(self):
self.setup()
GPIO.output(self.RightAhead_pin,GPIO.HIGH)
GPIO.output(self.LeftAhead_pin,GPIO.HIGH)
####  leftFront函数,小车左拐弯defleftFront(self):
self.setup()
GPIO.output(self.RightAhead_pin,GPIO.HIGH)
####  rightFront函数,小车右拐弯defrightFront(self):
self.setup()
GPIO.output(self.LeftAhead_pin,GPIO.HIGH)
####  rear函数,小车后退defrear(self):
self.setup()
GPIO.output(self.RightBack_pin,GPIO.HIGH)
GPIO.output(self.LeftBack_pin,GPIO.HIGH)
####  leftRear函数,小车左退defleftRear(self):
self.setup()
GPIO.output(self.RightBack_pin,GPIO.HIGH)
####  rightRear函数,小车右退defrightRear(self):
self.setup()
GPIO.output(self.LeftBack_pin,GPIO.HIGH)
####  定义main主函数defmain(status):
car=Car()
ifstatus=="front":
car.front()
elifstatus=="leftFront":
car.leftFront()
elifstatus=="rightFront":
car.rightFront()
elifstatus=="rear":
car.rear()
elifstatus=="leftRear":
car.leftRear()
elifstatus=="rightRear":
car.rightRear()
elifstatus=="stop":
car.setup()      
#p.stop()elifstatus=="q1":
p.ChangeDutyCycle(35)
elifstatus=="q2":
p.ChangeDutyCycle(50)
elifstatus=="q3":
p.ChangeDutyCycle(75)
elifstatus=="q4":
p.ChangeDutyCycle(90)
elifstatus=="q5":
p.ChangeDutyCycle(100)
##socketconnectionlist= {}
defdecode(data):
ifnotlen(data):
returnFalse# 用数据包的第二个字节,与127作与位运算,拿到前七位。length=data[1] &127# 这七位在数据头部分成为payload,如果payload等于126,就要再扩展2个字节。# 如果等于127,就要再扩展8个字节。# 如果小于等于125,那它就占这一个字节。iflength==126:
extend_payload_len=data[2:4]
mask=data[4:8]
decoded=data[8:]
eliflength==127:
extend_payload_len=data[2:10]
mask=data[10:14]
decoded=data[14:]
else:
extend_payload_len=Nonemask=data[2:6]
decoded=data[6:]
byte_list=bytearray()
print(mask)
print(decoded)
# 当payload确定之后,再往后数4个字节,这4个字节成为masking key,再之后的内容就是接收到的数据部分。# 数据部分的每一字节都要和masking key作异或位运算,得出来的结果就是真实的数据内容。foriinrange(len(decoded)):
chunk=decoded[i] ^mask[i%4]
byte_list.append(chunk)
new_str=str(byte_list, encoding="utf-8")
print(new_str)
returnnew_strdefencode(data):  
data=str.encode(data)
head=b'\x81'iflen(data) <126:
head+=struct.pack('B', len(data))
eliflen(data) <=0xFFFF:
head+=struct.pack('!BH', 126, len(data))
else:
head+=struct.pack('!BQ', 127, len(data))
returnhead+datadefsendMessage(message):
globalconnectionlistforconnectioninconnectionlist.values():
connection.send(encode(message))
defdeleteconnection(item):
globalconnectionlistdelconnectionlist['connection'+item]
classWebSocket(threading.Thread):
GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"def__init__(self,conn,index,name,remote, path="/"):
threading.Thread.__init__(self)
self.conn=connself.index=indexself.name=nameself.remote=remoteself.path=pathself.buffer=""defrun(self):
print('Socket%s Start!'%self.index)
headers= {}
self.handshaken=FalsewhileTrue:
try: 
ifself.handshaken==False:
print ('Socket%s Start Handshaken with %s!'% (self.index,self.remote))
self.buffer+=bytes.decode(self.conn.recv(1024))
ifself.buffer.find('\r\n\r\n') !=-1:
header, data=self.buffer.split('\r\n\r\n', 1)
forlineinheader.split("\r\n")[1:]:
key, value=line.split(": ", 1)
headers[key] =valueheaders["Location"] = ("ws://%s%s"%(headers["Host"], self.path))
key=headers['Sec-WebSocket-Key']
token=b64encode(hashlib.sha1(str.encode(str(key+self.GUID))).digest())
handshake="HTTP/1.1 101 Switching Protocols\r\n"\
"Upgrade: websocket\r\n"\
"Connection: Upgrade\r\n"\
"Sec-WebSocket-Accept: "+bytes.decode(token)+"\r\n"\
"WebSocket-Origin: "+str(headers["Origin"])+"\r\n"\
"WebSocket-Location: "+str(headers["Location"])+"\r\n\r\n"self.conn.send(str.encode(str(handshake)))
self.handshaken=Trueprint('Socket%s Handshaken with %s success!'%(self.index, self.remote))
sendMessage('Welcome, '+self.name+' !')
else:
msg=decode(self.conn.recv(1024))
main(msg)
ifmsg=='quit':
print ('Socket%s Logout!'% (self.index))
nowTime=time.strftime('%H:%M:%S',time.localtime(time.time()))
sendMessage('%s %s say: %s'% (nowTime, self.remote, self.name+' Logout'))                  
deleteconnection(str(self.index))
self.conn.close()
breakelse:
#print('Socket%s Got msg:%s from %s!' % (self.index, msg, self.remote))nowTime=time.strftime('%H:%M:%S',time.localtime(time.time()))
sendMessage('%s %s say: %s'% (nowTime, self.remote, msg))       
self.buffer=""exceptExceptionase:
self.conn.close()
classWebSocketServer(object):
def__init__(self):
self.socket=Nonedefbegin(self):
print( 'WebSocketServer Start!')
self.socket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind(("172.19.8.102", 8081))
self.socket.listen(50)
globalconnectionlisti=0whileTrue:
connection, address=self.socket.accept()
username=address[0]     
newSocket=WebSocket(connection,i,username,address)
newSocket.start()
connectionlist['connection'+str(i)]=connectioni=i+1if__name__=="__main__":
server=WebSocketServer()
server.begin()

car.html  代码:

<!DOCTYPE html><htmllang="zh-cn"><head><metahttp-equiv="Content-Type"content="text/html; charset=utf-8"/><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>遥控树莓派</title><linkhref="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"rel="stylesheet"media="screen"><scriptsrc="http://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script><styletype="text/css">#front {
margin-left: 55px;
margin-bottom: 3px;
        }
#rear{
margin-top: 3px;
margin-left: 55px;
        }
.btn{
background: #62559f;
            }
</style><script>varsocket;
functioninit() {
varhost="ws://192.168.1.111:8081/";
try {
socket=newWebSocket(host);
socket.onopen=function () {
                };
socket.onmessage=function () {
                };
socket.onclose=function () {
                };
            }
catch (ex) {
            }
        }
functionsend(msg) {
try {
socket.send(msg);
            } catch (ex) {
            }
        }
window.onbeforeunload=function () {
try {
socket.send('quit');
socket.close();
socket=null;
            }
catch (ex) {
            }
        };
</script></head><bodyonload="init()"><divid="container"class="container"><div><buttonid="front"class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-up"onclick="send('front')"></button></div><div><buttonid='leftFront'class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-left"onclick="send('leftFront')"></button><buttonid='stop'class="btn btn-lg btn-primary glyphicon glyphicon-stop"onclick="send('stop')"></button><buttonid='rightFront'class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-right"onclick="send('rightFront')"></button></div><divstyle="height:50px;"><buttonid='rear'class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down"onclick="send('rear')"></button></div><divstyle="height:20px;"></div><divstyle="height:50px;"><buttonid='leftRear'class="btn btn-lg btn-primary glyphicon"onclick="send('leftRear')">左后转</button><buttonid='rightRear'class="btn btn-lg btn-primary glyphicon"onclick="send('rightRear')">右后转</button></div><divstyle="height:20px;"></div><divstyle="height:50px;"><buttonid='q1'class="btn btn-lg btn-primary glyphicon"onclick="send('q1')">P1</button><buttonid='q2'class="btn btn-lg btn-primary glyphicon"onclick="send('q2')">P2</button><buttonid='q3'class="btn btn-lg btn-primary glyphicon"onclick="send('q3')">P3</button><divstyle="height:20px;"></div><buttonid='q4'class="btn btn-lg btn-primary glyphicon"onclick="send('q4')">P4</button><buttonid='q5'class="btn btn-lg btn-primary glyphicon"onclick="send('q5')">P5</button></div></div><scriptsrc="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script></body></html>

注意: host 端口号要匹配哦

目录
相关文章
|
16天前
|
传感器 小程序 搜索推荐
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
通过电子班牌设备和智慧校园数据平台的统一管理,在电子班牌上,班牌展示、学生上课刷卡考勤、考勤状况汇总展示,课表展示,考场管理,请假管理,成绩查询,考试优秀标兵展示、校园通知展示,班级文化各片展示等多种化展示。
40 0
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
|
14天前
|
前端开发 JavaScript Java
计算机Java项目|基于Web的足球青训俱乐部管理后台系统的设计与开发
计算机Java项目|基于Web的足球青训俱乐部管理后台系统的设计与开发
|
11天前
|
缓存 前端开发 JavaScript
【前端性能优化】深入解析重绘和回流,构建高性能Web界面
【前端性能优化】深入解析重绘和回流,构建高性能Web界面
20 1
|
16天前
|
数据库 数据安全/隐私保护 Python
Web实战丨基于Django与HTML的新闻发布系统(二)
Web实战丨基于Django与HTML的新闻发布系统(二)
19 1
|
16天前
|
存储 数据库 数据安全/隐私保护
Web实战丨基于Django与HTML的新闻发布系统
Web实战丨基于Django与HTML的新闻发布系统
17 1
|
16天前
|
存储 搜索推荐 数据库
Web实战丨基于Django与HTML的用户登录验证系统
Web实战丨基于Django与HTML的用户登录验证系统
23 1
|
1月前
|
应用服务中间件 nginx
蓝易云 - 编写Dockerfile制作Web应用系统nginx镜像
这是一个基本的例子,你可能需要根据自己的应用进行调整。例如,你可能需要添加更多的配置,或者使用不同的Nginx版本。
45 2
|
1月前
|
存储 监控 Ubuntu
Linux系统之GoAccess实时Web日志分析工具的基本使用
【5月更文挑战第22天】Linux系统之GoAccess实时Web日志分析工具的基本使用
50 1
|
16天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的高校疫情防控web系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的高校疫情防控web系统附带文章源码部署视频讲解等
14 0
|
23天前
|
数据安全/隐私保护 Windows
windows系统bat批处理 笔记本开wifi 笔记本查看wifi密码
windows系统bat批处理 笔记本开wifi 笔记本查看wifi密码
19 0