2021年4月4日日曜日

本書の電子工作パーツをRaspberry Pi Picoで利用する

はじめに

2021年1月にRaspberry Pi Picoが発表されました。例えば下記のショップで取り扱われています(品切れのときもあります)。後で述べるように、購入する場合は「Pico にピンヘッダを実装したもの」あるいは「Pico H (ピンヘッダ実装済のPico)」がお勧めです。 また、2023年3月には、Wifi対応の Raspberry Pi Pico W も発売されました。 Raspberry Pi Pico は従来の Raspberry Pi シリーズのように「コンピューター」として使うものではなく、以下のように「マイクロコントローラー」に分類される商品です。マイクロコントローラーの代表例として、本書1章では Arduino UNO を紹介したのでした。

コンピューターRaspberry Pi Zero / 1 / 2 / 3 / 4 など
マイクロコントローラーArduino UNO、Raspberry Pi Pico など

これは、Raspberry Pi Pico は Linux OS をインストールして利用するものではないということを意味します。また従来の Raspberry Pi ではできたことで、Raspberry Pi Pico にはできないことがたくさんあります。本書の範囲で言えば、カメラを利用する演習などです。

しかし、電子工作は Linux OS を用いる手法よりもマイクロコントローラーを用いて行う手法の方が歴史がありますし、Raspberry Pi Pico の方が優れている面もまたたくさんあります。例えば、出力できるハードウェアPWMが16個であることや、電源投入後すぐに回路が動き出すことなどです。

本書を購入された方は、秋月電子通商さんによるパーツセットなどの電子工作パーツを合わせて購入された方も多いでしょう。その電子工作パーツを Raspberry Pi Pico で利用してみると、電子工作の世界をより深く知ることができます。従来の Raspberry Pi と Raspberry Pi Pico の利点を知ることで、それぞれを適材適所で使い分けることもできるでしょう。

なお、Raspberry Pi 財団は、公式のキーボードマウスを販売するなど、ユーザーが愛着を持てるようなブランド作りにこだわっているように筆者には思えます。従来のシリーズとは異なる Raspberry Pi Pico にも接することで、皆さんの Raspberry Pi シリーズへの愛着はさらに増すかもしれません。

そこで、本ページでは本書で用いた電子工作パーツを Raspberry Pi Pico でも用いる方法を紹介します。

下図は、本書4章で行ったLチカを Raspberry Pi Pico で実行している様子です。
以下、本ページでは本書 1 章から 8 章の演習のうち、Raspberry Pi Pico でも実行可能なものを紹介します。
Raspberry Pi Pico W を用いている方は、9章以降の Wifi 接続を必要とする演習も実行可能です。本ページで Raspberry Pi Pico の取り扱いに慣れてから以下のページに進むとよいでしょう。

初回のみ実行すればよい準備

さてここからは、Raspberry Pi Pico で電子工作するために、最初に一回だけ実行すればよい準備を行っていきます。

ピンヘッダが取り付けられていない Raspberry Pi Pico を購入された方は、それをはんだ付けする必要があります。
はんだ付けをしたくない方には、あらかじめページ上部のリンクでピンヘッダ実装済のものを購入するのがお勧めです。

さて、Raspberry Pi Pico (Pico W 含む) に自分でピンヘッダをはんだ付けする場合、ピンヘッダとよばれるパーツを入手する必要があります。例えば秋月電子通商さんの下記のものがあります。 これは40ピンのピンヘッダですが、これをニッパで半分にカットして20ピンのものを2つ用意します。なお、ピンヘッダを2つにカットする際、ピンヘッダのプラスチック部が破損することがありますので、 ピンヘッダは複数購入するのが安全です。

ピンヘッダをはんだ付けする際、ピンヘッダと Raspberry Pi Pico のみでは固定するのに苦労します。下図のようにブレッドボードに差した状態ではんだ付けするのが簡単です。 はんだ付けのコツはp.162の図7-2をご覧ください。ピンとランドの両方を熱することが重要なのでした。

なお、手早く行わないとブレッドボードが溶けてきますので注意しましょう。ブレッドボードは安価なので、もし溶けてしまったとしても新しいものを購入することは比較的容易です。

