ラズパイピコでIoTする方法

ラズパイピコ

 2022年6月にRaspberry Pi Pico Wが発表され、これまで単体ではネットワーク接続ができなかったラズパイピコを無線LANでネットワークに接続できるようになりました。これによりラズパイピコで安価なIoTデバイスを作れるようになります。

 ところで、残念ながらこのRaspberry Pi Pico Wは2022年8月20日現在、日本国内では発売時期が未定となっています。というのも日本国内で無線接続する機器には工事設計認証(いわゆる技適)が必要で、まだ認証が得られていないためです(海外から個人輸入し技適未取得機器を用いた実験等の特例制度の申請をすれば利用可)。

 そこで本稿ではWではない現行のRaspberry Pi Pcoを使って、wifi接続でPCとソケット通信する方法をご紹介します。無線LANへの接続には技適認証が得られているESP-WROOM-02を使います。Raspberry Pi Pico Wの6ドルよりは数百円高くなるものの、現行のラズパイピコでもIoTデバイスをつくって遊べます。

広告

使う電子部品

 使う電子部品は下記の通りです。最低限、wifi接続するだけならRaspberry Pi PicoとESP-WROOM-02、10kΩの抵抗器だけで良いのですが、ネットワーク接続の動作を確認するためにサーボモーターをつけました。

電子部品個数備考
1個Raspberry Pi Pico
“W”ではない標準のタイプです。
1個ESP-WROOM-02
今回は配線しやすいようにDIP化キットを使いました。
モジュール単体なら秋月電子通商で320円でした。
1個低損失三端子レギュレーター 3.3V1A TA48033S
ESP-WROOM-02を動かすのに3.3V電源が必要です。ピコの3.3V電源を使っても良いのですが、安全のためVBUSの5V電源を3.3Vに降圧して使いました。
秋月電子通商で買ったところ0.1μFの積層セラミックコンデンサと47μFの電解コンデンサが付属していました。
1個マイクロサーボ SG92R
とりあえず今回はwifi接続でモーターを動かしてみます。
2個タクトスイッチ
プログラムの停止用と再起動用にスイッチを2個つけました。
4個抵抗器
マイクロサーボに1kΩを1つ、ESP-WROOM-02に10kΩを3つ使います。

配線図

 配線図は下記の通りです。ESP-WROOM-02は3.3Vで動作し、平均消費電流は80mAです。ラズパイピコに大きな電流を流したくないので、今回は5Vの電源から三端子レギュレーターで3.3Vに降圧して電源に使いました。
 なお、ラズパイピコのデータシートを見てみると、3.3V(OUT)は最大で300mAまで使えるようなので、三端子レギュレーターによるVBUSからの降圧は必ずしも必要ではないようです。Raspberry Pi 4が、GPIOピン1つで16mA、合計で50mA以下なのに比べると、電流容量には余裕があります。
 タクトスイッチを2個つけています。1つはプログラムの停止用で、もう1つはリセット用です。wifiにうまくつながらない場合はリセットします。

ラズパイピコをESP-WROOM-02でwifiに接続する

コーディング(Raspberry Pi Pico側)

 PCとソケット通信するため、Raspberry Pi Pico側とPC側の両方でプログラムを動かします。本稿ではラズパイピコをサーバーとし、PC側をクライアントとしています。
 このプログラム内で使っているUARTとかAT+…とかは、別途解説が必要と思いますが、本稿では長くなるので割愛します。

from machine import Pin,PWM
import time
import sys

#サーボモータの準備
freq = 50
duty_offset = 0.5 / 20
duty_coef = (2.4 - 0.5) / 20 / 180
servo = PWM(Pin(28))

#プログラム終了ボタン(タクトスイッチ)
switch=Pin(22,Pin.IN,Pin.PULL_DOWN)

#動作時はRaspberry Pi PicoのLEDを点灯
led=Pin(25,Pin.OUT)
led.high()

#角度を受け取ってサーボモータを回転させる関数
def set_angle(angle):
    degree = angle + 90
    duty = int((duty_offset + duty_coef * degree) * 65535)
    servo.freq(freq)
    servo.duty_u16(duty)

#UARTの準備
print("UART START")
u = machine.UART(1,115200,tx=Pin(4),rx=Pin(5))

#ESP-WROOM-02をリセット
print("reset esp-wroom02...")
try:
    u.write(b'AT+RST\r\n')
    time.sleep(3)
    res = u.read()
