这几天都在玩树莓派小车的项目,前几天做完了小车的测试题电机方案后,这两天做完了电源方案,也接入了实体小车,所以就稍微花了点时间写了点控制端代码,用来实现远程遥控小车。
这里提一下整个代码的逻辑:
1、通讯采用http协议(目前观察http请求延迟还行,暂时就先不考虑socket长连接了)。
2、前端采用html,绘制界面为两个虚拟摇杆,摇杆采用的是nipplejs库绘制,这个js库提供了摇杆所需要的一些操作监控什么的。其中左边摇杆控制A电机,实现左右方向控制,右边摇杆控制B电机,实现小车的前进和后退。
3、后端采用python flask框架,用来接受web请求,区分web请求指令,执行相应电机控制操作(前进,后退,左转,右转,停止移动,停止转向)。
这里贴上一些关键代码:
前端界面,index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>智能车控制中心</title>
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5">
<style>
html, body {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 0;
margin: 0;
}
#left {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 50%;
background: rgba(0, 255, 0, 0.1);
}
#right {
position: absolute;
right: 0;
top: 0;
height: 100%;
width: 50%;
background: rgba(0, 0, 255, 0.1);
}
</style>
</head>
<body>
<div id="left"></div>
<div id="right"></div>
<script src="{{ url_for('static', filename='js/nipplejs.js') }}" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/axios.min.js') }}" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/vuw_net.js') }}" charset="utf-8"></script>
<script>
/**
* 取元素的百分百大小,返回px
*/
const getSize = function(elem, percent) {
const tem = (elem.clientWidth > elem.clientHeight ? elem.clientHeight : elem.clientWidth);
return parseInt(percent * tem);
}
/**
* 控制转向
*/
const turn = function(direction){
doPost('/turn?direction='+direction, (data) =>{
console.log(data);
})
}
/**
* 控制转向
*/
const move = function(direction){
doPost('/move?direction='+direction, (data) =>{
console.log(data);
})
}
/**
* 左侧摇杆,控制左右方向
*/
const joystickL = nipplejs.create({
zone: document.getElementById('left'),
mode: 'static',
position: {left: '40%', top: '70%'},
color: 'green',
size: getSize(document.body, 0.25)
});
/**
* 前后摇杆,控制前进后退
*/
const joystickR = nipplejs.create({
zone: document.getElementById('right'),
mode: 'static',
position: {left: '60%', top: '70%'},
color: 'red',
size: getSize(document.body, 0.25)
});
joystickL.on('start', function (evt, data) {
{#console.log(data);#}
console.log('开始');
}).on('end', function (evt,data){
console.log('结束');
turn('end')
}).on('move', function (evt, data) {
{#console.log(data);#}
}).on('dir:up plain:up dir:left plain:left dir:down ' +
'plain:down dir:right plain:right',
function (evt, data) {
if(data.direction.x === 'left'){
console.log('左转');
turn('left')
}else if(data.direction.x === 'right'){
console.log('右转');
turn('right')
}else{
console.log('我也不知道往哪里转');
}
}
).on('pressure', function (evt, data) {
{#console.log(evt.type);#}
});
joystickR.on('start', function (evt, data) {
{#console.log(data);#}
console.log('开始');
}).on('end', function (evt,data){
console.log('结束');
move('end')
}).on('move', function (evt, data) {
{#console.log(data);#}
}).on('dir:up plain:up dir:left plain:left dir:down ' +
'plain:down dir:right plain:right',
function (evt, data) {
console.log(data);
if(data.direction.y === 'up'){
console.log('前进');
move('front')
}else if(data.direction.y === 'down'){
console.log('后退');
move('back')
}else{
console.log('我也不知道应该前进还是后退');
}
}
).on('pressure', function (evt, data) {
{#console.log(evt.type);#}
});
</script>
</body>
</html>
后端请求接口,app.py:
from flask import Flask, render_template, json, request
from my_gpio import MyGpio
app = Flask(__name__)
# 转向电机速度,百分比0-100,数值越大转速越快
turn_speed = 10
# 移动电机速度,百分比0-100,数值越大转速越快
move_speed = 30
my_go = MyGpio()
@app.route('/')
def hello_world():
"""
首页
:return:
"""
return render_template("index.html")
@app.route('/turn', methods=['POST'])
def turn_around():
"""
转向
:return:
"""
direction = request.args.get('direction')
print('转向方向:%s' % direction)
if direction == 'left':
my_go.turn_left(turn_speed)
elif direction == 'right':
my_go.turn_right(turn_speed)
else:
my_go.turn_stop()
return json.dumps({'code': 0, 'msg': 'done'}, ensure_ascii=False)
@app.route('/move', methods=['POST'])
def move():
"""
前进后退
:return:
"""
direction = request.args.get('direction')
print("前进后退方向: %s" % direction)
if direction == 'front':
my_go.move_front(move_speed)
elif direction == 'back':
my_go.move_back(move_speed)
else:
my_go.move_stop()
return json.dumps({'code': 0, 'msg': 'done'}, ensure_ascii=False)
if __name__ == '__main__':
app.run()
树莓派控制电机封装:
import RPi.GPIO as GPIO
class MyGpio:
"""
树莓派电机相关操作封装类
"""
def __init__(self):
# 电机A针脚对应
self.PWMA = 18
self.AIN1 = 22
self.AIN2 = 27
# 电机B针脚对应
self.PWMB = 23
self.BIN1 = 25
self.BIN2 = 24 # 该驱动模块调速区间为[0-100]
self.GPIO = GPIO
self.GPIO.setwarnings(False)
self.GPIO.setmode(self.GPIO.BCM)
self.GPIO.setup(self.AIN2, self.GPIO.OUT)
self.GPIO.setup(self.AIN1, self.GPIO.OUT)
self.GPIO.setup(self.PWMA, self.GPIO.OUT)
self.GPIO.setup(self.BIN1, self.GPIO.OUT)
self.GPIO.setup(self.BIN2, self.GPIO.OUT)
self.GPIO.setup(self.PWMB, self.GPIO.OUT)
self.Turn_Motor = self.GPIO.PWM(self.PWMA, 100)
self.Turn_Motor.start(0)
self.Move_Motor = self.GPIO.PWM(self.PWMB, 100)
self.Move_Motor.start(0)
# self.GPIO.cleanup()
def move_front(self, speed):
"""
前进,驱动B电机
:param speed: 转速
:return:
"""
self.Move_Motor.ChangeDutyCycle(speed)
self.GPIO.output(self.BIN2, False)
self.GPIO.output(self.BIN1, True)
def move_back(self, speed):
"""
后退,驱动B电机
:param speed: 转速
:return:
"""
self.Move_Motor.ChangeDutyCycle(speed)
self.GPIO.output(self.BIN2, True)
self.GPIO.output(self.BIN1, False)
def move_stop(self):
"""
停止移动
:return:
"""
self.Move_Motor.ChangeDutyCycle(0)
self.GPIO.output(self.BIN2, False) # BIN2
self.GPIO.output(self.BIN1, False) # BIN1
def turn_left(self, speed):
"""
左转,驱动A电机
:param speed: 转速
:return:
"""
self.Turn_Motor.ChangeDutyCycle(speed)
self.GPIO.output(self.AIN2, False)
self.GPIO.output(self.AIN1, True)
def turn_right(self, speed):
"""
右转,驱动A电机
:param speed: 转速
:return:
"""
self.Turn_Motor.ChangeDutyCycle(speed)
self.GPIO.output(self.AIN2, True)
self.GPIO.output(self.AIN1, False)
def turn_stop(self):
"""
停止转向
:return:
"""
self.Turn_Motor.ChangeDutyCycle(0)
self.GPIO.output(self.AIN2, False) # AIN2
self.GPIO.output(self.AIN1, False) # AIN1
差不多就是这样了,很简单的实现。
目前小车用的转向和移动电机都是直流电机,也没有霍尔传感器,所以暂时也没有涉及到电机的精细控制,就先这样子吧。
后一个阶段应该会接入一些传感器收集驾驶环境的数据,用来做训练模型。
再说吧,有空继续玩。
peace !