Raspberry Pi Zero 2 W + Raspberry Pi OS + Python3でI2CやSPI接続のセンサを制御

Raspberry Pi Zero 2 W(以下、Zero 2 W)にRaspberry Pi OS 32bit版をセットアップしました。メモリ(SDRAM)搭載量が512MBと少ないのでRaspberry Pi OSが満足に動作するか心配していましたが、OSのGUI操作や軽いアプリケーションであれば拍子抜けするくらい普通に動作します。

Zero 2 Wには無線LAN機能が加わったので、同じSSIDの無線LANに接続しているPCからVNC Vewerで遠隔操作できます。時計も正確です。

USBブートのRaspberry Pi 4 Model B(以下、4B)の快適さに慣れてしまうとアプリの起動など遅いのですが、Python 3でI2CやSPI接続したモジュール制御には問題なく対応できました。

Zero 2 WとI2C接続したSCD30、BME280センサ、SPI接続した2.8インチTFT液晶で動作確認した際のメモです。

Raspberry Pi Zero 2 W + Raspberry Pi OS + PythonでCO2濃度、気圧、温湿度の測定
目次

Zero 2 Wの仕様

Zero 2 WはCPU性能が向上し、WiFiがついたのでIoT用途にも向いています。メモリ(SDRAM)搭載量が512MBと少ないので重いアプリを動かすのは難しいですが、Raspberry Pi OS上のPython3から各種センサモジュールを制御できるので使い勝手が良いです。

もうすぐRaspberry Pi PicoにInfineon CYW43439無線チップを追加搭載したRaspberry Pi pico Wの国内販売が始まるようです。値段も安いので登場が待ちどおしいです。

項目Raspberry Pi 4 Model BRaspberry Pi Zero2 WRaspberry Pi pico W
SoC
プロセッサ
Broadcom BCM2711
ARM v8 Cortex-A72
Quad core

1.5GHz or 1.8GHz
Broadcom BCM2710A1
ARM v8 Cortex-A53
Quad core 1GHz
RP2040
ARM Cortex-M0+
Dual-core 133 MHz
メモリー1GB, 2GB, 4GB or 8GB
LPDDR4-3200 SDRAM
512MB
LPDDR2 SDRAM
264kB on-chip SRAM
ネットワーク• 2.4 GHz and 5.0 GHz
  IEEE 802.11.b/g/n/ac

  wireless
•Gigabit Ethernet
2.4GHz
IEEE 802.11b/g/n wireless
2.4GHz 802.11n
wireless
GPIO •40-pin GPIO header • 40-pin I/O header footprint
※GPIO端子の半田付け必要
26 multifunction
GPIO pins
代表的な
コネクタ
•2×USB 3.0 ports、
 2×USB 2.0 ports
• microSD card slot
•2×micro-HDMI ports
•MIPI DSI display port
• USB 2.0 port

• microSD card slot
• mini HDMI port
USB 1.1 controller
BOOTSEL button
電源USB-C connector
5V DC 3A
microUSB connector
5V DC 2.5A
micro USB power port

参考:
Raspberry Pi 4 Model B specifications – Raspberry Pi
Raspberry Pi Zero 2 W specifications – Raspberry Pi
Raspberry Pi Pico and Pico W – Raspberry Pi Documentation
Raspberry Pi Pico W – Raspberry Pi
Operating system images – Raspberry Pi OS

Raspberry Pi OSのセットアップ、モジュールとの結線

Zero 2 WとI2C接続したSCD30センサとBME280センサモジュールの測定データをSPI接続した2.8インチTFT液晶(240×320、ILI9341)モジュールに日本語フォントで表示して動作確認しました。

4Bと同じ構成、手順で動作させることができました。

あわせて読みたい
Raspbery Pi 4BとSCD30、BME280センサでCO2濃度、気圧、気温、湿度の測定、SPI接続2.8インチTFT液晶に表示 Raspberry Pi 4B(以下4B)とSCD30センサとBME280センサモジュールの測定データをSPI接続した2.8インチTFT液晶(240×320、ILI9341)モジュールに日本語フォントで表示し...

Raspberry Pi OSのセットアップ

Zero 2 Wのmini HDMI portにはHDMI接続のディスプレイを、micro USB(USBと印字の)コネクタにはキーボードとマウスを、micro USB(PWR INと印字の)コネクタにはACアダプタをつなぎます。

セットアップ手順は4Bと同じです。PCにインストールしたRaspberry Pi Imagerを使ってmicroSDカードにRaspberry Pi OSのセットアップイメージを書込みます。書き込んだmicroSDカードをZero 2 Wのスロットに挿し込んで電源ON(ACアダプタをmicro USBコネクタに接続)です。

