見出し画像

「Raspberry Pi Pico W」を使おう!


「Raspberry Pi Pico W」は、Raspberry Pi Picoに「Wi-Fi」機能を搭載した開発ボードです。そのため、インターネットへの接続が便利になり、使用用途が大幅に広がります。今回は、MicroPythonを使ったプログラミングを行います。

1.セットアップ(準備)

Raspberry Pi Pico Wを使うために「Thonny」をインストールします。
次のURLからダウンロードします。

以下の写真のように進めてください。

画像


画像

ダウンロードされたファイルをダブルクリックすると以下のような画面が出ます。上の選択肢を押して次に行ってください。

画像

するとSetup画面が出てくるのですべてNextを押してインストールしてください。途中デスクトップにアイコンを作成するか問われます必ず作成してください。

画像


画像

上の画像が出てきたらインストール完了です。

Raspberry Pi Pico W のファームウェアを最新にアップデートします。

https://rpf.io/pico-w-firmware

上記のURLからダウンロードしてください。
次にUSBケーブルをRaspberry Pi Pico W につなげます。

画像

BOOTSELボタンを押しながらパソコンに接続します。するとエクスプローラーで確認すると、以下のような画面が出てきます。ダウンロードしたファームウェアファイルを自分のパソコンの好きなところに長押ししながら移してください。
以上でファームウェアのアップデート手順は終了です。

画像

Thonnyとの接続

Thonnyを起動します。以下のように選択してLet’s goボタンを押します。

画像

次に右下のインタプリタ設定を押します。

画像

上の画像のようにMicroPython(Raspberry Pi Pico)を選択します。
ポートの設定は、ポートの自動検出を試すを選択します。
install or update MicroPython」をクリックします。


画像

以上でセットアップは終了です。お疲れさまでした。

2.「Raspberry Pi Pico W」を使おう!

まず初めにプログラムの解説です。

画像

上の図のようになっています。
このことを理解してコードを見てみたりいじったりしてみてください。

【語句の説明】
ライブラリ:特定の機能をまとめたプログラムの部品で、他のプログラムから引用できるものです。
インポート:ライブラリやモジュール内のオブジェクト(関数やクラスなど)を現在のコードに取り込むこと
while:指定した条件が満たされている間だけ、指定されたコードを繰り返し実行する制御構文
else:条件分岐の際に条件に当てはまらない場合に実行するコードを記述するための節

Raspberry Pi Pico Wに実装済みのLEDを光らせよう

import machine  # GPIO制御用ライブラリ
import time  # 一定時間処理を停止
import rp2  # RP2040用のライブラリ

led = machine.Pin('LED', machine.Pin.OUT)

while True :
    # pico w 本体のLEDを点灯
    led.on()
        
    # 1秒待機
    time.sleep(1)

    # pico w 本体のLEDを消灯
    led.off()
    
    # 1秒待機
    time.sleep(1)

(手順)※①~③は毎回同じです。
①Raspberry Pi Pico Wをパソコンにつなげます。
②Thonnyを起動して、エディタ部分(真ん中の白い部分)に前述のプログラムを貼り付けます。
※エディタ部分がない場合は左上の新規ファイルまたはCtrl+Nを押してエディタ部分を出す。
③左上の保存ボタンを押し任意の保存名を書き保存します。
④実行ボタンを押しLEDが光るか確かめましょう。

【コードの説明】
aspberry Pi Pico Wの本体LED(オンボードLED)を1秒ごとに点滅させるというものです。

【演習問題】
LEDを3秒点灯させ5秒消灯させてみましょう。

Raspberry Pi Pico Wに実装済みのLEDをボタンを押すことで光らせよう

import machine  # GPIO制御用ライブラリ
import utime  # 一定時間処理を停止
import rp2  # RP2040用のライブラリ

# 内蔵LEDにつながっているPINを定義
led = machine.Pin('LED', machine.Pin.OUT)

# BOOTSELボタンの状態を取得する関数
def is_bootsel_pressed():
    return rp2.bootsel_button() == 1

# 無限ループ
while True:
    if is_bootsel_pressed():  # BOOTSELボタンが押されている場合
        led.on()  # LEDを点灯
    else:
        led.off()  # LEDを消灯

    utime.sleep(0.1)  # 0.1秒間処理を停止

【コードの説明】
Raspberry Pi Pico WのBOOTSELボタンを使って内蔵LEDのON/OFFを切り替えるプログラムです。

【演習問題】
ボタンを押しているときに消灯し押していないときに点灯するようにしてみましょう。

Raspberry Pi Pico Wに実装済みの温度センサーでデータ取得しよう

