写点什么

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

作者:Five
  • 2022 年 8 月 18 日
    四川
  • 本文字数:8871 字

    阅读完需:约 29 分钟

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

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

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

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


你需要准备的有

  python 环境

bottle 库

安装 bottle 命令


pip install bottle
复制代码


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

index.html 源码

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>遥控树莓派</title>    <link href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" media="screen">    <script src="http://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script>    <style type="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><div id="container" class="container"> <div> <button id="front" class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-up"></button> </div> <div>
<button id='leftFront' class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-left"></button> <button id='stop' class="btn btn-lg btn-primary glyphicon glyphicon-stop"></button> <button id='rightFront' class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-right"></button> </div> <div> <button id='rear' class="btn btn-lg btn-primary glyphicon glyphicon-circle-arrow-down"></button> </div> <div> <button id='leftRear' class="btn btn-lg btn-primary glyphicon">左后转</button> <button id='rightRear' class="btn btn-lg btn-primary glyphicon">右后转</button> </div></div>
<script src="//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>
复制代码

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


index.py 源码

#!/usr/bin/env python3# -*- coding:utf-8 -*-from bottle import get,post,run,request,template
import RPi.GPIO as GPIOimport timeimport sys
#### 定义Car类class Car(object): def __init__(self): self.enab_pin = [5,6,13,19]#### self.enab_pin是使能端的pin self.inx_pin = [21,22,23,24]#### self.inx_pin是控制端in的pin self.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]#### 分别是右轮前进,右轮退后,左轮前进,左轮退后的pin self.setup() #### setup函数初始化端口 def setup(self): print ("begin setup ena enb pin") GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) for pin in self.enab_pin: GPIO.setup(pin,GPIO.OUT) GPIO.output(pin,GPIO.HIGH)#### 初始化使能端pin,设置成高电平 pin = None for pin in self.inx_pin: GPIO.setup(pin,GPIO.OUT) GPIO.output(pin,GPIO.LOW)#### 初始化控制端pin,设置成低电平 print ("setup ena enb pin over") #### fornt函数,小车前进 def front(self): self.setup() GPIO.output(self.RightAhead_pin,GPIO.HIGH) GPIO.output(self.LeftAhead_pin,GPIO.HIGH) #### leftFront函数,小车左拐弯 def leftFront(self): self.setup() GPIO.output(self.RightAhead_pin,GPIO.HIGH) #### rightFront函数,小车右拐弯 def rightFront(self): self.setup() GPIO.output(self.LeftAhead_pin,GPIO.HIGH) #### rear函数,小车后退 def rear(self): self.setup() GPIO.output(self.RightBack_pin,GPIO.HIGH) GPIO.output(self.LeftBack_pin,GPIO.HIGH) #### leftRear函数,小车左退 def leftRear(self): self.setup() GPIO.output(self.RightBack_pin,GPIO.HIGH) #### rightRear函数,小车右退 def rightRear(self): self.setup() GPIO.output(self.LeftBack_pin,GPIO.HIGH) #### 定义main主函数def main(status): car = Car()
if status == "front": car.front() elif status == "leftFront": car.leftFront() elif status == "rightFront": car.rightFront() elif status == "rear": car.rear() elif status == "leftRear": car.leftRear() elif status == "rightRear": car.rightRear() elif status == "stop": car.setup()


@get("/")def index(): return template("index")@post("/cmd")def cmd(): adss=request.body.read().decode() print("按下了按钮:"+adss) main(adss) return "OK"run(host="0.0.0.0")
复制代码


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

from bottle import get,post,run,request,template

@get("/")def index(): return template("index") #### 这个是 客户端请求 服务端就发给一个 index.html 控制界面给客户端@post("/cmd")def cmd(): 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 分钟内吧 😁(我第一次打开 就用了好久 都以为没有成功)


PC端控制界面

手机端输入 ip


手机端控制界面


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


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

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

  car.py 代码

