记Tkinter制作的飞机仪表控件

前言

最近在做基于公网通信的遥控固定翼。飞机、控制端、服务器都用Python开发。之前没有做过GUI项目,所以搭建了PyQt,尝试发现designer里提供的一些控件都不适用,所以还是需要手写代码。Tkinter之前做过一些相关的练习,所以最终选择了用Tkinter来做控制端的UI。

目标

控制端也跑在树莓派上(因为油门杆、侧杆、AP旋钮什么的用旋转编码器的好接)

使用单屏幕,长宽比约为16:9的样子。整个屏幕分为:

  • Video 图传的显示

  • PFD(primary flight display):有姿态仪(飞机上的三轴陀螺仪)、空速表(准备做个皮托管,还没做)、高度表(气压计)、磁航向(电子罗盘)、无线电高度显示(肚子下面放一个TOF传感器)

  • EWD(Engine and warning display) 显示电涵的转速(来自霍尔传感器)、功率百分比(给电调的PWM的脉宽)、电池电压(电压计)、升降舵 方向舵 副翼(没做flaps)的位置(由于控制端的侧杆、油门杆和舵没做随动设计,autopilot engaged之后机师需要知道这些飞机上器件的位置状态)

  • 一个显示起落架灯的面板 (三个灯)

  • ND(navigation display):机载的4G模块带GPS 所以有GPS导航 (后期或许为加一个用三轴加速计的惯导玩玩)

  • ECAM(Airbus的叫法):一个以命令行输出信息和输入指令的地方

大概是这样:
记Tkinter制作的飞机仪表控件_第1张图片
(之前画的 和实现代码的样子有出入)

实现

图传

个人不喜欢HUD的感觉 所以用numpy+opencv解码收到的数据然后显示在canvas上

PFD

大概长这样

记Tkinter制作的飞机仪表控件_第2张图片

姿态仪

在这张图片
记Tkinter制作的飞机仪表控件_第3张图片
中用opencv旋转bank angle度后根据attack angle选定裁取中心的坐标(注意坐标转换)裁取一个正方形 画在canvas上

【还没做 之后补】

空速表、高度表

from tkinter import *
from time import sleep
from threading import Thread

class rollBar:
    def __init__(self, master, width, height, LoR):
        self.LoR = LoR
        self.frame = Frame(master = master, width = width, height = height, bg = "black")
        self.frame.pack()
        self.canvas = Canvas(self.frame, width = width, height = height, bg = "grey", bd = 0, highlightthickness = 0)
        self.canvas.pack()
        self.width = width
        self.height = height
        self.div_len = height / 4
        self.lines = []
        self.numbers = []
        if LoR == "L":
            self.canvas.create_rectangle(10, int(self.height / 2) + 6, self.width - 1, int(self.height / 2) - 6, outline = "white", fill = "black")
        elif LoR == "R":
            self.canvas.create_rectangle(0, int(self.height / 2) + 6, self.width - 11, int(self.height / 2) - 6, outline = "white", fill = "black")

    def turn_on(self, div):
        self.div = div
        if self.LoR == "L":
            self.canvas.create_polygon(10, int(self.height / 2) + 6, 10, int(self.height / 2) - 6, 0, int(self.height / 2), fill = "white")
        elif self.LoR == "R":
            self.canvas.create_polygon(self.width - 11, int(self.height / 2) + 6, self.width - 11, int(self.height / 2) - 6, self.width - 1, int(self.height / 2), fill = "white")
        self.change_to(0)
        

    def change_to(self, val):
        # del lines and numbers
        for line in self.lines:
            self.canvas.delete(line)
        self.lines = []
        for number in self.numbers:
            self.canvas.delete(number)
        self.lines = []

        # draw lines and numbers
        delta_h = (val % self.div) * (self.div_len / self.div)
        y = int(self.height / 2 + delta_h)
        y_val = val - (val % self.div)

        delta_y = 0
        delta_y_val = 0

        if self.LoR == "L":
            while delta_y + y < self.height:
                self.lines.append(self.canvas.create_line((0, y + delta_y), (int(self.width / 2), y + delta_y), fill = "white", width = 2))
                self.numbers.append(self.canvas.create_text(self.width * 0.75, y + delta_y, text = str(y_val - delta_y_val), fill = "white", font=("Menlo", int(self.width / 5))))
                dd_y = 0
                while delta_y + y + dd_y < self.height and dd_y < self.div_len:
                    self.lines.append(self.canvas.create_line((0, y + delta_y + dd_y), (int(self.width / 4), y + delta_y + dd_y), fill = "white", width = 1))
                    dd_y += int(self.div_len / 5)
                delta_y += self.div_len
                delta_y_val += self.div

            delta_y = 0
            # delta_y = self.div_len
            delta_y_val = 0
            # delta_y_val = self.div

            while y - delta_y >= 0:
                self.lines.append(self.canvas.create_line((0, y - delta_y), (int(self.width / 2), y - delta_y), fill = "white", width = 2))
                self.numbers.append(self.canvas.create_text(int(self.width * 0.75), y - delta_y, text = str(y_val + delta_y_val), fill = "white", font=("Menlo", int(self.width / 5))))
                dd_y = 0
                while y - delta_y - dd_y >= 0 and dd_y < self.div_len:
                    self.lines.append(self.canvas.create_line((0, y - delta_y - dd_y), (int(self.width / 4), y - delta_y - dd_y), fill = "white", width = 1))
                    dd_y += int(self.div_len / 5)
                delta_y += self.div_len
                delta_y_val += self.div
            
            self.canvas.create_rectangle(10, int(self.height / 2) + 6, self.width - 1, int(self.height / 2) - 6, outline = "white", fill = "black")
            self.canvas.create_text(int((self.width - 10) / 2) + 10, int(self.height / 2), text = str(val), fill = "white", font=("Menlo", int(self.width / 5 + 1)))
            self.canvas.pack()

        elif self.LoR == "R":

            while delta_y + y < self.height:
                self.lines.append(self.canvas.create_line((self.width - 1, y + delta_y), (int(self.width / 2), y + delta_y), fill = "white", width = 2))
                self.numbers.append(self.canvas.create_text(self.width * 0.25, y + delta_y, text = str(y_val - delta_y_val), fill = "white", font=("Menlo", int(self.width / 5))))
                dd_y = 0
                while delta_y + y + dd_y < self.height and dd_y < self.div_len:
                    self.lines.append(self.canvas.create_line((self.width - 1, y + delta_y + dd_y), (int(self.width / 4 * 3), y + delta_y + dd_y), fill = "white", width = 1))
                    dd_y += int(self.div_len / 5)
                delta_y += self.div_len
                delta_y_val += self.div

            delta_y = 0
            # delta_y = self.div_len
            delta_y_val = 0
            # delta_y_val = self.div

            while y - delta_y >= 0:
                self.lines.append(self.canvas.create_line((self.width - 1, y - delta_y), (int(self.width / 2), y - delta_y), fill = "white", width = 2))
                self.numbers.append(self.canvas.create_text(int(self.width * 0.25), y - delta_y, text = str(y_val + delta_y_val), fill = "white", font=("Menlo", int(self.width / 5))))
                dd_y = 0
                while y - delta_y - dd_y >= 0 and dd_y < self.div_len:
                    self.lines.append(self.canvas.create_line((self.width - 1, y - delta_y - dd_y), (int(self.width / 4 * 3), y - delta_y - dd_y), fill = "white", width = 1))
                    dd_y += int(self.div_len / 5)
                delta_y += self.div_len
                delta_y_val += self.div
            
            self.canvas.create_rectangle(0, int(self.height / 2) + 6, self.width - 11, int(self.height / 2) - 6, outline = "white", fill = "black")
            self.canvas.create_text(int((self.width - 10) / 2) + 10, int(self.height / 2), text = str(val), fill = "white", font=("Menlo", int(self.width / 5 + 1)))
            self.canvas.pack()            

        