このはんだ付けが、Raspberry Pi Picoを用いる上で最も難易度が高い作業だと個人的には思います。
ピンヘッダが装着されたら、Raspberry Pi Pico を PC に接続します。PCは Windows や macOS を搭載したものでもよいですし、従来の Raspberry Pi Zero / 1 / 2 / 3 / 4 でも構いません。以下では、Raspberry Pi Pico を Windows PC と接続した場合を例に解説を進めます。

PCとの接続には microUSB ケーブルを用います。microUSB ケーブルは、充電専用のものではなくPCと通信可能なものを用意してください。充電専用のケーブルでは以下の作業を実行できません。

そして、Raspberry Pi Pico の基板上の白い BOOTSEL ボタンを押しながら microUSB ケーブルをPCのUSBポートに接続します。BOOTSEL ボタンを押しながらPCに接続すると、Raspberry Pi Pico は PC からは USB メモリのようなストレージとして見えます。

私の Windows 10 では、下図のようなストレージとして表示されました。
このストレージの内部を見ると、下図のように INDEX.HTM と INFO_UF2.TXT というファイルが存在します。図中に先回りで記述されているように、ここに UF2 と呼ばれるファイルをダウンロード(あるいはコピー)します。このファイルは、Raspberry Pi Pico を MicroPython という言語で用いるために必要なものです。MicroPythonとは、マイクロコントローラーで動作させるための Python です。
UF2ファイルはRaspberry Pi の公式ページのこちらよりダウンロードできます。ページ中の「Download the correct MicroPython UF2 file for your board」という箇所にある UF2 ファイルをダウンロードします。Pico 用と Pico W 用がありますので、ご自分のお使いの Pico にあったファイルを選びましょう。Pico H を用いている方は Pico 用を、Pico WH を用いている方は Pico W 用を選択します。

執筆時には、Pico用の場合「rp2-pico-20221011-unstable-v1.19.1-543-gab317a0d6.uf2」という名称のファイルがダウンロードされました。 このファイルを、先ほどの Raspberry Pi Pico を表すストレージに直接ダウンロードするか、あるいはダウンロードされたファイルをストレージにコピーしましょう。 ストレージへのダウンロードまたはコピーが完了すると、Raspberry Pi Pico が自動的に再起動されます。

それにより、基板上の白い BOOTSEL ボタンを押さずに Raspberry Pi Pico に電源を入れたときと同じ状態になり、Raspberry Pi Pico で MicroPython が利用できるようになります。 Raspberry Pi Pico の次回以降の起動の際は、何も押さずに Raspberry Pi Pico と PC を microUSB ケーブルで接続するだけで OK です。

次に、Raspberry Pi Pico 上で MicroPython プログラムを実行するために、開発環境である Thonny をインストールします。 PC として Windows や macOS をお使いの場合、多くの方は Thonny をインストールしていないでしょうから、こちらから各 OS 用の Thonny をダウンロードし、インストールしてください。

PC として Raspberry Pi を用いる場合はインストール済の Thonny を用いて構いません。ただし、Raspberry Pi OS が古い場合、下記コマンドで Thonny を最新にした方が良いでしょう。
sudo apt update
sudo apt install thonny
さて、インストールした Thonny を起動します。そのウインドウの右下に例えば「Python 3.7.9」のように Pythonのバージョンが書かれていますので、そこをマウスでクリックします。 すると、下図の状態になりますので、Configure Interpreter をクリックします。
すると、下図のウインドウが開きますので、「MicroPython (Raspberry Pi Pico)」をクリックし、OKボタンをクリックしましょう。
するとウインドウの右下の表示が以下のようになります。この状態になったら、Raspberry Pi Pico で MicroPython プログラムを実行するための開発環境として Thonny を利用することができます。
今回初めて Thonny をインストールした方の場合、 このまま Thonny を Raspberry Pi Pico 専用の開発環境にしてしまってもよいでしょう。そうではない場合、すなわち、これまで Thonny を通常の Python の開発環境としても利用していた場合、 Raspberry Pi Pico 用プログラムの開発が終わったら上の画面で「The same interpreter which runs Thonny (default)」をクリックし、Thonny をデフォルトの状態に戻す必要がありますのでご注意ください。

4章のLチカを実行してみよう

