树莓派小车教程(三)之——初步实现网页控制小车速度可调(顺序执行)

项目场景:

之前写了一篇手把手树莓派小车教程(二)之——基于Tornado框架的网页控制小车(按键+鼠标点击)。当时只记录了如何通过Tornado框架能让网页控制小车跑起来(以恒定速度),但是项目中小车还是需要变速行驶的。
基于这样的需求,我在之前教程(二) 的基础上,初步实现了网页控制小车速度可调(顺序执行)。


变速方式:

实现小车的变速有多种方法。像之前笔者介绍的L298N驱动模块中有一对pwm控制的引脚,当时买的时候如图一样是用跳线帽连起来的。这种方法(通过PWM控制)也在csdn上搜到了很多教程树莓派 Python GPIO编程控制小车的运动
但这种方法的话还要多设置频率、多引出两条杜邦线,做起来会比较麻烦。
在这里插入图片描述
因此笔者采用了通过 控制高低电平交错输出时间 来达到变速的目的。


变速分析:

之前的代码中每次循环输出的电平都为高电平。所以只要在循环中增加低电平的输出,即可达到速度的减缓效果。且低电平占比越高,速度会越慢。但低电平输出时间不能过大,否则小车会出现边开边卡的现象。
首先定义低电平输出的函数:

#变速
def change(tf):
    GPIO.output(IN1,False)
    GPIO.output(IN2,False)
    GPIO.output(IN3,False)
    GPIO.output(IN4,False)
    time.sleep(tf)
    #GPIO.cleanup()

可以看到所有的输出都为False。若小车需要增加停止行驶按键的话可以直接引用这个函数。


代码引用:

基于变速函数与上一个教程手把手树莓派小车教程(二)之——基于Tornado框架的网页控制小车(按键+鼠标点击)给出的代码。我们可以给出如下的控制代码。
xiaoche.py:

# coding:utf-8
import RPi.GPIO as GPIO
import time
import sys
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.options
from tornado.options import define,options

#GPIO.setmode(GPIO.BOARD)
#端口号定义
define("port",default=8080,help="run on the given port",type=int)

#IO口定义
IN1 = 11
IN2 = 12
IN3 = 13
IN4 = 15

#IO口初始化
def init():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setwarnings(False)
    GPIO.setup(IN1,GPIO.OUT)
    GPIO.setup(IN2,GPIO.OUT)
    GPIO.setup(IN3,GPIO.OUT)
    GPIO.setup(IN4,GPIO.OUT)
#向右
def right(tf):
    GPIO.output(IN1,GPIO.HIGH)
    GPIO.output(IN2,GPIO.LOW)
    GPIO.output(IN3,False)
    GPIO.output(IN4,False)
    time.sleep(tf)
    #GPIO.cleanup()
#向左
def left(tf):
    GPIO.output(IN1,GPIO.LOW)
    GPIO.output(IN2,GPIO.HIGH)
    GPIO.output(IN3,False)
    GPIO.output(IN4,False)
    time.sleep(tf)
    #GPIO.cleanup()
#向前
def before(tf):
    GPIO.output(IN1,False)
    GPIO.output(IN2,False)
    GPIO.output(IN3,GPIO.HIGH)
    GPIO.output(IN4,GPIO.LOW)
    time.sleep(tf)
    #GPIO.cleanup()
#向后
def cabk(tf):
    GPIO.output(IN1,False)
    GPIO.output(IN2,False)
    GPIO.output(IN3,GPIO.LOW)
    GPIO.output(IN4,GPIO.HIGH)
    time.sleep(tf)
    #GPIO.cleanup()
#左上        
def zuoshang(tf):
    GPIO.output(IN1,GPIO.HIGH)
    GPIO.output(IN2,GPIO.LOW)
    GPIO.output(IN3,GPIO.HIGH)
    GPIO.output(IN4,GPIO.LOW)
    time.sleep(tf)
    #GPIO.cleanup()
#右上
def youshang(tf):
    GPIO.output(IN1,GPIO.HIGH)
    GPIO.output(IN2,GPIO.LOW)
    GPIO.output(IN3,GPIO.LOW)
    GPIO.output(IN4,GPIO.HIGH)
    time.sleep(tf)
    #GPIO.cleanup()