import machine  # GPIOやADC制御用ライブラリ
import utime  # 一定時間処理を停止
import rp2  # RP2040用のライブラリ

# Picoの内蔵温度センサーを読み取るための設定
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / 65535  # ADCの値を電圧(V)に変換

# 内蔵温度センサーのデータを取得し、摂氏(℃)に変換する関数
def read_temperature_on_cpu():
    reading = sensor_temp.read_u16() * conversion_factor  # 16ビットのADC値を電圧(V)に変換
    temperature = 27 - (reading - 0.706) / 0.001721  # 温度を求める公式
    return temperature

# 無限ループ
while True:
    if rp2.bootsel_button() == 1:  # BOOTSELボタンが押下状態の場合
        cpu_temp = read_temperature_on_cpu()  # 現在のCPU温度を取得
        print("[temp] : {}(℃)".format(cpu_temp))  # 温度をコンソールに表示

    utime.sleep(0.1)  # 0.1秒間処理を停止

【コードの説明】
Raspberry Pi Pico wの内蔵温度センサーを使用して、CPUの温度を測定し、BOOTSELボタンが押されたときにその温度をコンソールに表示するプログラム


次に、センサを取り付けていきます。
ここで注意してほしいのが、接続の間違いです。
配線を誤ると、最悪の場合センサやマイコンが発熱・発火してしまう恐れがあります。安全のためにも、配線を行う際は必ずピンの役割を確認してください。

そのために、今回新たに使う「ブレッドボード」について説明します。

【ブレッドボードとは?】

ブレッドボードは、電子部品やセンサなどをはんだ付けせずに簡単に接続できる実験用の基板です。穴に部品のピンやジャンパー線を差し込むことで、内部で電気的につながるようになっています。

画像

・上下の「+」と「-」が書いてある列は、電源専用のラインです。
この列は横方向にすべて繋がっています。
センサやマイコンの電源をここから分岐させることで、複数の部品に電源を供給できます。
・真ん中のたくさん並んだ穴の部分は、5つ1グループで縦に繋がっています。
A〜E、F〜Jの列
で分かれていて、真ん中に1本スキマ(溝)があります。
このスキマをまたいで左右は繋がっていないので注意してください。
マイコンなどのようにピンが左右に分かれている部品を置くときは、このスキマがちょうどいい感じに活躍します。
これらのことを頭に入れ接続してください。

Raspberry Pi Pico Wに超音波センサーを取り付けてデータ取得しよう

import machine  # ハードウェア制御用のライブラリ
import time  # 時間制御用のライブラリ

# 超音波センサーのTRIGとECHOのピン設定
TRIG = machine.Pin(17, machine.Pin.OUT)  # TRIGピンを出力として設定
ECHO = machine.Pin(16, machine.Pin.IN)  # ECHOピンを入力として設定

# 距離を測定する関数(単位:cm)
def distance():
    TRIG.low()  # TRIGをLowにする
    time.sleep_us(2)  # 2マイクロ秒待機
    TRIG.high()  # TRIGをHighにする
    time.sleep_us(10)  # 10マイクロ秒待機
    TRIG.low()  # TRIGを再びLowにする

    # ECHOピンがHighになるのを待つ
    while not ECHO.value():
        pass
    time1 = time.ticks_us()  # ECHOがHighになった時刻を記録

    # ECHOピンがLowになるのを待つ
    while ECHO.value():
        pass
    time2 = time.ticks_us()  # ECHOがLowになった時刻を記録

    # ECHOがHighだった時間を計算
    during = time.ticks_diff(time2, time1)

    # 距離を計算(音速340m/sを使用)
    return during * 340 / 2 / 10000  # cm単位で返す

# メインループ
while True:
    dis = distance()  # センサーから距離を取得
    print("Distance: %.2f cm" % dis)  # 距離を表示
    time.sleep_ms(300)  # 300ミリ秒待機

下の画像のように超音波センサーをブレッドボードにさして、ジャンパー線で配線します。これによって、以下のようにつながります。
【超音波センサー】⇔【Raspberry Pi Pico W】
VCC⇔3V3(OUT)(マイコンからセンサーのVCCに3.3Vの電圧を供給)
GND⇔GND(マイコンとセンサーのグランド(電圧の基準)を合わせる)
TRIG⇔GPIO17(TRIG信号をやり取りする信号線。プログラミングコードで選択)
ECHO⇔GPIO16(ECHO信号をやり取りする信号線。プログラミングコードで選択)


画像

※間違えて接続して試すと煙が出て発火の原因となりますので気をつけてください。


【コードの説明】
Raspberry Pi Pico wなどのマイクロコントローラに接続された超音波センサーを使って、距離を測定し、結果をコンソールに表示するプログラム