さて、以上で準備は整いました。ここからは、本書4章以降で用いた電子工作パーツを Raspberry Pi Pico (Pico W 含む) で利用する方法を解説していきます。

Raspberry Pi Pico のピン配置は以下のようになっています。このうちそれぞれの電子工作パーツに必要なピンを用いて回路を作成していきます。
Raspberry Pi Pico Datasheet の p.4 より引用


まず、4章で用いたLEDでLチカを行うための回路を以下に示します。
そして、実行すべきプログラムは以下のものです。
from machine import Pin
from time import sleep

led = Pin(16, Pin.OUT)

while True:
    led.toggle()
    sleep(0.5)
このプログラムをコピーして下図のように Thonny 上に貼り付けます。そして、貼り付けが終わったら緑色の実行ボタンをクリックしましょう。新しい Thonny を使っている場合、すぐにプログラムが実行され、 ブレッドボード上の LED が点滅すると思います。
以下のウインドウが現れますので、「Raspberry Pi Pico」をクリックしましょう。
すると、下図のように Raspberry Pi Pico 上に保存する際のファイル名を聞かれます。以下のすべてのプログラムで、プログラム名を main.py としてOKをクリックしてください。 main.py は特別なファイル名となっており、Raspberry Pi Pico に電源が投入されたときに自動的に実行されるプログラムとなるのです。新しい Thonny を使っている場合、メニューの「ファイル」→「保存」または「名前を付けて保存」からこれらの画面を出すことができます。
なお、このとき、「Device is busy... (以下省略)」というエラーメッセージが表示された場合、Raspberry Pi Pico 上でプログラム実行中の可能性があります。その場合、Thonny の「STOP(停止)」ボタンをクリックし、実行中のプログラムを停止してから保存するようにしてください。これは、本ページの以下のプログラムでも共通のことですので、覚えておきましょう。

さて、OKボタンをクリックすると、main.py が保存され、さらにそのプログラムが実行されます。

さて、以上の方法でプログラムを実行すれば、ブレッドボード上でLEDが点滅しているはずです。これをLチカと呼ぶのでした。

Lチカを確認できたら、Raspberry Pi Pico の電源を一旦切ってから入れ直し、Lチカプログラムが自動実行されることも確認してみましょう。ただし、上で述べたように Raspberry Pi Pico 上に main.py というファイル名でプログラムを保存しないと、この「電源投入と同時に行われるプログラム自動実行」は機能しませんのでご注意ください。

なお、Raspberry Pi Pico は従来の Linux OS をインストールする Raspberry Pi と異なり、いきなり USB ケーブルを抜いて電源を切っても構いません。

USBケーブルを接続して Raspberry Pi Pico に電源を入れなおすと、即座にLチカが始まったのではないでしょうか? このように「プログラムの自動実行が容易であること」、「電源投入後にすぐに回路が動作すること」が Raspberry Pi Pico の特長です。

Linux OS をインストールする従来の Raspberry Pi ではプログラムの自動実行がそれなりに大変であり(本書での紹介はp.286~291)、回路が動作するまでには OS の起動を待たねばなりませんから 1 分程度の時間がかかるのでした。

さて、以上で Raspberry Pi Pico で電子工作パーツを動かす基本の解説は終わりです。以下では、残りの章で用いた電子工作パーツ用の回路図とプログラムを列挙していきます。

5章のタクトスイッチを使ってみよう

タクトスイッチを利用するための回路が下図です。タクトスイッチの状況に応じて点灯させるための LED も取り付けられています。
上の回路に対し、「タクトスイッチを押している間だけ LED が点灯する」という動作のプログラムが以下です。本書のサンプルでは 05-02-sw-pd.py に相当します。 このプログラムをコピーして Thonny 上に貼り付け、緑色の実行ボタンをクリックして Raspberry Pi Pico 上に main.py という名前で保存することで実行するのでした。
from machine import Pin

led = Pin(16, Pin.OUT)
switch = Pin(17, Pin.IN, Pin.PULL_DOWN)

while True:
    if switch.value()==1:
        led.value(1)
    else:
        led.value(0)
一方、「タクトスイッチを押すたびに LED の点灯/消灯が切り替わる」という動作のプログラムが以下です。本書のサンプルでは 05-03-sw-pd-event.py に相当します。 「一度イベントを検出したら 200ms の間は次のイベントを検出しない」という機能がライブラリになさそうなので、プログラム上で時間を計測して実現しています。
from machine import Pin
import time

