网络异常,图片无法展示
|
好丑😂 对不对 ,不过反正可以蛇皮走位就行。
蛇皮走位演示视频: 手机QQ视频_20190105152514.mp4_免费高速下载|百度网盘-分享无限制
只需要 一个 index.html 和Index.py 就可以实现 简单WiFi 控制小车。
你需要准备的有
python 环境
bottle 库
安装bottle命令
pip install bottle
网络异常,图片无法展示
|
树莓派控制界面(web客户端)
index.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() "/") (defindex(): returntemplate("index") "/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"/") (defindex(): returntemplate("index") #### 这个是 客户端请求 服务端就发给一个 index.html 控制界面给客户端"/cmd") (defcmd(): adss=request.body.read().decode()#### 接收到 客户端 发过来的数据print("按下了按钮:"+adss) main(adss) #### 传值到主函数 实现对应功能return"OK"run(host="0.0.0.0") #### 开启服务端
运行 index.py 开启服务器:
网络异常,图片无法展示
|
然后打开浏览器(手机浏览器也可以但必须在同一个局域网内) 输入 树莓派的ip
有可能 打开比较慢 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 代码:
<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 端口号要匹配哦