#右下
def youxia(tf):
    GPIO.output(IN1,GPIO.LOW)
    GPIO.output(IN2,GPIO.HIGH)
    GPIO.output(IN3,GPIO.LOW)
    GPIO.output(IN4,GPIO.HIGH)
    time.sleep(tf)
    #GPIO.cleanup()
#右上
def zuoxia(tf):
    GPIO.output(IN1,GPIO.LOW)
    GPIO.output(IN2,GPIO.HIGH)
    GPIO.output(IN3,GPIO.HIGH)
    GPIO.output(IN4,GPIO.LOW)
    time.sleep(tf)
    #GPIO.cleanup()
#变速
def change(tf):
    GPIO.output(IN1,False)
    GPIO.output(IN2,False)
    GPIO.output(IN3,False)
    GPIO.output(IN4,False)
    time.sleep(tf)
    #GPIO.cleanup()
    
change_time=0.01# IO输出低电平初始时间
class IndexHandler(tornado.web.RequestHandler):
        def get(self):
                self.render("xiaoche.html")
        def post(self):
                init()
                sleep_time=0.1 # IO输出高电平时间
                global change_time # 引用上面的change_time 若直接在这里定义会导致变量一直更新在0.01 无法变速
                arg=self.get_argument('k')
                if(arg=='w'):
                        before(sleep_time)
                        change(change_time) #通过高低电平交错实现小车的变速
                        #print("1")
                elif(arg=='x'):
                        cabk(sleep_time)
                        change(change_time)
                elif(arg=='a'):
                        left(sleep_time)
                        change(change_time)
                elif(arg=='d'):
                        right(sleep_time)
                        change(change_time)
                elif(arg=='q'):
                        zuoshang(sleep_time)
                        change(change_time)
                elif(arg=='z'):
                        youshang(sleep_time)
                        change(change_time)
                elif(arg=='e'):
                        zuoxia(sleep_time)
                        change(change_time)
                elif(arg=='c'):
                        youxia(sleep_time)
                        change(change_time)
                elif(arg=='j'):
                        if(change_time>0.01):
                            change_time=change_time-0.001;
                elif(arg=='k'):
                        if(change_time<0.03):
                            change_time=change_time+0.001;
                else:
                        return False
                self.write(arg)
if __name__ == '__main__':
        tornado.options.parse_command_line()
        app = tornado.web.Application(handlers=[(r"/",IndexHandler)])
        http_server = tornado.httpserver.HTTPServer(app)
        http_server.listen(options.port)
        print("Demo is runing at 192.168.1.102:8888")
        tornado.ioloop.IOLoop.instance().start()  

对应网页给出的xiaoche.html(与上面代码中render内的名称一样 且代码放同一目录下):