#coding=utf8
import struct, socket, sysimport hashlibimport threading, randomimport timefrom base64 import b64encode, b64decodeimport RPi.GPIO as GPIOimport sys
GPIO.setmode(GPIO.BCM)GPIO.setwarnings(False)GPIO.setup(17,GPIO.OUT)p=GPIO.PWM(17,600)p_pin =35p.start(p_pin)#### 定义Car类class Car(object): def __init__(self):
self.inx_pin = [19,26,5,6]#### self.inx_pin是控制端in的pin self.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]#### 分别是右轮前进,左轮前进,右轮退后,左轮退后的pin self.RightP_pin=17 self.LeftP_pin =27 self.setup() #### setup函数初始化端口 def setup(self): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False)#### 初始化使能端pin,设置成高电平 pin = None for pin in self.inx_pin: GPIO.setup(pin,GPIO.OUT) GPIO.output(pin,GPIO.LOW)#### 初始化控制端pin,设置成低电平 print ("setup ena enb pin over") #### fornt函数,小车前进 def front(self): self.setup() GPIO.output(self.RightAhead_pin,GPIO.HIGH) GPIO.output(self.LeftAhead_pin,GPIO.HIGH) #### leftFront函数,小车左拐弯 def leftFront(self): self.setup() GPIO.output(self.RightAhead_pin,GPIO.HIGH) #### rightFront函数,小车右拐弯 def rightFront(self): self.setup() GPIO.output(self.LeftAhead_pin,GPIO.HIGH) #### rear函数,小车后退 def rear(self): self.setup() GPIO.output(self.RightBack_pin,GPIO.HIGH) GPIO.output(self.LeftBack_pin,GPIO.HIGH) #### leftRear函数,小车左退 def leftRear(self): self.setup() GPIO.output(self.RightBack_pin,GPIO.HIGH) #### rightRear函数,小车右退 def rightRear(self): self.setup() GPIO.output(self.LeftBack_pin,GPIO.HIGH)
#### 定义main主函数def main(status): car = Car()
if status == "front": car.front() elif status == "leftFront": car.leftFront() elif status == "rightFront": car.rightFront() elif status == "rear": car.rear() elif status == "leftRear": car.leftRear() elif status == "rightRear": car.rightRear() elif status == "stop": car.setup() #p.stop() elif status == "q1": p.ChangeDutyCycle(35) elif status == "q2": p.ChangeDutyCycle(50) elif status == "q3": p.ChangeDutyCycle(75) elif status == "q4": p.ChangeDutyCycle(90) elif status == "q5": p.ChangeDutyCycle(100)


##socketconnectionlist = {}
def decode(data): if not len(data): return False
# 用数据包的第二个字节,与127作与位运算,拿到前七位。 length = data[1] & 127
# 这七位在数据头部分成为payload,如果payload等于126,就要再扩展2个字节。 # 如果等于127,就要再扩展8个字节。 # 如果小于等于125,那它就占这一个字节。 if length == 126: extend_payload_len = data[2:4] mask = data[4:8] decoded = data[8:] elif length == 127: extend_payload_len = data[2:10] mask = data[10:14] decoded = data[14:] else: extend_payload_len = None mask = data[2:6] decoded = data[6:] byte_list = bytearray()
print(mask) print(decoded)
# 当payload确定之后,再往后数4个字节,这4个字节成为masking key,再之后的内容就是接收到的数据部分。 # 数据部分的每一字节都要和masking key作异或位运算,得出来的结果就是真实的数据内容。 for i in range(len(decoded)): chunk = decoded[i] ^ mask[i % 4] byte_list.append(chunk) new_str = str(byte_list, encoding="utf-8") print(new_str) return new_str
def encode(data): data=str.encode(data) head = b'\x81'
if len(data) < 126: head += struct.pack('B', len(data)) elif len(data) <= 0xFFFF: head += struct.pack('!BH', 126, len(data)) else: head += struct.pack('!BQ', 127, len(data)) return head+data def sendMessage(message): global connectionlist for connection in connectionlist.values(): connection.send(encode(message)) def deleteconnection(item): global connectionlist del connectionlist['connection'+item]
class WebSocket(threading.Thread):
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
def __init__(self,conn,index,name,remote, path="/"): threading.Thread.__init__(self) self.conn = conn self.index = index self.name = name self.remote = remote self.path = path self.buffer = "" def run(self): print('Socket%s Start!' % self.index) headers = {} self.handshaken = False
while True: try: if self.handshaken == False: print ('Socket%s Start Handshaken with %s!' % (self.index,self.remote)) self.buffer += bytes.decode(self.conn.recv(1024))
if self.buffer.find('\r\n\r\n') != -1: header, data = self.buffer.split('\r\n\r\n', 1) for line in header.split("\r\n")[1:]: key, value = line.split(": ", 1) headers[key] = value
headers["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 = True print('Socket%s Handshaken with %s success!' %(self.index, self.remote)) sendMessage('Welcome, ' + self.name + ' !')
else: msg = decode(self.conn.recv(1024)) main(msg) if msg == '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() break else: #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 = "" except Exception as e: self.conn.close()
class WebSocketServer(object): def __init__(self): self.socket = None def begin(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)
global connectionlist
i = 0 while True: connection, address = self.socket.accept()
username=address[0] newSocket = WebSocket(connection,i,username,address) newSocket.start() connectionlist['connection'+str(i)]=connection i = i + 1
if __name__ == "__main__": server = WebSocketServer() server.begin()
复制代码


 car.html  代码:

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


注意: host 端口号要匹配哦 

发布于: 刚刚阅读数: 3
用户头像

Five

关注

有事多研究,没事瞎琢磨 2022.08.02 加入

CSDN 前端领域优质创作者 , 博客专家认证, 华为云云享专家。 退役ACMer, IT技术狂热爱好者 擅长领域,web前端,算法, 业务架构,可视化,富文本编辑器等。 github: https://github.com/Five-great

评论

发布
暂无评论
简单WiFi控制小车系统(树莓派+python+web控制界面)_树莓派_Five_InfoQ写作社区