あわせて読みたい
Raspberry Pi 4B + 液晶タッチスクリーンディスプレイに「Raspberry Pi OS」を簡単インストール Raspberry Pi 4B(以下、ラズパイ4B)へのRaspberry Pi OSのセットアップが「Raspberry Pi Imager」で簡単になりました。 Raspberry Pi OS はラズパイ4BのUSB3.0に挿し...

Raspberry Pi OSのI2CとSPIを有効化

I2CとSPIの設定 はデフォルトでは無効です。
苺メニューの「設定」—>「Raspberry Piの設定」を開いて—>「インターフェース」でI2CとSPIを有効にチェック。

再起動するとSoC内蔵の I2C(ハードウエア I2C)とSPI通信が使えるようになります。

I2CとSPIを有効化
I2CとSPIを有効化

Zero 2WにSCD30センサとBME280センサを結線した後、LXTerminalで下記コマンドを投入すると、i2c-1(バス番号1)にBME280のアドレス(0x76)とSCD30のアドレス(0x61)が見えます。

i2cdetect -y 1
BME280とSCD30のI2Cアドレス
BME280とSCD30のI2Cアドレス

結線図

2.8インチTFT液晶(240×320)モジュールをSPIで、SCD30センサとBME280センサモジュールをSoC内蔵の I2C(ハードウエア I2C)で接続する結線図です。2.8インチTFT液晶(240×320)モジュールは4線式のSPIです。

Zero 2 Wと4BのGPIOのピン構成は同じです。Zero 2 WのmicroSDカードスロット側がGPIOの1番ピン側になります。

結線図
結線図

2.8インチTFT液晶モジュールとGPIOとのピン接続の詳細は下記ページに纏めました。本記事ではライブラリのインストールなど必要事項のみの記載です。

