コンテンツにスキップ

CircuitPython を使った Raspberry Pi Pico の開発

フラッシュメモリをリセットする

Raspberry Pi Documentation - Raspberry Pi Pico and Pico W

上記からflash_nuke.uf2をダウンロードする。

BOOTSEL ボタンを押した状態で Raspberry Pi Pico を USB 接続した状態で表示されるストレージにflash_nuke.uf2をコピーする。

CircuitPython をインストールする

Raspberry Pi Pico用の CircuitPython は以下。

Pico Download

Raspberry Pi Pico W用の CircuitPython は以下。

Pico W Download

書き込みを間違えると import エラーが出るなど正しく動作しない。

上記からadafruit-circuitpython-raspberry_pi_pico-en_US-x.x.x.uf2をダウンロードする。

BOOTSEL ボタンを押した状態で Raspberry Pi Pico を USB 接続した状態で表示されるストレージにadafruit-circuitpython-raspberry_pi_pico-en_US-x.x.x.uf2をコピーする。

Hello, World

1
2
3
4
5
import time

while True:
    print("Hello World!")
    time.sleep(1)

シリアルポートに出力される。出てこない場合はAcronis True Image for Crucialをアンインストールする。

LED を点滅させる

Raspberry Pi Pico W では内蔵の LED 点滅ができなかったので諦める。

code.pymain.pyにリネームして以下で保存する。

main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import digitalio
import time
import board

led = digitalio.DigitalInOut(board.GP0)
led.direction = digitalio.Direction.OUTPUT

while True:
    led.value = True
    time.sleep(1)
    led.value = False
    time.sleep(1)

トグルスイッチを使う

main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import time

import analogio
import board
import digitalio

# 代入はこの順番で行わないとトグルスイッチから正しい値が取得できない
toggle = digitalio.DigitalInOut(board.GP0)
toggle.direction = digitalio.Direction.INPUT
toggle.pull = digitalio.Pull.UP

def main() -> None:
    delta_t = 1 / 60
    toggle_before = toggle.value
    while True:
        print(toggle.value)
        if toggle_before and not toggle.value:
            print("Pressed")
        toggle_before = toggle.value
        time.sleep(delta_t)


if __name__ == "__main__":
    main()
1
2
3
4
5
6
7
8
9
True
True
True
False
Pressed
False
False
False
...

CircuitPython のライブラリ

Libraries

Wi-Fi に接続する(Raspberry Pi Pico W)

Overview | Quick-Start the Pico W WiFi with CircuitPython | Adafruit Learning System

settings.tomlに以下を記載する。

settings.toml
1
2
CIRCUITPY_WIFI_SSID="xxxxxxxx"
CIRCUITPY_WIFI_PASSWORD="xxxxxxxx"

main.pyに以下を記載する。

main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import os

import socketpool
import wifi

print("Connecting to Wi-Fi")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print("Connected to Wi-Fi")
pool = socketpool.SocketPool(wifi.radio)

print("MAC address:", ":".join([hex(i)[2:] for i in wifi.radio.mac_address]))
print("IP address:", wifi.radio.ipv4_address)

固定 IP

settings.toml
1
2
3
4
5
WIFI_SSID="xxxxxxxx"
WIFI_PASSWORD="xxxxxxxx"
IPV4_ADDRESS="xxx.xxx.xxx.xxx"
SUBNET_MASK="255.255.255.0"
DEFAULT_GATEWAY="xxx.xxx.xxx.xxx"
main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import ipaddress
import os
import time

import socketpool
import wifi

try:
    # Wi-Fi
    print("Connecting to Wi-Fi")
    wifi.radio.set_ipv4_address(
        ipv4=ipaddress.IPv4Address(os.getenv("IPV4_ADDRESS")),
        netmask=ipaddress.IPv4Address(os.getenv("SUBNET_MASK")),
        gateway=ipaddress.IPv4Address(os.getenv("DEFAULT_GATEWAY"))
    )
    wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
    print("Connected to Wi-Fi")
    pool = socketpool.SocketPool(wifi.radio)
    print("MAC address:", ":".join([hex(i)[2:] for i in wifi.radio.mac_address]))
    print("IP address:", wifi.radio.ipv4_address)

except Exception as e:
    print(e)
    print("Restarting...")
    time.sleep(3)
    microcontroller.reset()

MQTT 接続する(Raspberry Pi Pico W)

Adafruit MiniMQTT というライブラリを使う。

GitHub - adafruit/Adafruit_CircuitPython_MiniMQTT: MQTT Client Library for CircuitPython

adafruit_minimqttディレクトリをlibディレクトリ内にコピーする。

settings.toml
1
2
3
4
5
WIFI_SSID="xxxxxxxx"
WIFI_PASSWORD="xxxxxxxx"
MQTT_BROKER="xxx.xxx.xxx.xxx"
MQTT_PORT=1883
MQTT_CLIENT_ID="RPiPicoW"
main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import os
import time

