下面是小车
好丑 对不对 ,不过反正可以蛇皮走位就行。
蛇皮走位演示视频: https://pan.baidu.com/s/1RHHr8bRHWzSEAkrpwu99aw
只需要 一个 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 GPIO
import time
import 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 我的是 192.168.191.4:8080
有可能 打开比较慢 10分钟内吧 哈哈哈(我第一次打开 就用了好久 都以为没有成功)
手机端输入ip
登录成功!!!
输入之后 服务器会给你抛出一个 index.html 控制文件。
然后就可以点击按键 控制小车了 下面是 服务端中反馈
框架搭好后,根据自己需求更改 。
补充说明一下啊 因为我改过系统的语言和编码设置 (支持utf-8)
详情 : 树莓派 设置系统中文 并安装中文输入法
当很多人遇到
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position
1. 开头添加
import sys
reload(sys)
sys.setdefaultencoding('utf8')
2.暴力一点,把所有中文字符 汉字什么的 包括注释了的 都统统删掉 也可以解决
还有遇到 bottle 下载安装后 ,运行说 没有 安装 bottle 可能是 你把 bottle 安装到 python 2.7 环境下,而在python3 环境下找不到。
解决办法:
1 在命令行中 用对应pythonX 环境下运行
2.在执行脚本代码前 手动引包(得找到bottle 安装路径)
如果你想了解更多树莓派相关知识或则其他控制小车的手段
(如 自写网页,数据库,语音控制等)
先运行服务端代码 car.py,然后再 运行 car.html
car.py 代码
#coding=utf8
import struct, socket, sys
import hashlib
import threading, random
import time
from base64 import b64encode, b64decode
import RPi.GPIO as GPIO
import sys
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(17,GPIO.OUT)
p=GPIO.PWM(17,600)
p_pin =35
p.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)
##socket
connectionlist = {}
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>