Raspberry Pi Pico Wにサーボモーターを付けて動かしましょう

import machine  # ハードウェア制御用ライブラリ
import time  # 時間制御用ライブラリ

# サーボモーター制御用のPWMを初期化(GPIO15)
servo = machine.PWM(machine.Pin(15))
servo.freq(50)  # PWMの周波数を50Hzに設定(一般的なサーボモーター用)

# 値をある範囲から別の範囲へマッピングする関数
def interval_mapping(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

# 指定した角度にサーボを動かす関数
def servo_write(servo, angle):
    pulse_width = interval_mapping(angle, 0, 180, 0.5, 2.5)
    duty = int(interval_mapping(pulse_width, 0, 20, 0, 65535))
    servo.duty_u16(duty)

# メインループ(サーボを10度ずつスイープ)
while True:
    for angle in range(0, 181, 10):  # 0度から180度まで10度ずつ移動
        servo_write(servo, angle)
        time.sleep(0.5)
    for angle in range(180, -1, -10):  # 180度から0度まで10度ずつ戻る
        servo_write(servo, angle)
        time.sleep(0.5)

下の画像のようにサーボモーターのコネクタにオスーオスのジャンパー線をさして、下の画像のようにブレッドボードに配線します。
これによって、以下のようにつながります。
【サーボモーター】⇔【Raspberry Pi Pico W】
VCC【赤】⇔3V3(OUT)(マイコンからサーボのVCCに3.3Vの電圧を供給)
GND【茶】⇔GND(マイコンとサーボのグランド(電圧の基準)を合わせる)
PWM【橙】⇔GPIO15(サーボを動かすための、PWM信号をやり取りする信号線。プログラミングコードで選択)


画像

【コードの説明】
Raspberry Pi Pico wを使用して、サーボモーターを制御するプログラムです。サーボモーターを0度から180度まで、そしてその逆の180度から0度まで動かす処理を行います。
whileの中のfor angle in range(0, 180, 10)とfor angle in range(180, 0, -10)の部分の10,-10の数値を変えてみると違った結果になります。試してみましょう

超音波センサの値が○センチ以下ならサーボモーターを180度回転させよう

import machine  # ハードウェア制御用ライブラリ
import time  # 時間制御用ライブラリ

# 超音波センサーのTRIGとECHOのピン設定
TRIG = machine.Pin(17, machine.Pin.OUT)  # TRIGピンを出力として設定
ECHO = machine.Pin(16, machine.Pin.IN)  # ECHOピンを入力として設定

# サーボモーター制御用のPWMを初期化(GPIO16)
servo = machine.PWM(machine.Pin(15))  # サーボの制御ピンをGPIO15に変更
servo.freq(50)  # PWMの周波数を50Hzに設定(一般的なサーボモーター用)

# 値をある範囲から別の範囲へマッピングする関数
def interval_mapping(x, in_min, in_max, out_min, out_max):
    """
    値をある範囲から別の範囲に変換する関数
    サーボの角度を適切なパルス幅に変換するために使用
    """
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

# 指定した角度にサーボを動かす関数
def servo_write(servo, angle):
    """
    サーボモーターを指定した角度に動かす
    角度をPWM信号のデューティサイクルに変換
    """
    pulse_width = interval_mapping(angle, 0, 180, 0.5, 2.5)  # 角度をパルス幅(ms)に変換
    duty = int(interval_mapping(pulse_width, 0, 20, 0, 65535))  # パルス幅をデューティ比に変換
    servo.duty_u16(duty)  # PWMのデューティ比を設定

# 距離を測定する関数(単位:cm)
def distance():
    TRIG.low()  # TRIGをLowにする
    time.sleep_us(2)  # 2マイクロ秒待機
    TRIG.high()  # TRIGをHighにする
    time.sleep_us(10)  # 10マイクロ秒待機
    TRIG.low()  # TRIGを再びLowにする

    # ECHOピンがHighになるのを待つ
    while not ECHO.value():
        pass
    time1 = time.ticks_us()  # ECHOがHighになった時刻を記録

    # ECHOピンがLowになるのを待つ
    while ECHO.value():
        pass
    time2 = time.ticks_us()  # ECHOがLowになった時刻を記録

    # ECHOがHighだった時間を計算
    during = time.ticks_diff(time2, time1)

    # 距離を計算(音速340m/sを使用)
    return during * 340 / 2 / 10000  # cm単位で返す

# メインループ
while True:
    dis = distance()  # センサーから距離を取得
    print("Distance: %.2f cm" % dis)  # 距離を表示

    if dis <= 10:  # 距離が10cm以下の場合
        servo_write(servo, 180)  # サーボモーターを180度に回転
        print("Servo moved to 180 degrees!")
    else:
        servo_write(servo, 0)  # 距離が10cmより大きい場合、サーボモーターを0度に戻す
        print("Servo moved to 0 degrees!")

    time.sleep(0.5)  # 0.5秒待機
画像


【コード説明】
超音波センサーを使って距離を測定し、その結果に応じてサーボモーターを動かすプログラム。
メインループの10センチ以下の場合というところの数値を変えると違った結果になります。


3.[Raspberry Pi Pico W]アクセスポイント(AP)モードで遠隔でのLチカ

次の目標はざっくりいうと遠隔でマイコン上のLEDを光らせること
複雑なので今回はこんなことができるよ的な感覚を覚えてもらいます。

4.遠隔で内蔵LEDを光らせるコード

コードは次のようになります。
※T崎高校の生徒が実行するときの注意
 SSIDのところは自分のメールアドレスの7桁の数字を書いてください。

import usocket as socket
import network
import gc
import machine  # 追加: machineモジュールをインポート

# 定義
SSID:str = '' #好きな文字列入れて
PASSWORD:str = 'qwertyuiop'

def make_access_point(wifi_ssid:str, wifi_password:str):
    """アクセスポイントを作成し、access_pointを返す関数"""
    access_point = network.WLAN(network.AP_IF)  # AP:Access Pointとして使う
    access_point.config(essid=wifi_ssid, password=wifi_password)  # APの設定を反映する
    access_point.ifconfig(('192.168.4.3', '255.255.255.0', '192.168.4.1', '192.168.4.2'))  # 各種IPアドレスを指定する(固定)
    access_point.active(True)  # アクセスポイントとして検知されるようになる

    # 接続が成功した場合、(IPアドレス、ネットマスク、ゲートウェイ、DNS)を表示
    print("Please connection access_point by other device...")
    print("IP Address:{}\nNet Mask:{}\nGateway:{}\nDNS:{}".format(*access_point.ifconfig()))

    return access_point

class MyHomepageServer():
    def __init__(self):
        # socketの構成、設定
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # socketオブジェクトを作成
        self.socket.bind(('', 80))  # bind
        self.socket.listen(5)  # listen

    def _make_html_text(self, show_message:str):
        """ レスポンスとして返すテキスト(html形式)を返す関数 """
        html = ('''<html>
                     <head>
                       <meta charset="utf-8">
                       <title>Raspberry Pi pico server</title>
                     </head>
                     <body>
                       <h1>Message : {}</h1>
                       <a href="/led/on">Turn On LED</a></br>
                       <a href="/led/off">Turn Off LED</a>
                     </body>
                   </html>'''.format(show_message))
        return html

    def receive_waiting(self):
        """
        受信(accept)
        str型に変換し、テキストによって処理を分岐
        """
        tmp_connection, addr = self.socket.accept()  # 指示待ち状態に(指示あるまでココで一時停止状態となる)
        print(f'Got a connection from {addr}')  # アクセスして来た相手のAddressを表示
        received_text = tmp_connection.recv(1024)  # 受け取った内容を変数に格納(binary)
        print(f'=== Content ===\n{received_text}')  # 受け取った内容を表示(GET等)

        if b"GET /led/on" in received_text:
            led.value(1)  # 出力をHIGHにする(LEDが点灯)
            send_text = self._make_html_text("LED is ON!")
        elif b"GET /led/off" in received_text:
            led.value(0)  # 出力をlowにする(LEDが消灯)
            send_text = self._make_html_text("LED is Off")
        elif b"GET /favicon.ico" in received_text:
            send_text = self._make_html_text("GET favicon.ico")
        else:
            send_text = self._make_html_text("Please click any hyperlinks.")

        tmp_connection.send(send_text)  # 応答(response)を、接続相手に返す
        tmp_connection.close()  # connectionを閉じる

        return None

# ココからmain文
gc.collect()  # garbage collection(ゴミ掃除)
led = machine.Pin("LED", machine.Pin.OUT)  # LED点灯用のPINを設定
ap = make_access_point(SSID, PASSWORD)  # 関数にまとめてある

server = MyHomepageServer()  # クラスを定義

while True:
    server.receive_waiting()  # こちらも関数にまとめてある

5.実際にやってみよう

まず上記のコードをthonnyで実行します。
するとこのようにシェルに文字列が出てきます。

画像
出てきた文字列たち

次にWi-Fi設定のところを開くと下のようにSSID名(自分の場合はPICO_PICO_HAMMER)が出てくるので接続します。暗証番号を求められたらqwertyuiopを入力します。

画像
wi-fi設定画面

左図のように前に出てきた文字列のIP Adressをコピーして右図のようにペーストします。

画像
fight!!

これで開くと以下の画面にたどり着きます。

画像
表示される画面

Turn onを押すとマイコンのLEDが点灯し、Turn offを押すとマイコンのLEDが消灯します。

画像
表示される画面

パソコンだけでなくスマホでもやってみましょう。
スマホでラズパイに接続すると
同じようにラズパイを動かすことができます。

6. コードの説明

make_access_point()の説明

マイクロコントローラ上で、指定された SSID とパスワードを持つ Wi-Fi アクセスポイントを作成する Python 関数です。ここではSSIDはPICO_PICO_HAMMERと、パスワードはqwertyuiopと定義されています。

MyHomepageServer()の説明

このコードは、Raspberry Pi Pico 上で動作するシンプルな Web サーバーを実装したものです。Web ブラウザからアクセスすると、LED のオン/オフを切り替えられる仕組みになっています。

_make_html_text()の説明

Web ブラウザに送信する HTML テキストを生成します。`show_message` 引数は、HTML に表示されるメッセージです。`format(show_message)`には
`show_message` を HTML テンプレートに埋め込みます。

receive_wating()の説明

クライアントからの接続を受け取り、HTTP リクエストを処理します。`if b"GET /led/on" in received_text`: 受信したデータが `/led/on` リクエストである場合、LED をオンにします。`elif b"GET /led/off" in received_text`: 受信したデータが `/led/off` リクエストである場合、LED をオフにします。ここのコードを変えることでボタンを押したときに行われる動作を変更することができます。例えばLEDを点滅させるとか…

main文の説明

led=machine.Pin("LED",machine.Pin.out)はLEDのピン設定を
ap=make_access_point(SSID,PASSWORD)は上記のmake_access_pointの関数を呼び起こし実行します。
server.receive_waiting関数がループで実行されます。

7. AccessPoint(APモード)の解説

仕組み

サーバー側のDNS機能クライアント側のキャプティブポータルの機能を使います。

キャプティブポータルとは、公衆wifiなどで接続後にログインを求めるような場合に認証画面に誘導する仕組み(らしい)。
クライアント側がwifi接続後にキャプティブポータルにアクセスしようとする動作を利用します。
クライアントのOSはキャプティブポータルのページが存在するかどうか確かめるアクセスを試みますが、DNSサーバー側はそのアクセスをwebサーバーのIPアドレスに名前解決し、不明なページへのアクセスをリダイレクトさせてwebサーバーの任意のページに誘導します。
OSはキャプティブポータルからの応答をブラウザにつなぐので、ユーザーは通常のWEBアクセスに近い状態でアクセスが始まります(OSによって挙動が異なります)。wifiの接続操作をしたあと、上記の流れが自動で実行されるため、ユーザーがサーバーのIPアドレスを調べて入力する必要がありません。(今回はIPアドレスを調べて入力する必要があります…)

画像
アクセスポイント図


8.[Raspberry Pi Pico W]アクセスポイント(AP)モードで遠隔での温度測定

次の目標は遠隔でマイコン上の温度測定器で温度を測定すること、
難しいので感覚で理解できるくらいにしてもらえると嬉しいです。

9.遠隔で温度測定するためのコード

コードは下のようになります。
※T崎高校の生徒が実行するときの注意
 SSIDのところは自分のメールアドレスの7桁の数字を書いてください。

import usocket as socket
import network
import gc
import machine  # ハードウェア制御用
import utime

# 定義
SSID = ''  # アクセスポイントのSSID
PASSWORD = 'qwertyuiop'  # アクセスポイントのパスワード

# 温度センサー設定
sensor_temp = machine.ADC(4)  # 温度測定用のADCピン
conversion_factor = 3.3 / 65535  # センサーの変換係数

def read_temperature_on_cpu():
    """CPUの温度を読み取って計算する関数"""
    reading = sensor_temp.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706) / 0.001721
    return temperature

