Pico距離測定をグラフィック表示する

monkichi Raspberry Pi 工作

Raspberry Pi Picoで取得した距離センサーの出力をどのように表示するのがカッコいいか考えてみました。

イメージとして何を使おうか考えている最中に本棚にあったもんきち貯金箱が目に留まりました。もんきちに頑張ってもらいます。

ネットで公開されている先人の知恵を参考にさせていただき、距離センサー結果に従ってもんきちの位置が移動するコードを作成しました。キャンバスの左端がゼロで右端がおよそ1.5メートルに相当します。デバッグ用に上段に測定カウント、測定インターバル、エコーパルス幅、算出された距離をラベル表示しています。

距離測定結果が22センチの場合
距離測定結果が99センチの場合

このPythonコードは以下となります。肝はupdate()で、self.after(100,self.update)で、再帰的に100msインターバルで自己コール(いわゆるコール・ループ)しています。ソースコードの下の方のapp.mainloop()の直前でupdate()をコールして、このコール・ループをキックしています。以後、100ms間隔で実行されるかというと実際にはそうはならず、ラベルに表示されているようにこの工作の環境では平均で200ms程度になりました。なお、Pico側は200ms間隔で距離測定し、TWELITEから送信するようにしました。

import tkinter as tk
import threading
import serial
from PIL import Image, ImageTk
import time

s = serial.Serial("COM6", 115200, timeout=1)


class GUI(tk.Frame):
    def __init__(self,master = None):
        super().__init__(master)
        self.master = master
        master.geometry("1000x300+300+100")
        master.title("Test")

        self.label = tk.Label(self.master)
        self.label.pack()
        self.label["text"] = ''

        read_image = Image.open('\work\TKinter\osaru.jpg')
        self.im = ImageTk.PhotoImage(image=read_image)      
        self.canvas = tk.Canvas(self.master, width = 1000, height = 200)
        self.canvas.pack()

        self.count = 0
        self.lasttime = time.time()

    def update(self):
        self.count += 1
        s.reset_input_buffer()
        line = s.readline()
        line = line.decode('utf-8')
#        print(line)
        error_flag = 0
        if len(line):
            xferdata = [line[i:i+2] for i in range(1,len(line)-2,2)] # checksum calculation
            n=0
            for x in xferdata:
                n += int(x, 16)
#                print("n={}".format(n))
            if  n & 0xFF: 
                error_flag = 1 # checksum error
                print("checksum error {} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!".format(n))
            else :
                rdata = [line[i:i+2] for i in range(5,len(line)-4,2)]
                chars='0'
                for x in rdata:
                    n = int(x, 16)
                    if  n < 0x30 or 0x39 < n:
                        error_flag = 1
                        print("invalid data ****************************************")
                        break
                    ch = chr(int(n))
                    chars=chars+ch
        else:
            chars='0'
            error_flag = 1
            print("length is zero ???????????????????????????????????")

        if error_flag == 0:
            dist = int(chars)
            currenttime = time.time()
            textout="count= {}  time delta = {}  Echo={}  Dist(cm)={}".format(self.count, (currenttime - self.lasttime), dist, int(dist/58))
            self.lasttime = currenttime
            self.label["text"] = textout
            self.canvas.delete("osaru")
            self.canvas.create_image(dist/10, 100, anchor='center', image=self.im, tag="osaru")

        self.after(100,self.update)
     
     
if __name__ == "__main__":
    gui = tk.Tk()
    app = GUI(master = gui)
    app.update()
    app.mainloop()

    s.close()

TWELITEからのデータ受信に際して以下の3つの確認を行っています。

  1. TWELITEがデータに付与するチェックサムの確認
  2. 送られてくるデータ列が数値のみか確認
  3. 送られてくるデータ長が1以上か確認

2について、この工作においてPicoがTWELITEにUARTで送っている文字列がエコーパルス幅値のみのため、この確認を行っています。複数のデータ(例えば温度センサー値とか)を送る場合はデータフォーマットを定義することになるので、この確認の仕方も変わりますね。3について、時々空パケットが送られてくる場合があり、これを処理対象から取り除くために行っている確認になります。

測定結果も結構ばらつくようです。ぱっと見で10%程度はばらつくでしょうか。これは距離センサー個体によるものか、そもそもこのレベルの距離センサーは概してそういうものなのか、今後調べてみるつもりです。

コメント  

タイトルとURLをコピーしました