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

~~ 如果有什么问题可以在我的Five-great的博客留言,我会及时回复。欢迎来访交流 ~~

下面是小车

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

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

需要准备

python

bottle 库

bottle 安装

命令: pip install bottle

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

index.html

遥控树莓派

#front {

margin-left: 55px;

margin-bottom: 3px;

}

#rear{

margin-top: 3px;

margin-left: 55px;

}

.btn{

background: #62559f;

}

$(function(){

$("button").click(function(){

$.post("/cmd",this.id,function(data,status){});

});

});

左后转

右后转

js脚本解释:

$(function(){

$("button").click(function(){

$.post("/cmd",this.id,function(data,status){});

//表示 按钮对应的id值 会被传入树莓派服务器中,就如同 你在树莓派的命令行(cmd)中输入 id 的值

});

});

树莓派小车控制程序+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  代码:

遥控树莓派

#front {

margin-left: 55px;

margin-bottom: 3px;

}

#rear{

margin-top: 3px;

margin-left: 55px;

}

.btn{

background: #62559f;

}

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) {

}

};

左后转

右后转

P1

P2

P3

P4

P5

注意: host 端口号要匹配哦

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值