def make_access_point(wifi_ssid, wifi_password):
    """指定したSSIDとパスワードでアクセスポイントを作成する関数"""
    access_point = network.WLAN(network.AP_IF)
    access_point.config(essid=wifi_ssid, password=wifi_password)
    access_point.ifconfig(('192.168.4.3', '255.255.255.0', '192.168.4.1', '192.168.4.2'))  # 静的IP設定
    access_point.active(True)

    print("アクセスポイントに接続してください...")
    print("IPアドレス:{}\nネットマスク:{}\nゲートウェイ:{}\nDNS:{}".format(*access_point.ifconfig()))

    return access_point

class MyHomepageServer:
    def __init__(self):
        """サーバーの初期化"""
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # ソケットを作成
        self.socket.bind(('', 80))  # ポート80にバインド
        self.socket.listen(5)  # 接続を待機

    def _make_html_text(self, show_message, cpu_temp=None, led_state=None):
        """HTMLレスポンスを生成する関数"""
        if cpu_temp:
            show_message += f" <br> 現在の温度: {cpu_temp:.2f}°C"
        if led_state is not None:
            led_message = "LEDはオンです" if led_state == 0 else "LEDはオフです"
            show_message += f" <br> {led_message}"
        
        html = f'''<html>
                     <head>
                       <meta charset="utf-8">
                       <title>Raspberry Pi Pico Wで温度測定</title>
                     </head>
                     <style>#htmlを装飾するコード
                         h1{{
                       display: block;
                       margin: 10px;
                       color: #007bff;
                       text-decoration: none;
                       font-size: 18px;
                     }}</style>
                     <body>
                       <h1>{show_message}</h1>
                       <a href="/led/on">LEDをオン/温度を測定</a><br>
                       <a href="/led/off">LEDをオフ</a><br>
                     </body>
                   </html>'''
        return html

    def receive_waiting(self):
        """リクエストを受けて処理する関数"""
        tmp_connection, addr = self.socket.accept()
        print(f'接続元: {addr}')
        received_text = tmp_connection.recv(1024)
        print(f'=== コンテンツ ===\n{received_text}')

        cpu_temp = read_temperature_on_cpu()  # 各リクエスト時に温度を測定

        if b"GET /led/on" in received_text:
            led.value(1)  # LEDをオン(アクティブロー)
            send_text = self._make_html_text("LEDをオンしました", cpu_temp, led_state=0)
        elif b"GET /led/off" in received_text:
            led.value(0)  # LEDをオフ
            send_text = self._make_html_text("LEDをオフしました", cpu_temp, led_state=1)
        elif b"GET /favicon.ico" in received_text:
            send_text = self._make_html_text("アイコンが要求されました", cpu_temp)
        else:
            send_text = self._make_html_text("リンクをクリックしてください。", cpu_temp)

        tmp_connection.send(send_text)
        tmp_connection.close()

