~~ 如果有什么问题可以在我的Five-great的博客留言,我会及时回复。欢迎来访交流 ~~
下面是小车
好丑 对不对 ,不过反正可以蛇皮走位就行。
蛇皮走位演示视频: 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 的错误,原因是python的str默认是ascii编码,和unicode编码冲突,就会报这个标题错误,解决办法是
1. 开头添加
import sys
reload(sys)
sys.setdefaultencoding('utf8')
2.暴力一点,把所有中文字符 汉字什么的 包括注释了的 都统统删掉 也可以解决
还有遇到 bottle 下载安装后 ,运行说 没有 安装 bottle 可能是 你把 bottle 安装到 python 2.7 环境下,而在python3 环境下找不到。
解决办法:
1 在命令行中 用对应pythonX 环境下运行
2.在执行脚本代码前 手动引包(得找到bottle 安装路径)
如果你想了解更多树莓派相关知识或则其他控制小车的手段
(如 自写网页,数据库,语音控制等)
可以此处留言或前往Five-great的博客留言板进行交流讨论 欢迎您的来访
能帮助您 ,留点个赞 ,关注一波 …^_^…
最后 奉上 采用 websocket 的实现的代码
先运行服务端代码 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>
注意: host 端口号要匹配哦
转载:https://blog.csdn.net/qq_41923622/article/details/85850780