前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >树莓派综合项目2:智能小车(二)tkinter图形界面控制

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

作者头像
张国平
修改2021-02-26 23:16:32
2.6K0
修改2021-02-26 23:16:32
举报

一、介绍

  阅读本篇文章前建议先参考前期文章:

树莓派基础实验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):

代码语言:txt
复制
#!/usr/bin/python3
 
import tkinter
top = tkinter.Tk()
# 进入消息循环
top.mainloop()

实例(Python2.x):

代码语言:txt
复制
#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import Tkinter
top = Tkinter.Tk()
# 进入消息循环
top.mainloop()

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

(三)创建基本窗口
代码语言:txt
复制
#创建基本窗口

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标签的使用
代码语言:txt
复制
#设置标签的大小和字体
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

代码语言:txt
复制
#标签里插入图片,后面我们会用到按钮里插入图片
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按键的使用
代码语言:txt
复制
#创建一个按钮
#我们先创建一个宽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

代码语言:txt
复制
#为按键添加一个回调函数
#现在我们已经将按钮创建出来了,那么当按钮按下去之后我们需要做些什么呢?这就需要设置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

代码语言:txt
复制
#在按键中放置图片
#有些时候我们需要将界面做的更漂亮一点,我们可以像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滑动条的使用
代码语言:txt
复制
#比如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

代码语言:txt
复制
#绑定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控制控件的边距。

代码语言:txt
复制
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布局我们可以理解成单元格布局方式,窗体就像是一个表格,横向、纵向划分了若干格子,我们将控件依次放入格子中进行定位。

代码语言:txt
复制
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)。本实验中我用的是这种方式。

代码语言:txt
复制
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:

代码语言:txt
复制
#!/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:

代码语言:txt
复制
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状态

这个项目的代码90%是我原创瞎写的,有需要参考的同学可以下载:

树莓派智能小车项目python源代码下载

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、介绍
  • 二、组件
  • 三、实验原理
    • (一)常见的图形开发界面的库
      • (二)tk初始
        • (三)创建基本窗口
          • (四)Label标签的使用
            • (五)Button按键的使用
              • (六)Scale滑动条的使用
                • (七)控件的定位
                • 四、实验步骤
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档