# メイン処理
gc.collect()  # ガーベジコレクション(メモリの整理)
led = machine.Pin("LED", machine.Pin.OUT)  # LEDピンの初期化
ap = make_access_point(SSID, PASSWORD)  # アクセスポイントを作成

server = MyHomepageServer()  # サーバーインスタンスを作成

while True:
    server.receive_waiting()  # リクエストを継続的に処理

10.実際にやってみよう

まず上記のコードをthonnyで実行します。
するとこのようにシェルに文字列が出てきます。

画像
出てきた文字列たち

次にWi-Fi設定のところを開くと下のようにSSID名(自分の場合はPICO_PICO_HAMMER)が出てくるので接続します。暗証番号を求められたらqwertyuiopを入力します。

画像
wi-fi設定画面

左図のように前に出てきた文字列のIP Adressをコピーして右図のようにペーストします。

画像
fight!!

これで開くと以下の画面にたどり着きます。

画像
表示される画面

ここの部分でホームページ上で「LEDをON/温度を測定」「LEDをOFF」の部分を押したとき温度を測定できるようにしました。

11.コードの説明

read_temperture_on_cpu()の説明

このコードは、CPUの温度を測定して摂氏で返す関数です。`sensor_temp.read_u16()` は、CPUの温度センサーから生のデータを読み取ります。`conversion_factor` は、生のデータ値を摂氏に変換するための係数です。`27 - (reading - 0.706) / 0.001721` は、生のデータ値を摂氏に変換するための計算式です。関数は、計算された摂氏温度を返します。この関数は、CPUの温度を監視するプログラムで使用できます。