<!DOCTYPE html>
<html>
 <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
        <title>小车</title>
 </head>

 <body>
 <!--keyCode 键盘码 在键盘事件发生的时候 记录对应按的哪个键-->
 <script type="text/javascript">
	function go(k){
     
     
		$.post('/',{
     
     k:k},function(){
     
     });
	}
	$(function(){
     
     
		window.document.onkeydown = abc;
		function abc(ev){
     
     
			ev = (ev) ? ev : window.event;
        // 指定方向键 ,w(上-->87),a(左-->83),s(下-->65),d(右-->67)
                if(ev.keyCode=='87'){
     
     
                        <!-- console.log('w'); -->
                        go('w');
                }
                if(ev.keyCode=='65'){
     
     
                        <!-- console.log('a'); -->
                        go('a');
                }
                if(ev.keyCode=='88'){
     
     
                        <!-- console.log('s'); -->
                        go('x');
                }
                if(ev.keyCode=='68'){
     
     
                        <!-- console.log('d'); -->
                        go('d');
                }
                if(ev.keyCode=='81'){
     
     
                        <!-- console.log('w'); -->
                        go('q');
                }
                if(ev.keyCode=='69'){
     
     
                        <!-- console.log('w'); -->
                        go('e');
                }
                if(ev.keyCode=='90'){
     
     
                        <!-- console.log('w'); -->
                        go('z');
                }
                if(ev.keyCode=='67'){
     
     
                        <!-- console.log('w'); -->
                        go('c');
                }
				if(ev.keyCode=='74'){
     
     
                        <!-- console.log('j'); -->
                        go('j');
                }
				if(ev.keyCode=='75'){
     
     
                        <!-- console.log('k'); -->
                        go('k');
                }
         }

         var i= null;
                $('.before').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('w'); -->
                                go('w');
                        },50);
                });
                $('.left').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('a'); -->
                                go('a');
                        },50);
                });
                $('.cabk').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('x'); -->
                                go('x');
                        },50);
                });
                $('.right').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('d'); -->
                                go('d');
                        },50);
                });
                $('.zuoshang').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('q'); -->
                                go('q');
                        },50);
                });
                $('.youshang').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('e'); -->
                                go('z');
                        },50);
                });
                $('.zuoxia').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('z'); -->
                                go('e');
                        },50);
                });
                $('.youxia').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                 <!-- console.log('c'); -->
                                go('c');
                        },50);
                });
				$('.jiasu').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('j'); -->
                                go('j');
                        },100);
                });
                $('.jiansu').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                 <!-- console.log('k'); -->
                                go('k');
                        },100);
                });
                $('#main span').mouseup(function(){
     
     
                        clearInterval(i);
                });
        });

 </script>


 <style type="text/css">
    #main{
     
     width: 150px;height: 150px;background: #ccc;}
	#main span{
     
     width: 50px;height: 50px;float: left;}
	#main span.on2{
     
     background: #ff00ff;}
	#main span.on3{
     
     background: #555555;position: absolute;left: 8px;top: 8px;}
	#main span.on4{
     
     background: #555555;position: absolute;left: 108px;top: 8px;}
	#main span.on5{
     
     background: #555555;position: absolute;left: 8px;top: 108px;}
	#main span.on6{
     
     background: #555555;position: absolute;left: 108px;top: 108px;}
	#main span.on7{
     
     background: #10e62a;position: absolute;left: 300px;top: 58px;}
	#main span.on8{
     
     background: #f10606;position: absolute;left: 370px;top: 58px;}
 </style>

 <div id="main">	
        <span></span>
        <span class="on2 before"></span>
        <span></span>
        <span class="on2 left"></span>
        <span></span>
        <span class="on2 right"></span>
        <span></span>
        <span class="on2 cabk"></span>
        <span></span>
        <span class="on3 zuoshang"></span>
        <span></span>
        <span class="on4 zuoxia"></span>
        <span></span>
        <span class="on5 youshang"></span>
        <span></span>
        <span class="on6 youxia"></span>
        <span></span>
		<span class="on7 jiasu"></span>
        <span></span>
        <span class="on8 jiansu"></span>
		<span></span>
</div>
</body>
</html>

网页显示内容如下图所示(无标注):
在这里插入图片描述
该网页较之前多了两个按键用来控制加速与减速。对应的键盘按键为j与k。运行python文件后在网页上输入IP+端口号,即可出现如下图所示的结果。
在这里插入图片描述
无论是按键还是鼠标都可以令python文件(2与3版本都可以)出现如下图所示的记录:
在这里插入图片描述

局限:

完成上面这些步骤后,小车基本可以通过按键与鼠标事件来控制小车变速行驶了。但是这种方法按键还不能一起捕捉(鼠标更不用说),所以小车还必须停下后才能变速,导致返回的数据都是单个的,小车只能顺序执行每一个事件,还不能实现同步加减速的效果。

参考:

树莓派4B-Python-控制L298N
树莓派 Python GPIO编程控制小车的运动
手把手树莓派小车教程(一)之——小车跑起来
手把手树莓派小车教程(二)之——基于Tornado框架的网页控制小车(按键+鼠标点击)

总结:

总的来说至少能实现小车变速行驶了,不仅是不用通过PWM的方式,还相对于PWM方式方便了很多。接下来就是实现同步的问题了。希望我也能够尽快实现,出来下一个教程。
感谢各位观看,如有不足,欢迎在评论内留言与讨论。如果觉得写得好的,可以给我点赞+收藏+关注哦,再次感谢各位!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_47390133/article/details/113743300
今日推荐