一、介绍
阅读本篇文章前建议先参考前期文章:
树莓派基础实验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源代码下载