def switch_pressed(p):
    global prev_time, counter, led
    pressed_time = time.ticks_ms()
    if pressed_time < prev_time + 200 :
        return
    led.toggle()
    prev_time = pressed_time

prev_time = time.ticks_ms()
led = Pin(16, Pin.OUT)
switch = Pin(17, Pin.IN, Pin.PULL_DOWN)
switch.irq(trigger=Pin.IRQ_RISING, handler=switch_pressed)
上記のどちらのプログラムも、Thonny に貼り付けて実行ボタンをクリックし、Raspberry Pi Pico 上に main.py という名称で保存して実行するのでした。

6章の半固定抵抗でアナログ値を使ってみよう

6章のAD変換によるアナログ値の利用をRaspberry Pi Picoでも実行してみましょう。書籍で用いた従来の Raspberry Pi と違うのは、 Raspberry Pi Pico には ADコンバータが内蔵されており、別途用意する必要がないことです。ピン配置図で ADC0~2 と書かれているピンでADコンバータを利用できます。

早速試してみましょう。半固定抵抗を用いる回路図が以下です。これは本書p.144の図6-6に相当します。
この回路を利用するためのプログラムが以下です。 本書のサンプルでは 06-01-print.py に相当します。 このプログラムをコピーして Thonny 上に貼り付け、緑色の実行ボタンをクリックして Raspberry Pi Pico 上に main.py という名前で保存することで実行するのでした。
from machine import ADC
from time import sleep

adc = ADC(26)

# Values in a range [272, 65535] were shown.

while True:
    value = adc.read_u16()
    print(value)
    sleep(0.2)
Raspberry Pi Pico の ADコンバータを read_u16 関数で読み取ると、0~65535 の数値が読み取れます。ただし、私が試したところ、小さな値としては 272 程度までしか下がらず、 0という値は出力されませんでした。そのことがコメントとして書かれています。

次に、フォトレジスタ(CdSセル)により明るさを読み取り、暗ければLEDを点灯するという演習を試してみましょう。回路図は以下で、これは本書p.155の図6-9に相当します。
この回路を利用するためのプログラムが以下です。 本書のサンプルでは 06-02-led.py に相当します。このプログラムでは明るい/暗いの境界の値を 50000 と定めています。必要に応じて変更してください。
from machine import ADC, Pin
from time import sleep

adc = ADC(26)
led = Pin(16, Pin.OUT)

# Values in a range [272, 65535] were shown.

while True:
    value = adc.read_u16()
    if value < 50000:
        led.value(1)
    else:
        led.value(0)
    print(value)
    sleep(0.2)


7章のI2Cデバイスを使ってみよう

次に、7章で用いたI2Cデバイスである温度センサと LCD を利用してみましょう。

温度センサを用いる回路図は以下です。本書p.164の図7-4に相当します。なお、I2C用のプルアップ抵抗ですが、RP2040 内部の 50~80kΩ のプルアップ抵抗が有効にされるようで、本ページの演習は全てI2C用のプルアップ抵抗なしで動作します(参考)。 50~80kΩ では大きすぎる、という場合に数 kΩのプルアップ抵抗を別途追加すると良いでしょう。
この回路を動かすためのプログラムは以下です。本書のサンプルでは 07-01-temp.py に相当します。
from machine import Pin, I2C
from time import sleep

def read_adt7410():
    word_data = int.from_bytes(i2c.readfrom_mem(address_adt7410, register_adt7410, 2), 'little', False)
    data = (word_data & 0xff00)>>8 | (word_data & 0xff)<<8
    data = data>>3 # 13ビットデータ
    if data & 0x1000 == 0:  # 温度が正または0の場合
        temperature = data*0.0625
    else: # 温度が負の場合、 絶対値を取ってからマイナスをかける
        temperature = ( (~data&0x1fff) + 1)*-0.0625
    return temperature

i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
i2c.scan()
address_adt7410 = 0x48
register_adt7410 = 0x00

while True:
    inputValue = read_adt7410()
    print(inputValue)
    sleep(0.5)
