树莓派小车教程(二)之——基于Tornado框架的网页控制小车(按键+鼠标点击)

项目场景:

前两天笔者写了一份手把手树莓派小车教程(一)之——小车跑起来的教程。当时只是让小车能动起来,不过项目中的小车肯定是需要一个用户界面能够操控的。
能看到这一部分的读者们可能基本都会简单的控制小车了。接下来这篇博客我们详细讲解一下如何用网页web端来控制小车运行。


Tornado框架:

笔者对网页控制小车需要用到基于python的异步io框架Tornado。首先需要在树莓派上搭建基于Tornado搭建Web服务(Liunx):

sudo pip install tornado
wget https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz
tar xvzf tornado-4.3.tar.gz
cd tornado-4.3
python setup.py build
sudo python setup.py install

笔者是用的python3环境。为了工程的正常开展,在这里我们同样选择在python3环境下搭建Tornado框架。

sudo apt-get install python3-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)
IN1 = 11
IN2 = 12
IN3 = 13
IN4 = 15

def init():
        GPIO.setmode(GPIO.BOARD)
        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()


class IndexHandler(tornado.web.RequestHandler):
        def get(self):
                self.render("xiaoche.html")
        def post(self):
                init()
                sleep_time=0.1
                arg=self.get_argument('k')
                if(arg=='w'):
                        before(sleep_time)
                        #print("1")
                elif(arg=='x'):
                        cabk(sleep_time)
                elif(arg=='a'):
                        left(sleep_time)
                elif(arg=='d'):
                        right(sleep_time)
                elif(arg=='q'):
                        zuoshang(sleep_time)
                elif(arg=='z'):
                        youshang(sleep_time)
                elif(arg=='e'):
                        zuoxia(sleep_time)
                elif(arg=='c'):
                        youxia(sleep_time)
                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)
        #print("1")
        http_server.listen(options.port)
        print("Demo is runing at 192.168.1.102:8080")
        tornado.ioloop.IOLoop.instance().start()
        #print("1")

可以看到与之前的代码是多了对tornado框架的运用,若想了解该框架原本如何运用,可以参考树莓派4B上 tornado的安装 以及访问传参。可以看到我的代码是要控制8个不同的方向的,需要用到的按键是键盘上绕s一圈的英文字母qweadzxc。中间有部分注释掉的代码是用来调试的。后面有个print(“Demo is runing at 192.168.1.102:8080”)。中间的192.168.1.102是我树莓派连接时的IP地址,后面8080是自己设定的端口号。
接下来是web网页的代码编写。网页文件名称需要和self.render()里面的名称一样。且与python文件放到同一目录下。
xiaoche.html:

<!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');
                }
         }

         var i= null;
                $('.before').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('w'); -->
                                go('w');
                        },40);
                });
                $('.left').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('a'); -->
                                go('a');
                        },40);
                });
                $('.cabk').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('x'); -->
                                go('x');
                        },40);
                });
                $('.right').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('d'); -->
                                go('d');
                        },40);
                });
                $('.zuoshang').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('q'); -->
                                go('q');
                        },40);
                });
                $('.youshang').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('e'); -->
                                go('z');
                        },40);
                });
                $('.zuoxia').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                <!-- console.log('z'); -->
                                go('e');
                        },40);
                });
                $('.youxia').mousedown(function(){
     
     
                        i = setInterval(function(){
     
     
                                 <!-- console.log('c'); -->
                                go('c');
                        },40);
                });
                $('#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;}
 </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>
</div>
</body>
</html>

如下图所示,我的html文件是这个样子的。这里请注意,我现在是直接从如图所示文件目录下打开的xiaoche.html文件。此时的文件不具备控制能力。
在这里插入图片描述
上面的代码中除了定义了这几个方块外,还创立了键盘控制函数、鼠标点击事件函数,go()函数用来接收前面两个函数传来的参数;可以注意到键盘是定义了几个数字,用来对应相应的键盘字母。

$(function(){
		window.document.onkeydown = abc;
		function abc(ev){
			ev = (ev) ? ev : window.event;

寻找字母方法:写到如上图函数的时候。点开html文件。先按键盘F12,在弹出来窗口内找到如下图所示console处。按下任何键盘都会给出相应的数字。记录后即可使用。
在这里插入图片描述
在这里插入图片描述

注意:

最后关于鼠标点击事件上的数字40,与python文件中主函数有的time.sleep(0.1)是对小车接收信号速度的调整。接收信号过多(过快)可能导致小车一直在跑无法停止。过少(过慢)则会边开边卡,尽量自己多测试,取到适合的位置。


运行调试:

起初看教程的时候我以为直接写完代码,运行之后直接打开html文件即可。但仔细查看资料后才发现是需要登录IP+端口号才行,网页如下图所示:
在这里插入图片描述
上图是运行python代码之后用IP+端口号登录的结果,可以看到网页地址与之前的不一样了。此时无论是按键还是点击事件小车都可以做出相应的行为。而且每做一次行为,python运行环境的shell中会多出很多记录:
在这里插入图片描述
出现这样的数据,且小车运行不异常。说明小车基本可以由网页直接控制了。希望读者在看完我的记录后能有启发。也能最终调试出这样的一串记录。

参考:

公开课 树莓派教程
树莓派小车调试记录
20-2 树莓派搭建服务器 Tornado Web服务器
树莓派4B上 tornado的安装 以及访问传参
手把手树莓派小车教程(一)之——小车跑起来
树莓派-网络监控(4)数据交互 基于python异步io框架Tornado

总结:

希望我教程能够帮助到在读的各位。本篇文章还是有些局限性的。比如小车现在是恒定速度行驶的,且现在还是最快速度行驶,遥控起来不免有些急促。所以接下来需要将其改为能够调节速度的网页遥控小车。后面会给大家讲解如何实现。
感谢各位观看,如有不足,欢迎在评论内留言与讨论。如果觉得写得好的,可以给我点赞+收藏+关注哦,再次感谢各位!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_47390133/article/details/113730925