あわせて読みたい
i2c-gpio(ソフトウエアI2C)を割り当てたRaspbery Pi CM4とBME280センサで気圧、温度、湿度の測定、SPI接... i2c-gpio (ソフトウエアI2C)を割り当てたRaspberry Pi Compute Module 4(以下CM4)とBME280センサモジュールの測定データをSPI接続した2.8インチTFT液晶(240x320、ILI9...

Python3プログラムを実行

SCD30センサ、BME280センサでCO2濃度、気圧、気温、湿度を測定して、SPI接続の2.8インチTFTに表示するPython3プログラムをZero 2で実行しました。

このPython3プログラムは4Bで実行した実績があります。

あわせて読みたい
Raspbery Pi 4BとSCD30、BME280センサでCO2濃度、気圧、気温、湿度の測定、SPI接続2.8インチTFT液晶に表示 Raspberry Pi 4B(以下4B)とSCD30センサとBME280センサモジュールの測定データをSPI接続した2.8インチTFT液晶(240×320、ILI9341)モジュールに日本語フォントで表示し...

ライブラリのインストール

ライブラリのインストールにはpipを使います。pipは、Pythonパッケージのインストールなどを行うユーティリティで、Raspberry Pi OS with desktop(bullseye)にはPython3とともにインストールされています。
現時点のバージョンはPythonが3.9.2、pipが20.3.4。
構築したRaspberry Pi OSにはPython3のみなので、コマンドではpipとpip3を区別していません。

smbus2

未インストールであればi2C通信を行うためにsmbus2をインストールします。smbus2パッケージは「smbus2-0.4.2」でした。

sudo pip install smbus2

smbus2 0.4.2

https://pypi.org/project/smbus2/

2.8インチTFT液晶ライブラリ

2.8インチTFT液晶 (240×320)モジュールの液晶コントローラLSIはILI9341。Adafruitのライブラリ「Adafruit_CircuitPython_RGB_Display」を利用させていただきました。

sudo pip install adafruit-circuitpython-rgb-display

adafruit/Adafruit_CircuitPython_RGB_Display

https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display

SCD30ライブラリ

SCD30のライブラリには「scd30_i2c」を利用させていただきました。ライブラリ「scd30_i2c」のバージョンは「scd30-i2c-0.0.6」でした。利用には、Pythonバージョン >=3.7.3が必要です。

sudo pip install scd30-i2c

SCD30 CO₂ sensor I²C driver in Python 3

https://pypi.org/project/scd30-i2c/

BME280ライブラリ

BME280のライブラリには「RPi.bme280 0.2.4」を利用させていただきました。Python3コード上でI2Cアドレスとポート番号を指定できるで使い勝手が良いです。

sudo pip install RPi.bme280

RPi.bme280 0.2.4

https://pypi.org/project/RPi.bme280/

BME280、SCD30センサの測定データを2.8インチTFT液晶に表示するプログラムコード

Adafruitライブラリ付属のサンプルプログラム「rgb_display_pillow_stats.py」を参考にして、SCD30センサでCO2濃度、BME280センサで気圧、気温、湿度の測定結果の出力先として2.8インチTFT液晶を加えたプログラムコード「bme280_scd30_sample_TFT_csv.py」を作りました。

日本語を表示するために、独立行政法人情報処理推進機構 (IPA) が提供している日本語フォント「IPAex フォント」をインストール。「ipaexfont-gothic」を使っています。

sudo apt install fonts-ipaexfont

Python3プログラムの実行環境には、Raspberry Pi OS with desktop(bullseye)にプリインストール されているThonny Python IDEを使って動作確認しました。
Thonny Python IDEのshell部分にCSV形式で連続表示するとともに、2.8インチTFT液晶にも2秒間隔で表示します。

bme280_scd30_sample_TFT_csv.pyの実行
Thonny Python IDEで実行、shell部分にCSV形式で連続表示

CSV表示は、先頭から日時(曜日)、SCD30データ(CO2濃度、気温、湿度)、BME280データ(気圧、気温、湿度)。2.8インチTFT液晶表示は、上からBME280データ(気温)、SCD30データ(CO2濃度)、BME280データ(気圧、湿度)、日時(曜日)です。

Raspberry Pi Zero 2 W + Raspberry Pi OS + PythonでCO2濃度、気圧、温湿度の測定
2.8インチTFT液晶に表示

Thonny Python IDEのshell部分へのCSV表示が不要な場合は117行目を#でコメントアウトします。

bme280_scd30_sample_TFT_csv.py
※ここをクリックするとコード表示を開閉できます。
#bme280_scd30_sample_TFT_csv.py
#coding: utf-8

#---TFT-ili9341 init-----rgb_display_pillow_stats.py---
import time
import subprocess
import digitalio
import board
from PIL import Image, ImageDraw, ImageFont
from adafruit_rgb_display import ili9341

# Configuration for CS and DC pins (these are PiTFT defaults):
cs_pin = digitalio.DigitalInOut(board.CE0)
dc_pin = digitalio.DigitalInOut(board.D25)
reset_pin = digitalio.DigitalInOut(board.D24)

# Config for display baudrate (default max is 24mhz):
BAUDRATE = 24000000

# Setup SPI bus using hardware SPI:
spi = board.SPI()

# pylint: disable=line-too-long
# Create the display:
disp = ili9341.ILI9341(
    spi,
    rotation=90,  # 2.2", 2.4", 2.8", 3.2" ILI9341
    cs=cs_pin,
    dc=dc_pin,
    rst=reset_pin,
    baudrate=BAUDRATE,
)
# pylint: enable=line-too-long
# Create blank image for drawing.
# Make sure to create image with mode 'RGB' for full color.
if disp.rotation % 180 == 90:
    height = disp.width  # we swap height/width to rotate it to landscape!
    width = disp.height
else:
    width = disp.width  # we swap height/width to rotate it to landscape!
    height = disp.height

image = Image.new("RGB", (width, height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0))
disp.image(image)

# First define some constants to allow easy positioning of text.
padding = -2
x = 0

# Load a ipaexfont-gothic font.
font1 = ImageFont.truetype("/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf", 50)
font2 = ImageFont.truetype("/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf", 20)
font3 = ImageFont.truetype("/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf", 15)


#---BME280 init---------------bme280_sample.py------------
import smbus2
import bme280

port = 1
address = 0x76
bus = smbus2.SMBus(port)

calibration_params = bme280.load_calibration_params(bus, address)

# the sample method will take a single reading and return a
# compensated_reading object
data = bme280.sample(bus, address, calibration_params)


#---SCD30 init-----------------scd30_sample.py------------
from scd30_i2c import SCD30

scd30 = SCD30()

scd30.set_measurement_interval(2)
scd30.start_periodic_measurement()

time.sleep(2)

while True:
#---csv out  ------------------------------------------
    if scd30.get_data_ready():
        m = scd30.read_measurement()
        if m is not None:
          dtd = time.strftime('%Y年%m月%d日', time.localtime())
          dtt = time.strftime('%H時%M分%S秒', time.localtime())
          dta = time.strftime('%a', time.localtime())
          if dta == "Mon": 
           jdta = dta.replace("Mon", "(月)")
          elif dta == "Tue": 
           jdta = dta.replace("Tue", "(火)")
          elif dta == "Wed": 
           jdta = dta.replace("Wed", "(水)")
          elif dta == "Thu": 
           jdta = dta.replace("Thu", "(木)")
          elif dta == "Fri": 
           jdta = dta.replace("Fri", "(金)")
          elif dta == "Sat": 
           jdta = dta.replace("Sat", "(土)")
          elif dta == "Sun": 
           jdta = dta.replace("Sun", "(日)")
          else:
           jdta="ー"
           
          data = bme280.sample(bus, address, calibration_params)
          pbme280 = f"{data.pressure:.1f},{data.temperature:.1f},{data.humidity:.1f}" 

          pscd30 = f"{m[0]:.1f},{m[1]:.1f},{m[2]:.1f}"
          P_csv = dtd + jdta + " " + dtt + "," + pscd30 + "," + pbme280
        print(P_csv)
        
#---TFT-ili9341- Draw ---------------------------------
        # Draw a black filled box to clear the image.
        draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0))

        draw.text((50, 192), dtd, font=font2, fill="#00ff00")
        draw.text((50, 212), dtt, font=font2, fill="#00ff00")
        draw.text((220, 192), jdta, font=font2, fill="#00ff00")
        
        draw.text((20, 3), "温度:", font=font2, fill="#ffffff")
        draw.text((24, 25), "( ℃ )", font=font3, fill="#ffffff")
        temp =format(float(data.temperature), '.1f')
        draw.text((90, 0), temp, font=font1, fill="#ffffff")

        draw.text((14, 50), "CO   :", font=font2, fill="#FFFF00")
        draw.text((47, 58), "2", font=font3, fill="#FFFF00")
        draw.text((14, 70), "( ppm )", font=font3, fill="#FFFF00")
        co2 =format(float(m[0]), '.1f')
        draw.text((90, 47), co2, font=font1, fill="#FFFF00")

        draw.text((20, 97), "気圧:", font=font2, fill="#ffffff")
        draw.text((18, 117), "( hpa )", font=font3, fill="#ffffff")
        pres =format(float(data.pressure), '.1f')
        draw.text((90, 93), pres, font=font1, fill="#ffffff")

        draw.text((20, 143), "湿度:", font=font2, fill="#ffffff")
        draw.text((24, 165), "( % )", font=font3, fill="#ffffff")
        humi =format(float(data.humidity), '.1f')
        draw.text((90, 140), humi, font=font1, fill="#ffffff")

        disp.image(image)

        time.sleep(2)
    else:
        time.sleep(0.2)