次に、温度センサとLCDを同時に用いる回路は以下です。これは、本書p.171の図7-6に相当します。
この回路を動かすためのプログラムは以下です。本書のサンプルでは 07-02-LCD.py に相当します。
from machine import Pin, I2C
from time import sleep

def setup_st7032():
    c_lower = (contrast & 0xf)
    c_upper = (contrast & 0x30)>>4
    i2c.writeto_mem(address_st7032, register_setting, bytes([0x38, 0x39, 0x14, 0x70|c_lower, 0x54|c_upper, 0x6c]))
    sleep(0.2)
    i2c.writeto_mem(address_st7032, register_setting, bytes([0x38, 0x0d, 0x01]))
    sleep(0.001)

def clear():
    global position
    global line
    position = 0
    line = 0
    i2c.writeto_mem(address_st7032, register_setting, bytes([0x01]))
    sleep(0.001)

def newline():
    global position
    global line
    if line == display_lines-1:
        clear()
    else:
        line += 1
        position = chars_per_line*line
        i2c.writeto_mem(address_st7032, register_setting, bytes([0xc0]))
        sleep(0.001)

def write_string(s):
    for c in list(s):
        write_char(ord(c))

def write_char(c):
    global position
    byte_data = check_writable(c)
    if position == display_chars:
        clear()
    elif position == chars_per_line*(line+1):
        newline()
    i2c.writeto_mem(address_st7032, register_display, bytes([byte_data]))
    position += 1

def check_writable(c):
    if c >= 0x06 and c <= 0xff :
        return c
    else:
        return 0x20 # 空白文字

i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
i2c.scan()
address_st7032 = 0x3e
register_setting = 0x00
register_display = 0x40

contrast = 32 # 0から63のコントラスト。30から40程度を推奨
chars_per_line = 8  # LCDの横方向の文字数
display_lines = 2   # LCDの行数

display_chars = chars_per_line*display_lines

position = 0
line = 0

setup_st7032()

write_string('Hello World')

# カタカナや特殊記号は文字コードを一文字ずつ入力
# 以下は「ラズベリー パイ」と表示する例
#s = chr(0xd7)+chr(0xbd)+chr(0xde)+chr(0xcd)+chr(0xde)+chr(0xd8)+chr(0xb0)+' '+chr(0xca)+chr(0xdf)+chr(0xb2)
#write_string(s)
また、温度センサの値をLCDに表示するためのプログラムは以下です。本書のサンプルでは 07-03-LCD-temp.py に相当します。 なお、古いバージョンの MicroPython では、温度センサで値を読み取り、LCDに結果を表示する際、間に「i2c.scan()」という命令を実行しないとエラーが出ていましたので、そのことがコメント文で記されています。
from machine import Pin, I2C
from time import sleep

def read_adt7410():
    word_data = int.from_bytes(i2c.readfrom_mem(address_adt7410, register_adt7410, 2), 'little', False)
    data = (word_data & 0xff00)>>8 | (word_data & 0xff)<<8
    data = data>>3 # 13ビットデータ
    if data & 0x1000 == 0:  # 温度が正または0の場合
        temperature = data*0.0625
    else: # 温度が負の場合、 絶対値を取ってからマイナスをかける
        temperature = ( (~data&0x1fff) + 1)*-0.0625
    return temperature

def setup_st7032():
    c_lower = (contrast & 0xf)
    c_upper = (contrast & 0x30)>>4
    i2c.writeto_mem(address_st7032, register_setting, bytes([0x38, 0x39, 0x14, 0x70|c_lower, 0x54|c_upper, 0x6c]))
    sleep(0.2)
    i2c.writeto_mem(address_st7032, register_setting, bytes([0x38, 0x0d, 0x01]))
    sleep(0.001)

def clear():
    global position
    global line
    position = 0
    line = 0
    i2c.writeto_mem(address_st7032, register_setting, bytes([0x01]))
    sleep(0.001)

def newline():
    global position
    global line
    if line == display_lines-1:
        clear()
    else:
        line += 1
        position = chars_per_line*line
        i2c.writeto_mem(address_st7032, register_setting, bytes([0xc0]))
        sleep(0.001)

def write_string(s):
    for c in list(s):
        write_char(ord(c))