except:
    led.low()
    sys.exit()

#ESP-WROOM-02のモードを変更
print("changing mode...")
try:
    u.write(b'AT+CWMODE=1\r\n') #set to =3 or =1
    time.sleep(3)
    res = u.read()
    print(res.decode('utf-8'))
except:
    print("except err!")
    print(res)
    led.low()
    sys.exit()

#ESP-WROOM-02はサーバーとして動かすので、複数のクライアントがアクセスできるように設定
print("enable multiple connection...")
try:        
    u.write(b'AT+CIPMUX=1\r\n')
    time.sleep(3)
    res = u.read()
    print(res.decode('utf-8'))
except:
    print("except err!")
    print(res)
    led.low()
    sys.exit()

#ESP-WROOM-02のIPアドレスを確認
#ここで確認したIPアドレスは、後でクライアント側のプログラムで使います。
print("checking IP...")
try:
    u.write(b'AT+CIFSR\r\n')
    time.sleep(3)
    res = u.read()
    print(res.decode('utf-8'))
except:
    print("except err!")
    print(res)
    led.low()
    sys.exit()

#サーバーモードを開始
print("starting server mode...")
try:
    u.write(b'AT+CIPSERVER=1,333\r\n')
    time.sleep(3)
    res = u.read()
    print(res.decode('utf-8'))
except:
    print("except err!")
    print(res)
    led.low()
    sys.exit()

#データの送受信を開始。
#クライアントからrightまたはleftが含む文字列を受け取ると、サーボモーターを回転させます。
#leftまたはright以外を受け取った場合は応答しません。(クライアント側でタイムアウトする)
#プログラム終了用のタクトスイッチを押すとループを抜けます。
print("receive and send the data...")
while switch.value()==0:
    try:
        res=u.read()
        if res != None:
            if (res.decode('utf-8')).find('right')!=-1:
                set_angle(45)
                time.sleep(0.3)
                set_angle(0)                
                print((res.decode('utf-8')))
                u.write(b'AT+CIPSEND=0,10\r\n')
                time.sleep(1)
                u.write(b'right done')
            elif (res.decode('utf-8')).find('left')!=-1:
                set_angle(-45)
                time.sleep(0.3)
                set_angle(0)
                print((res.decode('utf-8')))
                u.write(b'AT+CIPSEND=0,10\r\n')
                time.sleep(1)
                u.write(b'left done ')
    except:
        print("except err!")
        print(res)
        led.low()
        sys.exit() 

#プログラムが終了するとRaspberry Pi PicoのLEDが消灯します。
led.low()

コーディング(PC側)

 PC側のクライアントのコードです。xxxにはそれぞれポート番号やESP-WROOM-02のIPアドレスを入れます。このプログラムを実行するとターミナルで入力を促すので、leftまたはrightと入力して下さい。サーボモーターが回転します。left/right以外を入力するとRaspberry Pi Picoから応答がありませんので、5秒でタイムアウトしてプログラムが終了します。

import socket
import time

#使用するポートを設定
port = xxx
#受け取る文字列の数を指定
buffer_size = 14
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
    #ESP-WROOM-02のipアドレスを指定
    s.connect(('xxx.xxx.x.xxx',port))
    #Raspberry Pi Picoから応答がない場合のタイムアウト時間(5秒に設定)
    s.settimeout(5)
    time.sleep(3)
    print("ready...")
    #Raspberry Pi Picoと通信するためのループ。
    flag=True
    while flag:
        #"left"または"right"と入力するとサーボモータが回転します。
        str1=input("入力願います。")
        s.send(str1.encode("utf-8"))
        #leftまたはrightに応じてRaspberry Pi Picoから応答があります。
        #応答がない場合、タイムアウト時間を待って、プログラムを終了します。
        try:
            respond_d = s.recv(buffer_size).decode()
        except socket.timeout:
            respond_d = "timeout"
            flag=False
        #Raspberry Pi Picoからの応答、またはtimeoutと表示します。
        print(respond_d)

動作の様子(動画)

 動作の様子を撮影してみました。Raspberry Pi Picoは電源を家庭用コンセントから取っており、PCとは有線接続していません。PC画面でクライアントプログラムからleft, rightなどと入力してwifi経由でESP-WROOM-02とソケット通信し、Raspberry Pi Picoからサーボモーターを動かしています。

コメント

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