あらすじ
以前作ったコードをchatGPT o1-previewに書き直してもらったらずいぶんよくなったので改めて記事を作成した。どうもinput()ではなく sys.stdin.readline()でコマンドを読み取ると良いらしい。素人にはinput関数がどうやってserialのバッファを取得してるのかが分からなかったので、こういう大して難しくなさそうなのに地味でマイナーすぎてぐぐっても解決策がみつからない類の問題をサクッと解決してくれるchatGPT様には足を向けて寝られない。あと4oよりo1-preの方が明らかに頭がいい。
RaspberryPiPico側のコード
今回は基板に内臓されている温度センサーの値を取得してるけどGPIOピンからセンサーの値を取得したりモーター等を動かしたりすることもできる。1分に1回程度動作する環境制御機器を想定しているのでレスポンスの速さは確かめていない。
import machine
import utime
import sys
def read_temperature():
sensor_temp = machine.ADC(4)
reading = sensor_temp.read_u16()
voltage = reading * 3.3 / 65535
temperature = 27 - (voltage - 0.706) / 0.001721
return temperature
print("Waiting for commands...")
while True:
# コマンドをブロッキングで読み取る
command = sys.stdin.readline().strip()
if command == "GET_TEMP":
temp = read_temperature()
sys.stdout.write("Temperature: {:.2f} C\n".format(temp))
else:
sys.stdout.write("Unknown command.\n")
PC側のコード
最初にVender IDとProduct IDでPico基板を探している。デバイスの名前や説明を編集できれば一番いいのだけれどその機能がMicroPythonに実装されてるのか分からなかった。とりあえずPico側に名を名乗らせるコマンドを追加すれば対応できると思う。
import serial
import serial.tools.list_ports
import time
def find_pico_port(vid=0x2E8A, pid=0x0005):
ports = list(serial.tools.list_ports.comports())
for port in ports:
if (port.vid, port.pid) == (vid, pid):
return port.device
return None
def main():
pico_port = find_pico_port()
if pico_port is None:
print("Raspberry Pi Picoが見つかりませんでした。")
return
print(f"Raspberry Pi Picoが{pico_port}で見つかりました。")
# シリアルポートを開く
ser = serial.Serial(pico_port, baudrate=115200, timeout=1)
time.sleep(0.1) # デバイスの準備待ち
# 入力バッファをクリア
ser.reset_input_buffer()
try:
# 2秒ごとに温度を取得するループ
while True:
# コマンドを送信
ser.write(b'GET_TEMP\n')
# 応答を読み取る
response = ser.readline().decode('utf-8', errors='ignore').strip()
print(f"受信した温度データ: {response}")
# 2秒間待機
time.sleep(2)
except serial.SerialException as e:
print(f"シリアル通信でエラーが発生しました:\n {e}")
except KeyboardInterrupt:
pass
finally:
print("\n温度取得を終了します。")
ser.close()
if __name__ == "__main__":
main()
動作テスト
Windows機のThonnyで実行するとこんな感じ
>>> %Run MicroPython_USB_CDC_Host.py
Raspberry Pi PicoがCOM12で見つかりました。
受信した温度データ: Temperature: 17.68 C
受信した温度データ: Temperature: 17.21 C
受信した温度データ: Temperature: 16.75 C
受信した温度データ: Temperature: 17.21 C
温度取得を終了します。
>>>
動作中にUSBケーブルを抜くとこんな感じ
>>> %Run MicroPython_USB_CDC_Host.py
Raspberry Pi PicoがCOM12で見つかりました。
受信した温度データ: Temperature: 17.68 C
受信した温度データ: Temperature: 17.21 C
受信した温度データ: Temperature: 17.21 C
シリアル通信でエラーが発生しました:
WriteFile failed (PermissionError(13, 'デバイスがコマンドを認識できません。', None, 22))
温度取得を終了します。
>>>
とりあえずAIに頼めばいい感じのデモコードを作ってくれる時代になってしまったので簡単な作例を公開する意義が薄くなった気はするけど以前作ったやつがあんまりにもあんまりなので今回は公開する。