def write_char(c):
    global position
    byte_data = check_writable(c)
    if position == display_chars:
        clear()
    elif position == chars_per_line*(line+1):
        newline()
    i2c.writeto_mem(address_st7032, register_display, bytes([byte_data]))
    position += 1

def check_writable(c):
    if c >= 0x06 and c <= 0xff :
        return c
    else:
        return 0x20 # 空白文字

i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
i2c.scan()

address_adt7410 = 0x48
register_adt7410 = 0x00

address_st7032 = 0x3e
register_setting = 0x00
register_display = 0x40

contrast = 32 # 0から63のコントラスト。30から40程度を推奨
chars_per_line = 8  # LCDの横方向の文字数
display_lines = 2   # LCDの行数

display_chars = chars_per_line*display_lines

position = 0
line = 0

setup_st7032()

while True:
    inputValue = read_adt7410()
    #i2c.scan() # 古い MicroPython ではデバイス切り替え時に必要だった
    clear()
    s = str(inputValue)
    write_string(s)

    sleep(1)


8章で学んだPWMを使ってみよう

最後に8章で学んだ PWM を Raspberry Pi Pico でも利用してみましょう。 Raspberry Pi Pico ではハードウェア PWM を 16 個出力できます。これは従来の Raspberry Pi の 2 個に比べると大きな利点です。本ページでは解説しませんが、従来の Raspberry Pi と Raspberry Pi Pico を接続し、お互いの利点を活かす方法もあります(希望があれば接続方法を解説するかもしれません)。

さて、PWMにより LED の明るさを変更するための回路は以下です。これは、本書p.194の図8-6に相当します。
この回路を動かすためのプログラムは以下です。本書のサンプルでは 08-01-led.py に相当します。ADコンバータの読みが 272~65535となっていましたので、デューティ比の計算にその補正が入っています。
from machine import Pin, ADC, PWM
from time import sleep

adc = ADC(26)
pwm = PWM(Pin(16))
pwm.freq(100)

# Values in a range [272, 65535] were shown.
adc_min = 272
adc_max = 65535

while True:
    value = adc.read_u16()
    print(value)
    duty = (value-adc_min)/(adc_max-adc_min)
    if duty < 0:
        duty = 0
    pwm.duty_u16(int(65535*duty))
    sleep(0.2)
次に、3つのPWMにより RGBフルカラーLED の色を変更するための回路は以下です。これは、本書p.200の図8-8に相当します。半固定抵抗を3つ並べる際にスペースが必要となりますので、この回路は大きめのブレッドボードがないと実現できませんのでご注意ください。
この回路を動かすためのプログラムは以下です。本書のサンプルでは 08-02-rgbled.py に相当します。ADコンバータの読みが 272~65535となっていましたので、デューティ比の計算にその補正が入っています。
from machine import Pin, ADC, PWM
from time import sleep

adc1 = ADC(26)
adc2 = ADC(27)
adc3 = ADC(28)
pwm1 = PWM(Pin(16))
pwm2 = PWM(Pin(17))
pwm3 = PWM(Pin(18))
pwm1.freq(100)
pwm2.freq(100)
pwm3.freq(100)

# Values in a range [272, 65535] were shown.
adc_min = 272
adc_max = 65535

while True:
    value1 = adc1.read_u16()
    value2 = adc2.read_u16()
    value3 = adc3.read_u16()
    duty1 = (value1-adc_min)/(adc_max-adc_min)
    duty2 = (value2-adc_min)/(adc_max-adc_min)
    duty3 = (value3-adc_min)/(adc_max-adc_min)
    if duty1 < 0:
        duty1 = 0
    if duty2 < 0:
        duty2 = 0
    if duty3 < 0:
        duty3 = 0
    # アノードコモンの場合、下記の3行を有効に   
    #duty1 = 1 - duty1
    #duty2 = 1 - duty2
    #duty3 = 1 - duty3
    pwm1.duty_u16(int(65535*duty1))
    pwm2.duty_u16(int(65535*duty2))
    pwm3.duty_u16(int(65535*duty3))
    
    sleep(0.2)
