🔦

Raspberry PiとUbuntuでGPIO制御

2025/02/14に公開

以前PicoとPi Zero2をUARTで繋いでROS2連携しました。

https://zenn.dev/usagi1975/articles/2025-02-02_pico_micro_ros3

このとき、母艦となるPi Zero2が起動してWifi接続やAgent起動してから
Picoを通電させたほうが良いというコメントしました。

そういえば、UbuntuインストールしたラズパイでGPIO制御やったことなかったので、
そのあたり含めて確認しときます。

  • Ubuntu22.04でGPIO制御でLチカなどやってみる
  • Wifi疎通チェック(ネットワーク設定は事前に設定済み)
  • 上記をPythonで実行できるようにする
  • 上記をサービス起動できるようにする

これができると、PiZero2を起動してスタンバイになったか視覚的にもわかるし、
Pico側に「準備できたよ」と知らせることができる。

Ubuntu22.04でのGPIO制御でLチカ

Raspberry Pi OSであればPi.GPIOとかありましたが、Ubuntu22.04の場合はlgpioなるものを使う。

> sudo apt install python3-lgpio -y

Lチカプログラム。GPIO18番でON/OFFします。

# test_led.py
import lgpio
import time

# GPIO18 (物理ピン10)
LED_PIN = 18

# GPIOチップを開く
chip = lgpio.gpiochip_open(0)
# ピンをOUTPUTモードに設定
lgpio.gpio_claim_output(chip, LED_PIN)

try:
    pin_flg = 0
    while True:
        # LED ON/OFF
        pin_flg ^= 1
        lgpio.gpio_write(chip, LED_PIN, pin_flg)
        print("LED flg = %s"%(pin_flg))
        # 0.1sec
        time.sleep(0.1)
except KeyboardInterrupt:
    pass
finally:
    # GPIOチップを閉じる
    lgpio.gpiochip_close(chip)

Raspberry Pi Zero 2のピンレイアウトのおさらい。
SPIがもう1個ありそうでしたが省略してます。

GPIO18とGNDを接続してプログラムを実行します。ついでに標準出力をシリアルコンソールに表示するため、UART接続(GPIO14、15)もしてみます。

プログラム停止はCtrl+Cで強制終了する。

> python3 test_led.py
LED flg = 1
LED flg = 0
LED flg = 1
:

0.1sec間隔でLチカできました。

Wifi接続確認およびIPアドレス取得

いろいろあるけど、psutilが良いと思います。

> sudo apt install python3-psutil -y

wlan0のIPアドレスを取得して取れたらOKとします。

# test_wifi.py
import psutil

def get_wifi_address(wlan="wlan0"):
    try:
        net_if_addrs = psutil.net_if_addrs()
        for addr in net_if_addrs[wlan]:
            # check IPv4
            if addr.family == 2:
                return str(addr.address)
    except Exception as ex:
        print("get_wifi_address error : %s"%(str(ex)))
    return None

ip_addr = get_wifi_address()
print("wlan ip address : %s"%(ip_addr))

実行すると、IPv4のアドレスがとれます。

> python3 test_wifi.py
wlan ip address : 192.168.0.226

インターネットに接続確認が必要なケースもありますが、そこはラズパイ云々じゃないので、別プログラムでチェックします。

電源ONしたら自動的にプログラムをバックグラウンド起動させたい

  • ユーザはrootではなく、普段使うユーザで(ubuntu)
  • ネットワークデバイス関連が準備できた後で
  • 実行はPythonプログラム

systemdにサービスを登録するのがベストだと思います。

プログラムは先ほどのLチカプログラムで、起動したら自動的に点滅させてみます。
ポイントはnetwork-online.targetが稼働したあとで開始します。また、ユーザサービスとして登録しているので、rootではなくubuntuユーザでプログラムが実行されるところです。

[Unit]
Description=My Launch Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/ubuntu/work/test_led.py
Restart=always
WorkingDirectory=/home/ubuntu

[Install]
WantedBy=multi-user.target

上記のファイルをlaunch_my_service.serviceという名前で、ubuntuホーム以下(今回はworkサブフォルダ)に保存して、シンボリックリンクをsystemdのサービスフォルダに作成する。

> sudo ln -s /home/ubuntu/work/launch_my_service.service /etc/systemd/system/launch_my_service.service

> ls -l /etc/systemd/system/launch_my_service.service
lrwxrwxrwx 1 root root 43 Feb 15 14:35 /etc/systemd/system/launch_my_service.service -> /home/ubuntu/work/launch_my_service.service

サービスを登録する

> sudo systemctl daemon-reload
> sudo systemctl enable launch_my_service.service
Created symlink /etc/systemd/system/multi-user.target.wants/launch_my_service.service → /home/ubuntu/work/launch_my_service.service.

> sudo systemctl start launch_my_service.service

これにより、ユーザーubuntuがログインしていなくても、systemdのユーザーサービスが実行されるようになる。

> sudo systemctl status launch_my_service.service
● launch_my_service.service - My Launch Service
     Loaded: loaded (/etc/systemd/system/launch_my_service.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2025-02-15 14:37:44 JST; 19s ago
   Main PID: 3476 (python3)
      Tasks: 4 (limit: 372)
     Memory: 9.6M
        CPU: 448ms
     CGroup: /system.slice/launch_my_service.service
             └─3476 /usr/bin/python3 /home/ubuntu/work/test_led.py

Feb 15 14:37:44 pizero2 systemd[1]: Started My Launch Service.

停止させたい場合は

> sudo systemctl stop launch_my_service.service

ほかのサービスと同じです。サービスが開始してLEDが点滅することが分かったら、再起動して、自動的にLED点滅できたら一連のサービス化は成功です。

余談) Pi Zero 2のWifi接続でハマる

なぜか最近Wifi接続できない現象が続いてました。(もちろん設定済み)
以下を参考に対応して様子見してます。

https://qiita.com/cocoabreak/items/6967ad16cd7583b3189c

hidden: trueを追加しました。ステルスモード対応ですが、そうじゃなくても入れといたほうが良いかもしれない。

network:
    version: 2
    wifis:
        renderer: networkd
        wlan0:
            access-points:
                {SSID}:
                    hidden: true
                    password: {パスワード}
            dhcp4: true
            optional: true

以下で反映する

sudo netplan --debug try
sudo netplan --debug generate
sudo netplan apply

再起動や電源ONしたときにちゃんとつながるか確認

Discussion