if __name__ == "__main__":
    root = Tk()
    root.geometry("50x300")
    R = rollBar(root, 50, 300, "R")
    def c_c():
        sleep(1)
        R.turn_on(100)
        for i in range(500):
            R.change_to(i)
            sleep(0.01)
    t = Thread(target = c_c, args = ())
    t.start()
    root.mainloop()

效果:
记Tkinter制作的飞机仪表控件_第4张图片

磁航向、下降率表什么的之后做

EWD

转速表、功率表

from math import sin, cos, pi

from threading import Thread
from time import sleep
from tkinter import *
class Engine:
    def __init__(self, master, length, pack_side):
        self.length = length
        self.frame = Frame(master = master, width = length, height = length, bg = "black")
        
        self.arc = Canvas(self.frame, width = length, height = length, bg = "black", bd = 0, highlightthickness = 0)
        self.arc.create_arc(5, 5, length - 5, length - 5, start = 0, extent = 225, style = ARC, outline = "white", width = 2)
        self.arc.create_rectangle(0.5 * length, 0.6 * length, 0.9 * length, 0.9 * length, outline = "white", width = 2)
        self.arc.pack()
        self.frame.pack(side = pack_side, fill = "both")
        self.r = length / 2 - 5
        self.center = (int(length / 2), int(length / 2))


    def turn_on(self, val_min, val_max):
        self.val = 0
        self.val_max = val_max
        self.val_min = val_min
        self.text_color = "green"
        self.arc.create_text(0.25 * self.length, 0.8 * self.length, text = str(val_min), fill = "white", font=("Menlo", int(self.length / 15)))
        self.arc.create_text(0.9 * self.length, 0.55 * self.length, text = str(val_max), fill = "white", font=("Menlo", int(self.length / 15)))
        # self.text = self.arc.create_text(0.75 * self.length, 0.8 * self.length, text = str(self.val), fill = self.text_color)
        self.text = self.arc.create_text(0.7 * self.length, 0.75 * self.length, text = "", fill = self.text_color, font = ("Menlo", int(self.length / 15)))
        self.pointer = self.arc.create_line(self.center, (self._val2pos(0)[0] + self.center[0], self.length - (self._val2pos(0)[1] + self.center[1])), fill = "green", width = 3)
        self.arc.pack()

    def change_to(self, val):

        self.val = val
        self.arc.coords(self.pointer, self.center[0], self.center[1], self._val2pos(val)[0] + self.center[0], self.length - (self._val2pos(val)[1] + self.center[1]))
        self.arc.itemconfig(self.text, text = str(val))
        self.arc.pack()

    def _val2pos(self, val):
        return (
            int(cos((self.val_max - val) / (self.val_max - self.val_min) * (5/4) * pi) * self.r),
            int(sin((self.val_max - val) / (self.val_max - self.val_min) * (5/4) * pi) * self.r)
        )

if __name__ == "__main__":
    print(__name__)
    root = Tk()
    root.geometry("800x400")
    root.configure(bg = "black")
    E_1 = Engine(root, 400, "left")
    E_2 = Engine(root, 400, "right")
    def turn_on():
        sleep(5)
        E_1.turn_on(0, 100)
        for i in range(0, 101):
            E_1.change_to(i)
            sleep(0.01)
    t = Thread(target = turn_on, args = ())
    t.start()
    root.mainloop()
    

效果:
记Tkinter制作的飞机仪表控件_第5张图片

【未完待续】先写飞机上的程序去了 控制端之后写

你可能感兴趣的:(记Tkinter制作的飞机仪表控件)