私的AI研究会 > RaspiPico2

Raspberry Pi Pico 2

  マイコンボード「Raspberry Pi Pico」を使って PC から制御できる『自動ドア』の模型を作成する~

  

※ 最終更新:2022/09/22 

PC からコントロールできる『自動ドア』を作る

ハードウェアの製作

  1. DCモーターで開閉する『自動ドア』
    TAMIYA のサイト を参考に『自動ドア』を作成
  2. DCモーターの制御は Raspberri Pi Pico でおこなう
  3. PC から USBインターフェースで制御できるようにする
  4. モーターの動作確認用に正負の両電圧で点灯する 2色LED をつける
  5. 単3電池 2本のバッテリー駆動とする

Pico側 ソフトウェアの製作

  1. タイマーによるLED点滅プログラム「led.py」
    ##------------------------------------------
    ##  LED blink Program  Ver 0.01
    ##          platform: Raspberry pico
    ##
    ##               2022.08.17 Masahiro Izutsu
    ##------------------------------------------
    ## led.py
    
    from machine import Pin, Timer
    
    # LED定義Pin25
    led = Pin(25, Pin.OUT)
    # Timer生成
    timer = Timer()
    
    # callback関数
    def tica2(timer):
        global led
        led.toggle()
    
    # freq nHz(1秒間にn回の間隔)
    # mode Timer.PERIODIC(繰り返し実行)
    def blink_on(frq):
        timer.init(freq=frq, mode=Timer.PERIODIC, callback=tica2)
    
    # LED 停止
    def blink_off():
        timer.deinit()
        led.value(0)
     
    # ** main関数 **
    def main():
        import utime
    
        blink_on(2)
        utime.sleep(5)
        blink_off()
    
    # main関数エントリーポイント(実行開始)
    if __name__ == "__main__":
        main()
  2. DCモーター制御プログラム「motor.py」
    ##------------------------------------------
    ##  Motor controle Program  Ver 0.01
    ##          platform: Raspberry pico
    ##
    ##               2022.08.17 Masahiro Izutsu
    ##------------------------------------------
    ## motor.py
    
    import machine
    import utime
    
    IN1 = machine.Pin(1, machine.Pin.OUT)
    IN2 = machine.Pin(2, machine.Pin.OUT)
    ontime = 0.6
    stoptime = 1
    
    def forward(sec = ontime):
        # 正転
        IN1.value(1)
        IN2.value(0)
        utime.sleep(sec)
        brake(sec)
    
    def revers(sec = ontime):
        # 逆転
        IN1.value(0)
        IN2.value(1)
        utime.sleep(sec)
        brake(sec)
    
    def brake(sec = ontime):
        # ブレーキ
        IN1.value(1)
        IN2.value(1)
        utime.sleep(sec)
    
    def stop(sec = stoptime):
        # 停止
        IN1.value(0)
        IN2.value(0)
        utime.sleep(sec)
    
    def open_door(on_sec = ontime, stop_sec = stoptime):
        # 正転
        forward(on_sec)
        # 停止
        stop(stop_sec)
        # 逆転
        revers(on_sec)
    
    # main関数エントリーポイント(実行開始)
    if __name__ == "__main__":
        lp = 2
        while lp > 0:
            open_door()
            # 停止
            stop()
            lp = lp - 1
  3. ホストからのコマンド受信プログラム
    ・通信インターフェース仕様
    受信バイト文字列動作
    'open'ドアを開く
    'close'ドアを閉じる
    'door'ドアを開いて閉じる
    'quit'ホスト側 終了
     ※ USB UART 通信 ボーレート:115200 bps, パリティ:なし, ストップビット: 1

    ・Pico 側 ソースコード「uart.py」(最終的に自動実行 → main.py)
    ##------------------------------------------
    ##  UART communication Program  Ver 0.01
    ##          platform: Raspberry pico
    ##
    ##               2022.08.17 Masahiro Izutsu
    ##------------------------------------------
    ## uart.py
    
    from machine import Pin, Timer, UART
    import utime
    import led
    import motor
     
    # ** main関数 **
    def main():
        uart = UART(1, 115200, tx=Pin(4), rx=Pin(5), timeout=100)
    
        while True:
            rxData = uart.readline()
            if rxData == None:
                break
            utime.sleep(0.005)
    
        uart.write('** UART program start **')
        led.blink_on(8)
        utime.sleep(1)
        led.blink_off()
    
        while True:
            rxData = uart.readline()
            if rxData is not None:
                print(rxData)
                if rxData == b'open':
                    led.blink_on(2)
                    motor.forward()
                    led.blink_off()
    
                elif rxData == b'close':
                    led.blink_on(2)
                    motor.revers()
                    led.blink_off()
    
                elif rxData == b'door':
                    led.blink_on(4)
                    motor.open_door()
                    led.blink_off()
    
                elif rxData == b'quit':
                    led.blink_off()
    
    # main関数エントリーポイント(実行開始)
    if __name__ == "__main__":
        main()

