はじめに
「センサーを一気に揃えたい」「配線が面倒」あるあるだと思います。
そんなときWaveshareの Pico-Environment-Sensor と デュアルGPIOエキスパンダー の組み合わせが便利です。
温湿度・気圧・明るさ・UV・VOC・9軸(加速度/ジャイロ/地磁気)まで一気に手に入ります
この記事でわかること
Pico-Environment-Sensor+GPIOエキスパンダーのメリット(配線ほぼゼロ)
Pico-Environment-Sensorが便利な理由
基板上に以下のセンサーが載っていて、まとめて I2C で読読み取ることができます。
使用されているセンサもおなじみのものばかりです。
- 温度/湿度/気圧:BME280(I2C: 0x76)
- 明るさ(可視+IR):TSL25911FN(I2C: 0x29)
- UV:LTR390-UV-1(I2C: 0x53)
- VOC:SGP40(I2C: 0x59)
- 9軸:ICM20948(I2C: 0x68
デュアルGPIOエキスパンダーが便利な理由
これは、“GPIOを増やすIC”ではなく、Picoの同じピンを2列に引き出して、拡張基板を2枚刺せるようにするボードです。つまり配線が激減します。ただ、注意点もあります。
- 2×20のオスヘッダーが2セット(拡張モジュールを複数接続しやすい)
- ピン名称が印刷されていて迷いにくい
- 接続するモジュール同士でピン競合がないことの確認が必要
動作原理:I2Cが“配線2本で大量接続”できる理由
I2Cは、基本的に以下の2本だけで通信します。
- SCL:クロック(タイミング担当)
- SDA:データ(データの中身担当)
複数のセンサーが同じ2本を共有しても、各センサーは I2Cアドレス(0x29 など)で呼び分けられます。
つまり「同じ道を走って、行き先(住所)で届く先が変わる」イメージです。
配線(というか、ほぼ“刺すだけ”)
おすすめの重ね方
- デュアルGPIOエキスパンダーにPicoを挿す
- 片側のヘッダーに Pico-Environment-Sensor を挿す
- もう片側は、将来 LCD / ePaper / リレー基板など好きに拡張
重要:ピン競合だけは事前にチェック(同じGPIOを別用途で使うモジュール同士は同時に挿せません)
I2Cアドレス確認(0x29/0x53/0x59/0x68/0x76)
test_i2c_scan.py
念の為、以下のコードで各センサのアドレスを確認しましょう
from machine import Pin, I2C
import time
# -----------------------------
# I2Cピン候補(回路図に出てくる組み合わせ)
# - GP6/GP7
# - GP20/GP21
# まずはこの順でスキャンします
# -----------------------------
CANDIDATES = [
{"name": "I2C on GP6/GP7", "i2c_id": 1, "sda": 6, "scl": 7},
{"name": "I2C on GP20/GP21", "i2c_id": 0, "sda": 20, "scl": 21},
]
# 期待されるI2Cアドレス(Pico-Environment-Sensor)
EXPECTED = {
0x29: "TSL25911FN (Light)",
0x53: "LTR390-UV-1 (UV)",
0x59: "SGP40 (VOC)",
0x68: "ICM20948 (9-DOF)",
0x76: "BME280 (Temp/Hum/Press)",
}
def scan_once(i2c: I2C):
addrs = i2c.scan()
addrs.sort()
return addrs
def main():
print("=== Pico-Environment-Sensor I2C Scan ===")
for cfg in CANDIDATES:
print("\n--- Try:", cfg["name"], "---")
try:
i2c = I2C(
cfg["i2c_id"],
sda=Pin(cfg["sda"]),
scl=Pin(cfg["scl"]),
freq=400_000
)
time.sleep(0.2)
addrs = scan_once(i2c)
if not addrs:
print("No I2C devices found.")
continue
print("Found:", [hex(a) for a in addrs])
# 期待デバイスの表示
hit = 0
for a in addrs:
if a in EXPECTED:
print(" -", hex(a), "=>", EXPECTED[a])
hit += 1
if hit >= 3:
print("OK: Pico-Environment-Sensorが見えています。")
return
except Exception as e:
print("Error:", e)
print("\nNG: 期待アドレスが見えません。")
print("・刺し向き/ピン曲がり/半刺しを確認")
print("・別のI2Cピン設定が必要な個体の可能性(基板のI2C切替)")
if __name__ == "__main__":
main()BME280で体感温度を計算
おなじみのBME280からデータを取得し、体感温度を計算してみます。
私のモジュールは以下でした。うまく行かない場合は、ご自身のモジュールを確認ください
SDA:GP20
SCL:GP21
from machine import Pin, I2C
from bme280 import BME280
# I2Cの設定 自分の設定を書くにすること
def initialize_i2c():
return I2C(0, scl=Pin(21), sda=Pin(20), freq=400000)
i2c = initialize_i2c()
bme = BME280(i2c=i2c, address=0x76)
temperature, pressure, humidity = bme.read_compensated_data()
temperature = temperature / 100
pressure = pressure / 25600
humidity = humidity / 1024
# 体感温度の計算
A = 1.76 + 1.4 * 0.01 ** 0.75
sensible_temperature = (37 - (37 - temperature) / (0.68 - 0.0014 * humidity + 1 / A)) - 0.29 * temperature * (1 - humidity / 100)
sensible_temperature_str = "{:.1f}".format(sensible_temperature)
print(sensible_temperature_str)センサーの“身近な使い道”アイデア
温湿度・気圧:部屋の快適度ログ、エアコン効き具合の見える化、簡易天気傾向
明るさ(可視+IR):部屋の照度で自動点灯、カーテン開閉の判断材料
UV:屋外作業やサイクリングの日焼け対策
VOC:換気の目安(料理・塗料・接着剤などのタイミングで上がりやすい)
9軸:転倒検知、姿勢検知、簡易の振動ログ
まとめ
値段は比較的高価ですが、これらを組み合わせると非常に簡単にセンサ値を得ることができます。
まず試作してみる、といった場合は便利だと思います。
さらにディスプレイを組み合わるとデバックが非常に容易になるのでおすすめです。
コメント