美文网首页张国平玩树莓派树莓派玩转树莓派
树莓派综合项目2:智能小车(二)tkinter图形界面控制

树莓派综合项目2:智能小车(二)tkinter图形界面控制

作者: Maker张 | 来源:发表于2020-08-06 22:09 被阅读0次

    一、介绍

      阅读本篇文章前建议先参考前期文章:
      树莓派基础实验34:L298N模块驱动直流电机实验
      树莓派综合项目2:智能小车(一)四轮驱动

      树莓派综合项目2:智能小车(一)四轮驱动中,实现了代码输入对四个电机的简单控制,本章将使用Python 的图形开发界面的库——Tkinter 模块(Tk 接口),编写本地运行的图形界面,控制小车的前进后退、转向和原地转圈。

      Tkinter是Python的标准GUI库,Python使用Tkinter可以快速的创建 GUI 应用程序。由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。

      其它基础内容会在文集:树莓派基础实验当中讲解。

    二、组件

    ★Raspberry Pi 3主板*1

    ★树莓派电源*1

    ★40P软排线*1

    ★L298N扩展板模块*1

    ★智能小车底板模块*1

    ★减速电机和车轮*4

    ★面包板*1

    ★跳线若干

    三、实验原理

    扩展板供电接法

    (一)常见的图形开发界面的库

      Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下:

      Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里。Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。

      wxPython:wxPython 是一款开源软件,是 Python 语言的一套优秀的 GUI 图形库,允许 Python 程序员很方便的创建完整的、功能健全的 GUI 用户界面。

      PyQt:PyQt 是 Python 编程语言和 Qt 库的成功融合。Qt 本身是一个扩展的 C++ GUI 应用开发框架,Qt 可以在 UNIX、Windows 和 Mac OS X 上完美运行,因此 PyQt 是建立在 Qt 基础上的 Python 包装。所以 PyQt 也能跨平台使用。

    (二)tk初始

      注意:Python3.x 版本使用的库名为 tkinter,即首写字母 T 为小写。

    import tkinter

      创建一个GUI程序

    1、导入 Tkinter 模块
    2、创建控件
    3、指定这个控件的 master, 即这个控件属于哪一个
    4、告诉 GM(geometry manager) 有一个控件产生了。

    实例(Python3.x):

    #!/usr/bin/python3
     
    import tkinter
    top = tkinter.Tk()
    # 进入消息循环
    top.mainloop()
    

    实例(Python2.x):

    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
     
    import Tkinter
    top = Tkinter.Tk()
    # 进入消息循环
    top.mainloop()
    

    以上代码执行结果如下图:


    (三)创建基本窗口

    #创建基本窗口
    
    import tkinter as tk                # 将tkinter导入到工程中
    window = tk.Tk()                    # 创建窗体对象
    window.title('musicplay')           # 设置窗口标题
    window.geometry('380x390')          # 设置窗口大小,注意这里的x是英文字母x
    #如果需要规定窗体打开的位置,可以在在380x390后面加上“+10+10”,
    # 即横坐标为10,纵坐标为10 的位置
    window.resizable(0,0)               # 如果不想人为修改窗体的大小,可以加上这个
    #window.iconbitmap('./logo.ico')     # 设置窗体图标
    #window.withdraw()           # 隐藏窗口
    #window.deiconify()          # 显示窗口
    window.mainloop()                   # 调用mainloop方法,使窗体一直执行下去
    

    以上代码执行结果如下图:


    那么在tkinter中又有哪些控件可以供我们使用呢?


    tkinter控件表

    本实验中只需要学会3种控件:标签控件来显示文字,按钮控件来控制方向,范围控件来控制油门。有点编程基础的同学几个小时就可以学会!


    图形界面

    (四)Label标签的使用

    #设置标签的大小和字体
    import tkinter as tk
    
    window = tk.Tk()
    window.title('Label的使用')
    window.geometry('400x400')
    
    label = tk.Label(window,text='我是一个标签',     #text为显示的文本内容
                     bg='black',fg='white',         #bg为背景色,fg为前景色
                     font=("华文行楷", 20),         #设置字体为“华文行楷”,大小为20
                     width=20,height=3)             #width为标签的宽,height为高
    label.pack()
    window.mainloop()
    

    以上代码执行结果如下图:


    label
    #标签里插入图片,后面我们会用到按钮里插入图片
    import tkinter as tk
    
    window = tk.Tk()
    window.title('Label的使用')
    window.geometry('400x400')
    
    photo = tk.PhotoImage(file='./up.png')      #将图片加载到窗口中
    #注意加载进来的图片只支持‘.gif’格式的图片,如果是其他格式的文件可以用其他工具转换一下,如PS、画图等
    label2 = tk.Label(window,text='我是文字',
                      image=photo,
                      compound='center')        #compound参数是指图片和文字之间的关系
    
    label.pack()
    
    '''
    anchor可用的值:
        left:   图像居左
        right:  图像居右
        top:    图像居上
        bottom: 图像居下
        center: 文字覆盖在图像上
    '''
    window.mainloop()
    

    以上代码执行结果如下图:


    label_grahic

    (五)Button按键的使用

    #创建一个按钮
    #我们先创建一个宽20,长2,显示文字为‘单击’的按钮练练手
    
    import tkinter as tk
    
    window = tk.Tk()
    window.title("button")
    window.geometry("300x180")
    
    tk.Button(window,width=20,height=2,text='单击').pack()
    #如果后面我们需要对这个空间的属性进行修改,或者进行信息的获取,我们可以不指定对象,按键功能我们可以通过command参数实现
    
    window.mainloop()
    

    以上代码执行结果如下图:


    button_1
    #为按键添加一个回调函数
    #现在我们已经将按钮创建出来了,那么当按钮按下去之后我们需要做些什么呢?这就需要设置command属性,添加回调函数了
    
    import tkinter as tk
    
    window = tk.Tk()
    window.title("button")
    window.geometry("300x180")
    
    def danji():        #这个就是我们写的一个方法,下面由按钮进行调用
        print('hello')  #当按键按下时,打印‘hello’
    
    tk.Button(window,width=20,height=2,text='单击',command=danji).pack()
    #注意,在设置command属性的时候,回调函数是不加'()'的,我们一般调用方法是需要,但这里就是设置属性,不需要添加
    
    window.mainloop()
    

    以上代码执行结果如下图:


    button_2
    #在按键中放置图片
    #有些时候我们需要将界面做的更漂亮一点,我们可以像label一样,用图片来美化我们的按钮
    
    import tkinter as tk
    
    window = tk.Tk()
    
    photo = tk.PhotoImage(file='./up.png')
    tk.Button(window, text='botton', compound='bottom', image=photo).pack()
    tk.Button(window, text='top', compound='top', bitmap='error').pack()
    #设置的相关属性和Label类似,故这里就不做赘述了
    
    window.mainloop()
    

    以上代码执行结果如下图:


    button_3

    (六)Scale滑动条的使用

    #比如Windows下的音量控制,音乐或者视频的进度控制,
    #都是用滑动条来实现的,本实验中用来控制油门
    
    from tkinter import *
    
    window = Tk()
    
    Scale(window,label='accelerator',   #设置显示的标签
          from_=0,to=100,       # 设置最大最小值
          #注意设置最大值的属性不是'from',而是'from_',这是因为python中已经有了from关键字啦
          resolution=1,         # 设置步距值
          orient=HORIZONTAL,    # 设置水平方向
          #如果我们想设置成垂直方向改怎么办呢?直接缺省这个属性就可以啦,默认就是垂直哒
          ).pack()
    
    window.mainloop()
    

    以上代码执行结果如下图:


    scale_1
    #绑定Scale的值为我们所用
    
    from tkinter import *
    
    window = Tk()
    
    value = StringVar()
    def s_print(text):      #注意,Scale的回调函数需要给定形参,当触发时会将Scale的值传给函数
        print(value.get())
        print(text)         #两者同样的效果
    Scale(window,label='accelerator',
          from_=0,to=100,
          resolution=1,show=0,
          variable=value,command=s_print
          ).pack()
    
    window.mainloop()
    

    以上代码执行结果如下图:


    scale_2

    (七)控件的定位

    通过前面的文档我们已经知道Tkinter控件的简单使用,想要拥有一个简洁、合理的界面,控件布局就显得尤为重要了,而Tkinter提供了三种布局方式给我们。
    1.pack是一种相对布局方式,指定控件的相对位置,精确位置会由系统完成。

    pack布局没有任何属性参数,默认会自上而下垂直并且水平居中排列。我们可以通过side=TOP/BOTTOM/LEFT/RIGHT,控制控件的相对位置(上下左右),利用fill=x来是控件和窗体一样宽,用padx、pady、ipadx、ipady控制控件的边距。

    from tkinter import *
     
    window = Tk()
     
    Label(window,text='first',bg='red').pack(fill=X,padx=10)            #水平外边距
    Label(window,text='second',bg='green').pack(fill=X,pady=10)         #垂直外边距
    Label(window,text='third',bg='yellow').pack(fill=X,ipadx=10)        #水平内边距
    Button(window,text='fourth',bg='blue').pack(fill=X,ipady=10)        #垂直内边距
     
    window.mainloop()
    
    pack方式布局

    2.grid布局我们可以理解成单元格布局方式,窗体就像是一个表格,横向、纵向划分了若干格子,我们将控件依次放入格子中进行定位。

    from tkinter import *
     
    window = Tk()
     
    Label(window,text='first',bg='red').grid(row=1,column=1)
    Label(window,text='second',bg='green').grid(row=1,column=3)
    Label(window,text='third',bg='yellow').grid(row=2,column=2)
    Button(window,text='fourth',bg='blue').grid(row=3,column=1)
     
    window.mainloop()
    
    grid布局方式

    3.place布局是一种绝对位置布局方式,说的简单点就是坐标定位方式,窗体最左上角的位置就是原点(x=0,y=0)。本实验中我用的是这种方式。

    from tkinter import *
     
    window = Tk()
     
    Label(window,text='first',bg='red').place(x=10,y=10)
    Label(window,text='second',bg='green').place(x=10,y=40)
    Label(window,text='third',bg='yellow').place(x=10,y=70)
    Button(window,text='fourth',bg='blue').place(x=10,y=100)
     
    window.mainloop()
    
    place布局方式

    四、实验步骤

      第1步: 连接电路。与树莓派综合项目2:智能小车(一)四轮驱动中的接线相同。

    树莓派(name) 树莓派(BOARD) L298N小车扩展板
    GPIO.0 11 ENA
    GPIO.2 13 IN1
    GPIO.3 15 IN2
    GPIO.1 12 ENB
    GPIO.4 16 IN3
    GPIO.5 18 IN4
    GND GND 电池组供电负极

    关于这里树莓派GND、L298N小车扩展板的电池组供电负极相连,是特殊情况下的情况,经测试发现:
    如果树莓派用的是充电头供电,而L298N扩展板用的是电池组供电,这两个负极必须相连,否则马达不动。
    如果树莓派用的是L298N扩展板接出来的5V供电,即两者同一个电源,则这里不用连接。

    L298N小车扩展板 电池组 树莓派 电压表头 马达
    电池+(-) 电池+(-)
    5V供电 电源接口
    +(-) +(-)
    T1(L后) +(-)
    T2(L前) +(-)
    T3(R前) +(-)
    T4(R后) +(-)

    刚开始时使用了面包板接线,GPIO使用的BCM模式,后来为了方便路面移动测试,让树莓派使用了多功能L298N智能小车扩展板上的5V供电,并且GPIO改用了BOARD模式。

    智能小车四轮驱动电路图 扩展板供电接法1

      第2步: 编写电机的驱动程序,文件名为motor_4w.py。与树莓派综合项目2:智能小车(一)四轮驱动中的程序完全相同。

      该车的行进控制与履带车的行进控制类似:

    前进和后退很简单,左右两边的方向都朝前或朝后,速度一致;
    原地顺时针旋转时,左边轮子前进,右边轮子后退,速度一致;
    原地逆时针旋转时,左边轮子后退,右边轮子前进,速度一致;
    偏左前进时,左右两边的方向都朝前,左轮速度比右轮速度慢一点;
    偏右前进时,左右两边的方向都朝前,左轮速度比右轮速度快一点;
    偏左后退时,左右两边的方向都朝后,左轮速度比右轮速度慢一点;
    偏右后退时,左右两边的方向都朝后,左轮速度比右轮速度快一点;

    motor_4w.py:

    #!/usr/bin/env python
    import RPi.GPIO as GPIO
    
    class SMPcar:
        '''控制小车四轮动作的类'''
        ENA = 11  #使能信号A,左边两轮
        IN1 = 13  #信号输入1
        IN2 = 15  #信号输入2
        ENB = 12  #使能信号B,右边两轮
        IN3 = 16  #信号输入3
        IN4 = 18  #信号输入4
    
        GPIO.setwarnings(False) #关闭警告
    
        def setGPIO(self):
            '''初始化引脚'''
            GPIO.setmode(GPIO.BOARD)
            GPIO.setup(SMPcar.ENA, GPIO.OUT)
            GPIO.setup(SMPcar.IN1, GPIO.OUT)
            GPIO.setup(SMPcar.IN2, GPIO.OUT)
            
            GPIO.setup(SMPcar.ENB, GPIO.OUT)
            GPIO.setup(SMPcar.IN3, GPIO.OUT)
            GPIO.setup(SMPcar.IN4, GPIO.OUT)
        
        def pwm(self,pwm): 
            '''初始化PWM(脉宽调制),返回PWM对象'''
            EN_pwm = GPIO.PWM(pwm, 500)
            EN_pwm.start(0)
            return EN_pwm
    
        def changespeed(self,pwm,speed):
            '''通过脉宽调制改变占空比改变马达转速'''
            pwm.ChangeDutyCycle(speed)
        
        def clockwise(self,in1_pin,in2_pin):
            '''马达顺时针转的信号
          若电机旋转方向不正确,交换电机的正负极'''
            GPIO.output(in1_pin, 1)
            GPIO.output(in2_pin, 0)
     
        def counter_clockwise(self,in1_pin,in2_pin):
            '''马达逆时针转的信号'''
            GPIO.output(in1_pin, 0)
            GPIO.output(in2_pin, 1)
        
        def stop_car(self,in1_pin,in2_pin):
            '''马达制动的信号
           使能信号为低电平,或者高电平(占空比设为100,
           IN1和IN2都为0或1时)马达制动'''
            GPIO.output(in1_pin, 0)
            GPIO.output(in2_pin, 0)
         
            
        def destroy(self,A,B):
            '''结束程序时清空GPIO状态,
            若不清空状态,再次运行时会有警告'''
            A.stop()
            B.stop()
            GPIO.cleanup()    # Release resource
    
    
    if __name__ == '__main__':     # Program start from here
    
        try:
            smpcar = SMPcar() #创建树莓派小车对象
            smpcar.setGPIO()  #初始化引脚
    
            ENA_pwm=smpcar.pwm(smpcar.ENA) #初始化使能信号PWM,ENA为左边车轮
            ENB_pwm=smpcar.pwm(smpcar.ENB) #初始化使能信号PWM,ENB为右边车轮
            
            while True:
                '''通过输入的命令改变马达转动
    这里是考虑到后期,远程控制也是发送控制代码实现控制,
    这里采用这种方式也很方便'''
                cmd = input("Command, E.g. ff30ff30 :")
                direction = cmd[0] #只输入字母b时,小车刹车
                A_direction = cmd[0:2] #字符串0/1两位为控制A(左边车轮)方向信号
                B_direction = cmd[4:6] #4/5位为控制B(右边车轮)方向信号
            
                A_speed = cmd[2:4] #字符串2/3两位为控制A(左边车轮占空比)速度信号
                B_speed = cmd[6:8] #字符串6/7两位为控制B(右边车轮占空比)速度信号
                print (A_direction,B_direction,A_speed,B_speed) #测试用
            
                if A_direction == "ff": #控制A(左边车轮)顺时针信号
                    smpcar.clockwise(smpcar.IN1,smpcar.IN2)
                if A_direction == "00": #控制A(左边车轮)逆时针信号
                    smpcar.counter_clockwise(smpcar.IN1,smpcar.IN2)
                if B_direction == "ff": #控制B(右边车轮)顺时针信号
                    smpcar.clockwise(smpcar.IN3,smpcar.IN4)
                if B_direction == "00": #控制B(右边车轮)逆时针信号
                    smpcar.counter_clockwise(smpcar.IN3,smpcar.IN4)
    
                if direction == "b": #小车刹车,IN1和IN2都为0,马达制动
                    smpcar.stop_car(smpcar.IN1,smpcar.IN2)
                    smpcar.stop_car(smpcar.IN3,smpcar.IN4)
                    continue #跳出本次循环
    
                # 通过输入的两位数字设置占空比,改变马达转速
                smpcar.changespeed(ENA_pwm,int(A_speed))
                smpcar.changespeed(ENB_pwm,int(B_speed))
    
        except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
            smpcar.destroy(ENA_pwm,ENB_pwm)
        finally:
            smpcar.destroy(ENA_pwm,ENB_pwm)
    
    

      第3步: 编写图形控制界面,文件名为gui_motor_4w.py。界面控件一个个的添加和调试,每个控件的回调函数一个个调试,最终全部成功。先点击方向按钮,再滑动油门,小车行进;也可以先设定好油门,再点击方向按钮,小车行进。将这两个文件放进一个文件夹,只运行gui_motor_4w.py即可。

    图形界面

    上中和下中按钮为前进和后退,中左和中右为原地左转和原地右转,四个角上的按钮为向左、向右、向左后、向右后偏向行进,正中间的黑色暂停按钮为刹车和方向复位键。

    gui_motor_4w.py:

    from tkinter import *   # 将tkinter导入到工程中
    import motor_4w
    
    '''acc_left为左边车轮油门的中间参数,
       用于转向时,减低左轮的油门值,形成左右速差'''
    acc_left = 0
    acc_right = 0 #右边车轮油门的中间参数
    
    smpcar = motor_4w.SMPcar()
    smpcar.setGPIO() #初始化引脚
    
    ENA_pwm=smpcar.pwm(smpcar.ENA) #初始化PWM(脉宽调制)
    ENB_pwm=smpcar.pwm(smpcar.ENB)
    
    root = Tk() # 创建窗体对象
    root.wm_title('4w_motor Control') # 设置窗口标题
    
    curWidth = 1050 #窗口宽度
    curHight = 450 #窗口度
    
    # 获取屏幕宽度和高度
    scn_w, scn_h = root.maxsize()
    #print(scn_w, scn_h)
    
    # 计算中心坐标
    cen_x = (scn_w - curWidth) / 2
    cen_y = (scn_h - curHight) / 2
    #print(cen_x, cen_y)
    
    # 设置窗口初始大小和位置
    size_xy = '%dx%d+%d+%d' % (curWidth, curHight, cen_x, cen_y) # 注意这里的x是英文字母x
    root.geometry(size_xy) # 设置窗口大小
    
    def leftTurn():
        '''原地左转弯'''
        acc_value = scale_accelerator.get() #获取油门值
        
        smpcar.counter_clockwise(smpcar.IN1,smpcar.IN2) #左边车轮后退
        smpcar.clockwise(smpcar.IN3,smpcar.IN4) #右边车轮前进
        
        smpcar.changespeed(ENA_pwm,(acc_value)) #根据刚获取的油门值调整速度
        smpcar.changespeed(ENB_pwm,(acc_value))
            
    def rightTurn():
        '''原地右转弯'''
        acc_value = scale_accelerator.get()
        
        smpcar.clockwise(smpcar.IN1,smpcar.IN2)
        smpcar.counter_clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,(acc_value))
        smpcar.changespeed(ENB_pwm,(acc_value))
        
    def forward():
        '''直线前进'''
        acc_value = scale_accelerator.get()
        
        smpcar.clockwise(smpcar.IN1,smpcar.IN2)
        smpcar.clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,(acc_value))
        smpcar.changespeed(ENB_pwm,(acc_value))
            
    def reverse():
        '''直线后退'''
        acc_value = scale_accelerator.get()
        
        smpcar.counter_clockwise(smpcar.IN1,smpcar.IN2)
        smpcar.counter_clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,(acc_value))
        smpcar.changespeed(ENB_pwm,(acc_value))
        
    def brake():
        '''刹车'''
        smpcar.stop_car(smpcar.IN1,smpcar.IN2)
        smpcar.stop_car(smpcar.IN3,smpcar.IN4)
        global acc_left
        global acc_right
        acc_left = 0 #左边车轮油门清零
        acc_right = 0 #右边车轮油门清零
    
    '''定义前进、后退、原地左转、原地右转、刹车插图的对象'''
    up_im = PhotoImage(file='./up.png')
    down_im = PhotoImage(file='./down.png')
    left_im = PhotoImage(file='./left.png')
    right_im = PhotoImage(file='./right.png')
    brake_im = PhotoImage(file='./brake.png')
    
    '''定义按钮'''
    Button(root, text='forward',bd=10,image=up_im,command=forward).place(x=230,y=70) #定义前进按钮
    Button(root, text='reverse',bd=10,image=down_im,command=reverse).place(x=230,y=330) #定义后退按钮
    Button(root, text='left',bd=10,image=left_im,command=leftTurn).place(x=110,y=200) #定义原地左转按钮
    Button(root, text='right',bd=10,image=right_im,command=rightTurn).place(x=350,y=200) #定义原地右转按钮
    Button(root, text='brake',bd=10,image=brake_im,command=brake).place(x=230,y=200) #定义刹车按钮
    
    a=0
    '''a为中间参数,用于左前和左后按钮切换时,清零参数acc_left'''
    def forward_left():
        '''朝左前方转向行进'''
        global a
        global acc_left
        if a == 0: #表明调用该函数前,已点击了 左后 按钮
            acc_left = 0 #清零参数acc_left
        a += 1 #点击 左前 按钮后,a会一定大于0
        acc_value = scale_accelerator.get() #获取油门值
    
        '''forward_left()函数被调用一次,参数acc_left累减5'''
        
        acc_left -= 5
        global acc_right
        acc_right = 0 #左转时右轮参数acc_right清零
    
        '''左轮的实际油门+参数acc_left得到左轮油门降低
           而右轮不变的情况下,左轮慢,右轮快,车向左转向前进'''
        acc_value_left = acc_value + acc_left
        if acc_value_left < 0: #防止点左转次数过多
            acc_value_left = 0
            
        smpcar.clockwise(smpcar.IN1,smpcar.IN2) #车轮方向都向前行进
        smpcar.clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,acc_value_left)
        smpcar.changespeed(ENB_pwm,acc_value)
    b=0
    '''b为中间参数,用于右前和右后按钮切换时,清零参数acc_right'''
    def forward_right():
        '''朝右前方转向行进'''
        global b
        global acc_right
        if b == 0: #表明调用该函数前,已点击了 右后 按钮
            acc_right = 0 #清零参数acc_right
        b += 1 #点击 右前 按钮时,b会一定大于0
        acc_value = scale_accelerator.get() #获取油门值
        '''forward_right()函数被调用一次,参数acc_right累减5'''
        
        acc_right -= 5
        global acc_left
        acc_left = 0 #右转时左轮参数acc_left清零
    
        '''右轮的实际油门+参数acc_right得到右轮油门降低
            而左轮不变的情况下,左轮快,右轮慢,车向右转向前进'''
        acc_value_right = acc_value + acc_right
        if acc_value_right < 0:
            acc_value_right = 0
            
        smpcar.clockwise(smpcar.IN1,smpcar.IN2)
        smpcar.clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,acc_value)
        smpcar.changespeed(ENB_pwm,acc_value_right)
    
    def reverse_left():
        '''朝左后方转向倒车'''
        global a
        global acc_left
        if a > 0: #表明调用该函数前,点击了 左前 按钮
            acc_left = 0 #清零参数acc_left
        a *= 0 #每点击 左后 按钮a就会置0
            
        acc_value = scale_accelerator.get()
        
        
        acc_left -= 5
        global acc_right
        acc_right = 0
        
        acc_value_left = acc_value + acc_left
        if acc_value_left < 0:
            acc_value_left = 0
            
        smpcar.counter_clockwise(smpcar.IN1,smpcar.IN2)
        smpcar.counter_clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,acc_value_left)
        smpcar.changespeed(ENB_pwm,acc_value)
        
    def reverse_right():
        '''朝右后方转向倒车'''
        global b
        global acc_right
        if b > 0: #表明调用该函数前,点击了 右前 按钮
            acc_right = 0 #清零参数acc_right
        b *= 0 #每点击 右后 按钮b就会置0
        acc_value = scale_accelerator.get()
        
       
        acc_right -= 5
        global acc_left
        acc_left = 0
        
        acc_value_right = acc_value + acc_right
        if acc_value_right < 0:
            acc_value_right = 0
            
        smpcar.counter_clockwise(smpcar.IN1,smpcar.IN2)
        smpcar.counter_clockwise(smpcar.IN3,smpcar.IN4)
        
        smpcar.changespeed(ENA_pwm,acc_value)
        smpcar.changespeed(ENB_pwm,acc_value_right)
    
    '''定义左前、右前、左后、右后行进插图的对象'''
    up_left_im = PhotoImage(file='./up_left.png')
    up_right_im = PhotoImage(file='./up_right.png')
    down_left_im = PhotoImage(file='./down_left.png')
    down_right_im = PhotoImage(file='./down_right.png')
    
    Button(root, text='up_left',bd=10,image=up_left_im,command=forward_left).place(x=110,y=70) #定义向前偏左行进按钮
    Button(root, text='up_right',bd=10,image=up_right_im,command=forward_right).place(x=350,y=70) #定义向前偏右行进按钮
    Button(root, text='down_left',bd=10,image=down_left_im,command=reverse_left).place(x=110,y=330) #定义向后偏左行进按钮
    Button(root, text='down_right',bd=10,image=down_right_im,command=reverse_right).place(x=350,y=330) #定义向后偏右行进按钮
    
    '''定义标签'''
    label1 = Label(root,
                   text='Accelerator',
                   #bg='black',
                   fg='red',
                   font=("华文行楷", 20),          #设置字体为“华文行楷”,大小为20
                   #width=9,height=3
                   )
    label1.place(x=740,y=390)
    
    '''根据scale滑动条的值,调整油门大小'''
    def accelerator(v):
        
        acc_value = int(v)
        global acc_left
        global acc_right
        
        acc_value_left = acc_value + acc_left #加上中间参数
        acc_value_right = acc_value + acc_right
        
        if acc_value_left < 0:
            acc_value_left = 0
        if acc_value_right < 0:
            acc_value_right = 0
            
        smpcar.changespeed(ENA_pwm,acc_value_left)
        smpcar.changespeed(ENB_pwm,acc_value_right)
    
    '''定义scale滑动条'''
    scale_accelerator = Scale(root,
        #label='accelerator', # 设置显示的标签
        from_=100, # 设置最大最小值 
        to=0,
        resolution=2, # 设置步距值
        orient=VERTICAL,   #如果我们想设置成垂直方向改怎么办呢?直接缺省这个属性就可以啦,默认就是垂直
        #show=0,    # 隐藏滑动条的值
        #variable=value_a, # 绑定Scale的值为我们所用
        activebackground='red',
        length=350,
        width=30, # 设置Scale的宽度,默认是16。
        sliderlength=50, # 滑块的大小。默认值是30
        bd=10, # 设置Scale控件边框宽度
        tickinterval=20, # 显示刻度,并定义刻度的粒度
        troughcolor='red', # 设置滑动槽的背景颜色
        command=accelerator
                          )
    scale_accelerator.place(x=720,y=0)
    
    root.mainloop()
    
    smpcar.destroy(ENA_pwm,ENB_pwm) #退出程序时,清空GPIO状态
    

    相关文章

      网友评论

        本文标题:树莓派综合项目2:智能小车(二)tkinter图形界面控制

        本文链接:https://www.haomeiwen.com/subject/xogwrktx.html