PC側 ソフトウェアの製作

  1. ホストPC に「Thonny Python IDE」をインストール
    Thonny, Python IDE for beginners から「thonny-x.x.xx.exe」をダウンロード
    ・ダウンロード後セキュリティ警告が表示される場合 図の手順で保存する
    ・ダウンロードファイルをインストールする
     詳しい手順 → Raspberry Pi Pico の MicroPython を Thonny Python IDE で開発する

  2. 自動ドア制御プログラム
    ・制御キー入力
    key動作
    'o'ドアを開く
    'c'ドアを閉じる
    'd'ドアを開いて閉じる
    'Esc' または 'q'プログラム終了
     ※ ドアの開閉状態はプログラムでは把握していないことに注意

    ・プログラムの実行
    (py37w) PS D:\temp\thony> python uart_test.py
    'COM3' port ready.
    o
    c
    d
    Program Finished.
    ・ホスト側 ソースコード
    ▼ テストプログラム「uart_test.py」

  3. PC上の Python IDE「Thonny」から、Raspberry Pi に接続した Pico と通信する

    ・左は VNC Vewerでの Raspberry Pi 畳の Thonny 画面
    ・右は PC上の Thonny 画面

  4. PC上の PowerShell 上のプログラムから、Raspberry Pi に接続した Pico と通信する

    ・左は VNC Vewerでの Raspberry Pi 畳の Thonny 画面
    ・右は PC上の Thonny 画面

  5. Pico のコマンド受信プログラムを自動実行ファイル(main.py) として保存し、PC の「PowerShell」または「コマンドプロンプト」から実行する。
  6. 最終的にはコマンド受信プログラムをパッケージ化して、PC の顔認証プログラムに組み込む
    ・自動ドア 制御クラス
    Doorクラス 関数メソッド機能
    set_port(COM = "COM3", bitRate = 115200)ポートの初期化
    get_port()シリアルポート オブジェクトの取得
    send_command(cmd)コマンド文字列の送信
    info()ポートの状態を送信
    open_door()ドアを開く
    close_doorドアを閉じる
    open_close()ドアを開いて閉じる
    finish()シリアルポートを閉じて終了
    read()文字列の受信
    ・使い方
    import door_ctrl
    
    door = Door()         ←  インスタンス作成
    ser = door.set_port(COM)    ← ポートの初期化(ポート名)
    if ser is None:        ← ポートがない
        print(f"error: '{COM}' port not found.")
        return 0
    else:             ← ポートオープン
        print(f"'{COM}' port ready.")
        :
    
    door.open_close()       ← ドアを開いて閉じる
        :
    door.finish()         ← 終了
    ・ホスト側 ソースコード
    ▲ ドア制御プログラム「door_ctrl.py」
    # -*- coding: utf-8 -*-
    ##------------------------------------------
    ##  Auto-door control Program  Ver 0.01
    ##          platform: windows
    ##
    ##               2022.08.19 Masahiro Izutsu
    ##------------------------------------------
    ## door_ctrl.py
    
    import serial
    
    class Door:
        def set_port(self, COM = "COM3", bitRate = 115200):
            try:
                self.ser = serial.Serial(COM, bitRate, timeout=0.1)
                return self.ser
            except:
                return None
    
        def get_port(self):
            return self.ser.name
    
        def send_command(self, cmd):
            self.ser.write(cmd.encode())
    
        def info(self):
            cmd = f"'{self.ser.name}' port ready."
            self.send_command(cmd)
    
        def open_door(self):
            cmd = "open"
            self.send_command(cmd)
    
        def close_door(self):
            cmd = "close"
            self.send_command(cmd)
    
        def open_close(self):
            cmd = "door"
            self.send_command(cmd)
    
        def finish(self):
            cmd = "quit"
            self.send_command(cmd)
            self.ser.close()
    
        def read(self):
            ln = self.ser.readline()
            return ln.decode()
    
    
    #-----Test routine-----
    def main(COM = 'COM3'):
        from readchar import readchar, key      # UP.DOWN.LEFT,RIGHT 不可(複合キャラクタ)
        import time
    
        door = Door()
        ser = door.set_port(COM)
        if ser is None:
            print(f"error: '{COM}' port not found.")
            return 0
        else:
            print(f"'{COM}' port ready.")
    
        while True:
            time.sleep(0.05)
    
            line = door.read()
            if len(line) > 0:
                print(line)
    
            c = readchar()
            c_utf8 = c.encode("utf-8")
            print(c_utf8)
    
            if c == 'h':
                door.info()
    
            elif c == 'o':
                door.open_door()
    
            elif c == 'c':
                door.close_door()
    
            elif c == 'd':
                door.open_close()
    
            elif c == 'q' or c == key.ESC:
                print("Program Finished.")
                door.finish()
                break
    
    # main関数エントリーポイント(実行開始)
    # $ python3 door_ctrl.py {option:COM1}
    #
    if __name__ == "__main__":
        import sys
    
        args = sys.argv
        COM = 'COM3' if len(args) <= 1 else args[1]
        main(COM)

Pico の自動起動

  1. 完成したプログラムを「main.py」として保存することで、次の起動からプログラムが自動実行される
  2. 自動起動設定された Pico にホスト接続して「Thonny」を起動し「Ctrl」+「C」を押すことで、引き続き開発を続行することができる

更新履歴

 

参考資料

 

Last-modified: 2022-09-22 (木) 15:46:34