import adafruit_minimqtt.adafruit_minimqtt as MQTT
import socketpool
import wifi

print("Connecting to Wi-Fi")
wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
print("Connected to Wi-Fi")
pool = socketpool.SocketPool(wifi.radio)

print("MAC address:", ":".join([hex(i)[2:] for i in wifi.radio.mac_address]))
print("IP address:", wifi.radio.ipv4_address)

def connected(client, userdata, flags, rc):
    print("MQTT connected")


def disconnected(client, userdata, rc):
    print("MQTT disconnected")


def message(client, topic, message):
    print("MQTT message on topic {0}: {1}".format(topic, message))

mqtt_client = MQTT.MQTT(
    broker=os.getenv("MQTT_BROKER"),
    port=int(os.getenv("MQTT_PORT")),
    socket_pool=pool,
    client_id=os.getenv("MQTT_CLIENT_ID")
)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
print("MQTT connecting")
mqtt_client.connect()

while True:
    mqtt_client.loop()
    mqtt_client.publish("json", "{\"key\": \"value\"}")
    print("loop")
    time.sleep(1)

USB シリアル通信する

CircuitPython であれば以下のコードでシリアル出力できる。

Tera Term でスピードを 115200 にすること。

1
2
3
4
5
import time

while True:
    print("test")
    time.sleep(1)

Raspberry Pi に Raspberry Pi Pico を USB で接続したとき、以下コマンドでシリアル出力を確認できる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ dmesg | grep tty
# (略)
[44202.665254] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
[44268.886714] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device
$ cat /dev/ttyACM0
test

test

test

test

test

test

test

test

test

test

test

時刻を取得する

Libraries

adafruit_ntp — Adafruit NTP Library 1.0 documentation

adafruit_ntp.mpylibディレクトリ内にコピーする。

よくOSErrorが出るのでmicrocontroller.reset()を使うこと。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os

import microcontroller
import socketpool
import wifi

import adafruit_ntp

try:
    # Wi-Fi
    print("Connecting to Wi-Fi")
    wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
    print("Connected to Wi-Fi")
    pool = socketpool.SocketPool(wifi.radio)
    print("MAC address:", ":".join([hex(i)[2:] for i in wifi.radio.mac_address]))
    print("IP address:", wifi.radio.ipv4_address)

    # NTPサーバー
    ntp = adafruit_ntp.NTP(pool, tz_offset=9)
    print("Hello World!", ntp.datetime)
except Exception as e:
    print(e)
    print("Restarting...")
    time.sleep(3)
    microcontroller.reset()
1
Hello World! struct_time(tm_year=2024, tm_mon=10, tm_mday=4, tm_hour=9, tm_min=52, tm_sec=7, tm_wday=4, tm_yday=278, tm_isdst=-1)

ディープスリープを使う

Overview | Deep Sleep with CircuitPython | Adafruit Learning System

時間を取得する

time.time()は整数の秒なので使いにくい。time.monotonic_ns()でナノ秒単位で取得できる。

1
2
3
4
5
6
start = time.monotonic_ns()
while True:
    now = time.monotonic_ns()
    if now - start >= 1 * 1000 * 1000 * 1000:
        break
    time.sleep(1/60)

キーボードを作成する

以下からadafruit-circuitpython-hid-x.x-mpy-x.x.x.zipをダウンロードして、zip 内のadafruit_hidlibにコピーする。

GitHub - adafruit/Adafruit_CircuitPython_HID: USB Human Interface Device drivers.

main.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import time

import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode

keyboard = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(keyboard)

keyboard.press(Keycode.UP_ARROW)
time.sleep(0.1)
keyboard.release(Keycode.UP_ARROW)

keyboard.press()keyboard.release()はセットで扱うことに注意。

HTTP サーバーを作成する

以下からライブラリをダウンロードし、libディレクトリ内にadafruit_httpserverディレクトリをコピーする。

Libraries

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
└─lib
    └─adafruit_httpserver
            authentication.mpy
            exceptions.mpy
            headers.mpy
            interfaces.mpy
            methods.mpy
            mime_types.mpy
            request.mpy
            response.mpy
            route.mpy
            server.mpy
            status.mpy
            __init__.mpy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os

import socketpool
import wifi

import adafruit_httpserver

print("Connecting to Wi-Fi")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print("Connected to Wi-Fi")
pool = socketpool.SocketPool(wifi.radio)


print("MAC address:", ":".join([hex(i)[2:] for i in wifi.radio.mac_address]))
print("IP address:", wifi.radio.ipv4_address)

print("Hello World!")

server = adafruit_httpserver.Server(pool, debug=True)

@server.route("/hi", "GET")
def base(request: adafruit_httpserver.Request) -> adafruit_httpserver.Response:
    return adafruit_httpserver.JSONResponse(request, {"message": "Hi!"}, status=adafruit_httpserver.status.OK_200)

server.serve_forever("0.0.0.0", 80)

server.start("0.0.0.0", 80)を実行したあと while ループの中でserver.poll()を呼ぶ方法もある。