次に、PWMにより DC モーターを制御するための回路は以下です。これは、本書p.208の図8-11に相当します。モータードライバーと半固定抵抗の配置が窮屈になっていますので、大きめのブレッドボードをお持ちの方は、そちらで余裕をもって配置すると良いでしょう。
この回路を動かすためのプログラムは以下です。本書のサンプルでは 08-03-dcmotor.py に相当します。ADコンバータの読みが 272~65535となっていましたので、デューティ比の計算にその補正が入っています。
from machine import Pin, ADC, PWM
from time import sleep

adc = ADC(26)
pwm1 = PWM(Pin(16))
pwm2 = PWM(Pin(17))
pwm1.freq(100)
pwm2.freq(100)

# Values in a range [272, 65535] were shown.
adc_min = 272
adc_max = 65535
adc_mid = (adc_min + adc_max)/2

duty_max = 0.7

while True:
    inputVal = adc.read_u16()
    
    if inputVal < adc_mid:
        pwm2.duty_u16(0)
        duty = (adc_mid-inputVal)/(adc_mid-adc_min)
        if duty > 1:
            duty = 1
        duty *= duty_max
        pwm1.duty_u16(int(65535*duty))
    else:
        pwm1.duty_u16(0)
        duty = (inputVal-adc_mid)/(adc_max-adc_mid)
        if duty > 1:
            duty = 1
        duty *= duty_max
        pwm2.duty_u16(int(65535*duty))
    sleep(0.5)
最後に、PWMにより RC サーボモーターを制御するための回路は以下です。これは、本書p.215の図8-13に相当します。
この回路を動かすためのプログラムは以下です。本書のサンプルでは 08-04-servo.py に相当します。ADコンバータの読みが 272~65535となっていましたので、デューティ比の計算にその補正が入っています。
from machine import Pin, ADC, PWM
from time import sleep

def servo_duty_hwpwm(val):
    val_min = 272
    val_max = 65535
    servo_min = 0.035   # 最小デューティ比3.5%
    servo_max = 0.1  # 最大デューティ比10%
    if val < val_min:
        val = val_min
    duty = (servo_min-servo_max)*(val-val_min)/(val_max-val_min) + servo_max
    # 一般的なサーボモーターはこちらを有効に
    #duty = (servo_max-servo_min)*(val-val_min)/(val_max-val_min) + servo_min
    return duty

adc = ADC(26)
pwm = PWM(Pin(16))
pwm.freq(50)

while True:
    value = adc.read_u16()
    duty = servo_duty_hwpwm(value)
    pwm.duty_u16(int(65535*duty))
    sleep(0.2)


おわりに

以上、本書で実行した 1 章から 8 章の演習のうち、Raspberry Pi Pico でも実行可能なものを紹介しました。

9章以降の Wifi 接続を必要とする演習は、2023年3月に日本発売された、Wifi機能付きの Raspberry Pi Pico W を用いればおおむね動作させることができます(機能の制限はありますが)。その方法を示したのが下記のページです。 一方、本書の続編である「実例で学ぶRaspberry Pi電子工作」で紹介した、インターネットに接続する演習や画像処理を行う演習、「Raspberry Piではじめる機械学習」で紹介した、機械学習やディープラーニングを行う演習も、従来の Raspberry Pi の得意分野と言えるでしょう。

本ページをきっかけに、Raspberry Pi を用いた電子工作に対する皆さんのアイディアがさらに膨らむと幸いです。

2 件のコメント:

  1.  ラズベリーパイの価格を上昇してしまい、なかなか手を出しずらい状況が続いています。
     価格が安いpicoを使用した「本書(ラズパイ4対応 カラー図解 最新 Raspberry Piで学ぶ電子工作)の電子工作パーツをRaspberry Pi Picoで利用する」は大変興味深い内容でした。
     数年前に「実例で学ぶRaspberry Pi電子工作」を参考に電子工作を行わせていただきましたが、この第3章・第4章・第5章の内容をRaspberry Pi Picoで実行するプログラムの公開もしていただけるとうれしいのですが、ご検討よろしくお願い致します。

    返信削除
  2. 「実例で学ぶRaspberry Pi電子工作」は9年前の書籍であり、
    (少なくとも現時点では)改訂版が出る予定はありません。

    最新機種でも動作するようメンテナンスは続けていますが、
    新規のコンテンツを追加するのは難しいです。ご容赦ください。

    よろしくお願いします。

    返信削除