make_access_point()の説明

マイクロコントローラ上で、指定された SSID とパスワードを持つ Wi-Fi アクセスポイントを作成する Python 関数です。ここではSSIDはPICO_PICO_HAMMERと、パスワードはqwertyuiopと定義されています。

class MyHomepageServerの説明

基本的にはこのコードは、Raspberry Pi Pico 上で動作するシンプルな Web サーバーを実装したものです。Web ブラウザからアクセスすると、LED のオン/オフを切り替えられる仕組みになっています.
遠隔で内蔵LEDを光らせるコードと変更した点は

if b"GET /led/on" in received_text:
            led.value(1)  # LEDをオン(アクティブロー)
            send_text = self._make_html_text("LEDをオンしました", cpu_temp, led_state=0)
        elif b"GET /led/off" in received_text:
            led.value(0)  # LEDをオフ
            send_text = self._make_html_text("LEDをオフしました", cpu_temp, led_state=1)

ここの部分でホームページ上で「LEDをON/温度を測定」「LEDをOFF」の部分を押したとき温度を測定できるようにしました。

またhtmlのコードの部分にCSSのコードを書き加え、主に見た目の装飾に関する定義をするのを加えました。個々のコードを変更することで文字の色や文字の背景の色、余白を加えたりすることを可能にできるようにしています。
以下のコードは上に書いたサンプルコードでここを変えることで好きに見た目の装飾をすることができます。

 <style>#htmlを装飾するコード
       h1{{
          display: block;
          margin: 10px;#余白を作る
          color: #007bff;#文字の色を変える#007bffここの部分はカラーコードで好きな色のカラーコードを挿入することでその色にすることができる。
          text-decoration: none;
          font-size: 18px;#文字のサイズを決める
 }}</style>

