树莓派小车————远程控制

这里所说的远程控制,是指一台PC通过一个界面可以达到控制并监视小车的目的。当然你也可以设计红外遥控,蓝牙等方式。

  • 在设计界面时我选择了python自带的GUI工具————Tkinter。
    选择Tkinter是因为它简单,写完直接运行就行。我们只需要通过VNC或者Windows远程桌面连接到树莓派,运行代码,就可以在PC上控制小车。
    你自己也可以选择HTML来完成。做一个web页面。相关的自己可以去搜索。
  • 控制界面带一个视频传输的接口,在这次我选择了用OpenCV调用树莓派摄像头来实现实时的视频传输。
  • 代码如下:
#coding=utf-8
import RPi.GPIO as GPIO
import time
from Tkinter import *
from PIL import Image,ImageTk
import tkFileDialog as filedialog
import cv2
import threading

#控制界面函数
def ConInterface():
    #播放本地视频的函数
    def playLocalVideo():
        moviePath=filedialog.askopenfilename() #文件对话框,用来打开文件夹,选择文件
        print(moviePath)
        playBtn.place_forget() #隐藏播放按钮
        movie=cv2.VideoCapture(moviePath)
        waitTime= 1000/movie.get(5) #获取每帧需要的时间
        print(waitTime)
        movieTime = (movie.get(7) / movie.get(5))/60 #用视频文件的总帧数除以视频文件的帧速率得到视频的总时长,并换算成分钟
        print(movieTime)
        playSc.config(to=movieTime)
        while movie.isOpened():
            ret,readyFrame=movie.read() #read()返回两个值,ret 表示帧是否为空,readyFrame表示当前帧
            if ret==True:
                movieFrame=cv2.cvtColor(readyFrame,cv2.COLOR_BGR2RGBA) #校正颜色
                newImage=Image.fromarray(movieFrame).resize((675,360)) #调整大小
                newCover=ImageTk.PhotoImage(image=newImage)
                video.configure(image=newCover)  #将图像加入到video标签中
                video.image=newCover
                video.update()
                cv2.waitKey(int(waitTime)) #播放完每帧等待的时间
            else:
                break

    #使用opencv调用树莓派摄像头
    def playVideo():
        playBtn.place_forget()  #点击播放按钮之后开始播放视频,隐藏按钮
        movie=cv2.VideoCapture(0)  #打开摄像头
        movie_fps=movie.get(5)  #得到画面的帧速率
        print(movie_fps)
        waitTime=int(1000/movie_fps)
        print(waitTime)
        while movie.isOpened():
            #读取帧,返回布尔值和当前帧,ret 表示帧是否为空,readyFrame表示当前帧
            ret,readyFrame=movie.read()
            if ret==True:
                #校正图像颜色
                movieFrame=cv2.cvtColor(readyFrame,cv2.COLOR_BGR2RGBA)
                #设置图像大小
                newImage=Image.fromarray(movieFrame).resize((675,360))
                #将照片设置成和tkinter兼容的图像
                newCover=ImageTk.PhotoImage(image=newImage)
                #将图像放入Label中
                video.configure(image=newCover)
                video.image=newCover
                video.update()
                cv2.waitKey(20)
            else:
                break
        movie.release()   #释放资源

    #设置线程执行播放视频程序
    def Thread_playVideo():
        thread_playVideo=threading.Thread(target=playVideo)
        thread_playVideo.start()
                
    
    root=Tk() #初始化tk
    root.title("控制界面")     #设置标题
    root.geometry("1080x720")  #设置窗口大小
    root['bg']="#333333"       #设置窗口背景颜色
    #root.iconbitmap('/home/pi/ZRcode/go.ico')
    root.resizable(width=False,height=False)    #设置窗口长和宽是否可以变化


    #分别设置三个Frame 模块用于存放Label,Button
    videof=Frame(root,height=360,width=675,cursor="cross")
    videof.place(x=199,y=0)

    f1=Frame(root,height=270,width=540,cursor="circle",bg="#333333")
    f1.place(x=269,y=359)

    f2=Frame(root,height=180,width=540,cursor="plus",bg="#333333")
    f2.place(x=269,y=629)
    
    #视频窗口
    movieImage=Image.open('/home/pi/ZRcode/raspberry.jpg').resize((675,360))
    cover=ImageTk.PhotoImage(image=movieImage)
    
    video=Label(videof,width=675,height=360,bd=0,bg="pink",image=cover)
    video.place(x=0,y=0)

    #播放按钮的布局
    iconImag=Image.open('/home/pi/ZRcode/play.ico').resize((32,32))
    icoBtn=ImageTk.PhotoImage(image=iconImag)
    playBtn=Button(videof,image=icoBtn,cursor="hand2",command=Thread_playVideo,relief="groove")
    playBtn.place(x=319,y=159)
    #playSc=Scale(videof,from_=0,to=90,length=675,orient=HORIZONTAL,resolution=0.2,showvalue=0,bd=0,cursor="hand2",troughcolor="white")
    #playSc.place(x=0,y=310)
    
    
    #控制按钮
    up=Button(f1,text="前进",command=lambda:turn_up(20,1),activeforeground="green",activebackground="yellow",height=1,width=4)
    up.place(x=267,y=39)
    left=Button(f1,text="左转",command=lambda:turn_left(20,1),activeforeground="green",activebackground="yellow",height=1,width=4)
    left.place(x=132,y=134)
    right=Button(f1,text="右转",command=lambda:turn_right(20,1),activeforeground="green",activebackground="yellow",height=1,width=4)
    right.place(x=412,y=134)
    back=Button(f1,text="后退",command=lambda:turn_back(20,1),activeforeground="green",activebackground="yellow",height=1,width=4)
    back.place(x=267,y=230)
    stop=Button(f1,text="停止",command=car_stop,activeforeground="green",activebackground="yellow",height=1,width=4)
    stop.place(x=267,y=134)
    xunji=Button(f2,text="循迹",command=Thread_track,activeforeground="green",activebackground="yellow",height=1,width=4)
    xunji.place(x=68,y=44)
    bz=Button(f2,text="避障",command=Thread_bizhang,activeforeground="green",activebackground="yellow",height=1,width=4)
    bz.place(x=461,y=44)
    over=Button(f2,text="OVER",command=Thread_gpio_clean,activeforeground="green",activebackground="yellow",height=1,width=6)
    over.place(x=263,y=44)

    root.mainloop()
  • 为什么要导入threading?
    写完界面运行之后我发现,当你点击一个按钮之后,其他的按钮在程序执行时是不可以点击的。这就存在问题,我们需要在循迹或者避障的同时要摄像头传输视频,所以我们需要将程序设计成多线程的,它们才能并行。当然并行主要是循迹和视频传输,避障和视频传输。循迹和避障当然是不用并行。循迹功能中可以加入避障,但这不属于并发。
  • 导入的PIL和CV2
    这两个都是计算机视觉和图像处理的库。我也只是使用了部分功能,并没有深入了解。
  • 最终运行效果图
    在这里插入图片描述
  • 2
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值