张国平玩树莓派树莓派玩转树莓派

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

2020-08-06  本文已影响0人  Maker张

一、介绍

  阅读本篇文章前建议先参考前期文章:
  树莓派基础实验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状态
上一篇下一篇

猜你喜欢

热点阅读