main文の説明

led=machine.Pin("LED",machine.Pin.out)はLEDのピン設定を
ap=make_access_point(SSID,PASSWORD)は上記のmake_access_pointの関数を呼び起こし実行します。
server.receive_waiting関数がループで実行されます。

12.[Raspberry Pi Pico W]アクセスポイント(AP)モードで遠隔で超音波センサとサーボモーターを動かそう‼

今回の目標は遠隔でっサーボモーターと超音波センサを動かすことです。
難しいので感覚で理解してもらえると嬉しいです。

1 配線の説明

画像
pin配置図
画像
実体配線図(This image was created with Fritzing.)

13.遠隔でサーボモーターと超音波センサを動かすコード

コードはこちらになります。
※T崎高校の生徒が実行するときの注意
 SSIDのところは自分のメールアドレスの7桁の数字を書いてください。

import usocket as socket
import network
import gc
import machine  
import time

# DEFINE
SSID = ''  # 好きな文字列いれて
PASSWORD = 'qwertyuiop'  # アクセスポイントのパスワード

TRIG = machine.Pin(17, machine.Pin.OUT)  # TRIG pin set as output
ECHO = machine.Pin(16, machine.Pin.IN)  # ECHO pin set as input 

servo = machine.PWM(machine.Pin(15))  # サーボ制御用ピン 
servo.freq(50)