SCD30センサのセルフキャリブレーション

SCD30センサは換気の良い場所で電源を入れたままで一定時間連続測定してセルフキャリブレーションします。400ppm台の数値に落ち着くと思います。

SparkFun SCD30 CO₂ センサー ライブラリ
注: SCD30 には、自動セルフキャリブレーション ルーチンがあります。Sensirion は、セルフキャリブレーションを完了するために、少なくとも 1 日 1 時間の「新鮮な空気」で 7 日間の連続測定を推奨しています。

Note: The SCD30 has an automatic self-calibration routine. Sensirion recommends 7 days of continuous readings with at least 1 hour a day of ‘fresh air’ for self-calibration to complete.

https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library

Interface Description Sensirion SCD30 Sensor Module p.13/21
1.4.6 自動セルフキャリブレーション (ASC) の (非) アクティブ化
継続的な自動セルフキャリブレーションは、次のコマンドで (非) アクティブにすることができます。 初めてアクティブ化する場合、アルゴリズムが ASC の初期パラメーター セットを見つけることができるように、最低 7 日間必要です。 センサーは、毎日少なくとも 1 時間は新鮮な空気にさらす必要があります。 また、その間、センサーを電源から切り離すことはできません。そうしないと、キャリブレーション パラメータを見つける手順が中止され、最初からやり直す必要があります。 正常に計算されたパラメータは SCD30 の不揮発性メモリに保存され、再起動後も以前に見つかった ASC のパラメータが引き続き存在するという効果があります。

1.4.6 (De-)Activate Automatic Self-Calibration (ASC)
Continuous automatic self-calibration can be (de-)activated with the following command. When activated for the first time a period of minimum 7 days is needed so that the algorithm can find its initial parameter set for ASC. The sensor has to be exposed to fresh air for at least 1 hour every day. Also during that period, the sensor may not be disconnected from the power supply, otherwise the procedure to find calibration parameters is aborted and has to be restarted from the beginning. The successfully calculated parameters are stored in non-volatile memory of the SCD30 having the effect that after a restart the previously found parameters for ASC are still present.

https://sensirion.com/media/documents/D7CEEF4A/6165372F/Sensirion_CO2_Sensors_SCD30_Interface_Description.pdf
よかったらシェアしてね!
  • URLをコピーしました!
目次