def interval_mapping(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def servo_write(servo, angle):
    pulse_width = interval_mapping(angle, 0, 180, 0.5, 2.5)
    duty = int(interval_mapping(pulse_width, 0, 20, 0, 65535))
    servo.duty_u16(duty)

def distance():
    TRIG.low()
    time.sleep_us(2)
    TRIG.high()
    time.sleep_us(10)
    TRIG.low()

    while not ECHO.value():
        pass
    time1 = time.ticks_us()

    while ECHO.value():
        pass
    time2 = time.ticks_us()

    return time.ticks_diff(time2, time1) * 340 / 2 / 10000

def make_access_point(wifi_ssid, wifi_password):
    access_point = network.WLAN(network.AP_IF)
    access_point.config(essid=wifi_ssid, password=wifi_password)
    access_point.ifconfig(('192.168.4.3', '255.255.255.0', '192.168.4.1', '192.168.4.2'))
    access_point.active(True)
    print("アクセスポイントに接続してください...", access_point.ifconfig())
    return access_point

class MyHomepageServer:
    def __init__(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind(('', 80))
        self.socket.listen(5)

    def _make_html_text(self, show_message, distance_in_cm=None, led_state=None):
        if distance_in_cm:
            show_message += f" <br> 距離: {distance_in_cm:.2f}cm"
        if led_state is not None:
            led_message = "LEDはオンです" if led_state == 1 else "LEDはオフです"
            show_message += f" <br> {led_message}"
        return f'''<html><head><meta charset="utf-8"><title>Pico W Web</title></head>
                  <body><h1>{show_message}</h1>
                  <a href="/led/on">LEDをオン/距離を測定</a><br>
                  <a href="/led/off">LEDをオフ</a><br>
                  <a href="/servo">サーボon</a><br>
                  </body></html>'''

    def receive_waiting(self):
        try:
            tmp_connection, addr = self.socket.accept()
            received_text = tmp_connection.recv(1024)

            distance_in_cm = distance()
            if b"GET /led/on" in received_text:
                led.value(1)
                send_text = self._make_html_text("LEDをオンしました", distance_in_cm, 1)
            elif b"GET /led/off" in received_text:
                led.value(0)
                send_text = self._make_html_text("LEDをオフしました", distance_in_cm, 0)
            elif b"GET /servo" in received_text:
                for angle in range(0, 180, 10):
                    servo_write(servo, angle)
                    time.sleep(0.5)
                for angle in range(180, 0, -10):
                    servo_write(servo, angle)
                    time.sleep(0.5)
                send_text = self._make_html_text("サーボを動かしました", distance_in_cm)
            else:
                send_text = self._make_html_text("リンクをクリックしてください。", distance_in_cm)

            tmp_connection.send(send_text)
            tmp_connection.close()
        except Exception as e:
            print(f"エラー: {e}")
            if tmp_connection:
                tmp_connection.close()

# メイン処理
gc.collect()
led = machine.Pin(25, machine.Pin.OUT)  # LEDピン (修正: "LED"→25)
ap = make_access_point(SSID, PASSWORD)
server = MyHomepageServer()

while True:
    server.receive_waiting()

14.実際にやってみよう

まず上記のコードをthonnyで実行する。
するとこのようにシェルに文字列が出てくる。

画像
出てきた文字列

次にWi-Fi設定のところを開くと下のようにSSID名(自分はPICO_PICO_HAMMER)が出てくるので接続。暗証番号を求められたらqwertyuiopを入力。

画像
表示されたwi-fi

左図のように前に出てきた文字列のIP Adressをコピーして右図のようにペーストする。

これで開くと以下の画面にたどり着く

画像
打ち込んだ文字

するとこのような画面になる。

画像
表示された画面

下の「LEDをオン/距離を測定」「LEDをオフ」「サーボon」をクリックするとマイコンを動作させることができる。

私はパソコンで動作させましたがスマホでも実行させることができます。スマホのほうが実感がわくのでぜひやってみてください。

15.コードの説明

interval_mapping(x, in_min, in_max, out_min, out_max)の説明

このコードスニペットは、入力範囲(`in_min` から `in_max`)内の値 `x` を、出力範囲(`out_min` から `out_max`)内の対応する値にマッピングする関数です。この関数は、例えば、センサー値を別の単位に変換したり、異なるスケールのデータ間で値を比較したりする際に役立ちます。

servo_write()の説明

このコードスニペットは、サーボモーターを指定された角度に回転させるための関数です。このコードは、サーボモーターを制御するために必要なパルス幅を計算し、それをマイクロコントローラーが理解できるデューティサイクルに変換します。これにより、サーボモーターを指定された角度に正確に回転させることができます。

make_access_point()の説明

マイクロコントローラ上で、指定された SSID とパスワードを持つ Wi-Fi アクセスポイントを作成する Python 関数。ここではSSIDはPICO_PICO_HAMMERと、パスワードはqwertyuiopと定義されている。

_make_html_text()の説明

このコードスニペットは、距離とサーボ回転と LED 状態を含む HTML テキストを作成する Python 関数です。

receive_waiting()の説明

このコードは、Webサーバーがクライアントからのリクエストを受け取り、それに応じて処理する仕組みを示しています。

  1. 接続の受け入れ: `self.socket.accept()` を使用して、クライアントからの接続を受け入れます。

  2. リクエストの受信: `tmp_connection.recv(1024)` を使用して、クライアントから送信されたリクエストデータを受け取ります。

  3. リクエストの処理: - リクエストが `/led/on` であれば、LED をオンにし、距離を測定し、その情報を HTML テキストとしてクライアントに送信します。

    • リクエストが `/led/off` であれば、LED をオフにし、距離を測定し、その情報を HTML テキストとしてクライアントに送信します。

    • リクエストが `/servo` であれば、サーボモーターを 0 度から 180 度まで、そして 180 度から 0 度まで回転させ、その情報を HTML テキストとしてクライアントに送信します。

    • その他のリクエストであれば、リンクをクリックするよう促す HTML テキストをクライアントに送信します。

  4. レスポンスの送信: `tmp_connection.send(send_text)` を使用して、クライアントに HTML テキストを送信します。

  5. 接続のクローズ: `tmp_connection.close()` を使用して、クライアントとの接続を閉じます。
    このコードは、Webサーバーがクライアントからのリクエストを処理し、それに応じて LED、サーボモーターを制御し、距離を測定し、HTML テキストをクライアントに返す仕組みを示しています。

main文の説明

led=machine.Pin("LED",machine.Pin.out)はLEDのピン設定を
ap=make_access_point(SSID,PASSWORD)は上記のmake_access_pointの関数を呼び起こし実行する。
server.receive_waiting関数がループで実行される。

16.最後に

これでRaspberry Pi Pico Wを使う練習は終わりました。
次は自分たちでいろいろなコードを動かしてみましょう!

いいなと思ったら応援しよう!

コメント

コメントするには、 ログイン または 会員登録 をお願いします。
「Raspberry Pi Pico W」を使おう!|高崎高校
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1