Raspberry Pi Picoで荷重ロガーを製作
計装化クイックドロー
Raspberry Pi Picoを使って、クイックドローに加わった荷重を計測できる装置を製作しました。名付けて計装化クイックドロー(Instrumented quickdraw)。クライミング中の墜落時などの荷重を調べることが目的です。
現状、下の写真のものができています。写真右側が、カラビナ、M16アイボルト、容量2000kgfのロードセル、バックアップ用スリングから成るクイックドロー部分です。左側のプラケースが制御・データ収録部分となっています。
Raspberry Pi Picoとは
もう記憶がおぼろげなのですが、2021年にRaspberry Pi Zero (ラズベリーパイ ゼロ)で温度・湿度・気圧ロガーを製作したことがあります。Raspberry Pi Zeroは、Linux系のOSで動作する小さなコンピュータです。それとは別に、Raspberry Pi Pico(ラズベリーパイ ピコ、以下、Picoと表記)なるものもあるようで、興味が湧いてきました。
PicoにはOSが搭載されないのでコンピュータではなく、あらかじめ登録したプログラムに基づいて処理を行うマイクロコントローラ(マイコン)と呼ばれる装置に分類されるようです。マイコン用にカスタマイズされたMicroPythonという言語でプログラミングできるみたいです。
用意したもの
- Raspberry Pi Pico:770円
- 128×64ドット有機ELディスプレイ:580円
- 2000kgロードセル:4,950円
- HX711(ロードセルアンプ):1,680円
- microSDカード(32GB):680円
- M16アイボルト一式:約1,400円
- ブレッドボード、ジャンパピン類やケース:約1,000円
- 合計:約11,000円
集計してみると、材料費だけでそれなりにかかりました。でも、これくらいの容量のロードセルとデータ収録装置を既製品で揃えようとすると20~30万円はかかるので、それに比べれば圧倒的に安価です。もちろん、精度や信頼性は既製品の方が優れていますが。
Raspberry Pi Pico本体は有機ELディスプレイとのセット品をメルカリで、アイボルトは近所のホームセンターで、HX711はスイッチサイエンスで、その他はAmazonで購入しました。ロードセルアンプのHX711は、Amazonでもっと安価なのが買えますが、サンプリング周波数が10Hz固定のものがほとんどです。スイッチサイエンスで販売されいてるHX711は、10Hz/80Hzの切り替えが容易です。衝撃的な荷重を計測したいので、サンプリング周波数はできるだけ高くしたいのです。
容量2000kg(約20kN)のロードセルがこれほど安く買えるとは知りませんでした。個人的自由研究用途では十分でしょう。それを知らなかった当初は、カラビナのスパインにひずみゲージを貼り付けてロードセルを自作しようかと無謀なことを考えていました。
装置構成
時々刻々のロードセル出力をmicorSDカードに保存し、ディスプレイに動作状況を表示する構成としました(最初は、リアルタイムで計測値をディスプレイに表示していましたが、その処理のせいでサンプリング速度が遅くなるようなので、計測状態のみを表示するようにしています)。
2000kgfロードセルからには5本の線が出ており、それぞれ以下の意味となっています。
- 印加電圧:赤線(+)、黒線( – )
- 出力電圧:緑線(+)、白線( – )
- シールド:黄色
今回使用したロードセルは基準電圧が5Vなので、ロードセルアンプのVCCにはPicoの5V出力に接続しています。
ソフトウェア
モジュール
ロードセルアンプ用、液晶ディスプレイ用、SDカード用のMicroPythonモジュールを以下のとおり入手し、それらをimportして操作するプログラムを作成しました。
- ロードセルアンプ用:micropython-hx711
- 液晶ディスプレイ用:micropython-ssd1306
- SDカード用:sdcard.py
ロードセルアンプ用と液晶ディスプレイ用は、Raspberry piの開発環境であるThonny(ソニー)の「ツール」→「パッケージを管理」から検索すればインストールできました。SDカード用のモジュールは探すのが大変でしたが、Connecting an SD Card to a Raspberry Pi Picoの記事からたどり着けました。この記事ならって、SDカードアダプタにピンヘッダをはんだ付けして使用しています。ピンヘッダの配線も記事と同じにしています。
データ収録のタイミング
試作段階で、保存されたデータをみると50ms(ミリ秒)間隔でした。ロードセルアンプは80Hzで動作させているので、本来であれば12.5ms間隔のはずです。いろいろ調べてみると、液晶ディスプレイへのデータ表示と、microSDカードへのデータ保存をwith構文で都度openしていることが原因のようでした。
液晶ディスプレイへのリアルタイム表示はやめればいいとして、microSDカードの保存が問題です。いろいろ試して(こういう表現ばかりですみません、試しすぎてよく覚えていないのです)、file openしたまま都度データ書き込みし、計測終了したら外部割り込みでfile closeする方法が上手くいきました。
具体的には、MicroPythonリファレンス「外部割り込み」を参考に、タクトスイッチで割り込みを発生させてfile.close()させています。そうすると、ファイルへの書き込みができなくなり、OSErrorが発生するので、exceptで拾って終了処理をする方法としました。
これがベストではないとは思うのですが、とりあえずやりたい処理はできているし、他に方法も思いつかないので、このようにしています。概ね12〜13ms間隔でロードセルの値が保存されており、80Hzでサンプリングできるようになりました。
作成したプログラム
以下にプログラムを掲載します。10行目の
CALIB_FACT = 221.22
というのは、ロードセルの信号を実際の力に換算するための係数です。自重で計装化ロードセルにぶら下がって、そのときの出力と、そのときの体重とが対応するように係数を決めました。単位系はN(ニュートン)にしています。
プログラムをmain.pyという名前でPico本体に保存すると、電源を入れた瞬間から実行され、ディスプレイには「Measuring…」と表示されます。内部では34行目から始まるmeasure_load()関数のwhileループが動き続けており、80HzでmicroSDカードに計測データを書き込んでいます。
GP15につないだタクトスイッチを押すと、50行目の割り込み処理でsave関数を呼び出してfile.closeされ、以降はファイル書き込みできなくなるので、その例外を63行目のexcept OSErrorで拾って、ディスプレイに「Completed!」と表示させています。
物理的に電源を入れ直すと、計測が再開されます。このあたり、計測再開ボタンを設置するなどして、もう少しスマートにしたいなとは思います(動いているからまあいいか、とも思います)。
from machine import Pin, I2C, SPI
import time
import os
import sdcard
from ssd1306 import SSD1306_I2C
from hx711 import HX711
# Set load cell
hx711 = HX711(d_out=5, pd_sck=6)
CALIB_FACT = 221.22 # to Newton units
# Set display
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
display = SSD1306_I2C(128, 64, i2c)
# Set LED
led = Pin(25, Pin.OUT)
# Intialize the SD Card
cs = Pin(17, Pin.OUT) # Chip Select (CS) pin
spi = SPI(0,
baudrate=1000000,
polarity=0,
phase=0,
bits=8,
firstbit=machine.SPI.MSB,
sck=machine.Pin(18),
mosi=machine.Pin(19),
miso=machine.Pin(16))
sd = sdcard.SDCard(spi, cs)
vfs = os.VfsFat(sd) # Mount filesystem
os.mount(vfs, "/sd")
def measure_load():
t_start = time.ticks_ms()
while True:
t_interval = time.ticks_ms() - t_start
load = hx711.read() / CALIB_FACT
print(f'{t_interval}, F = {load:.1f}')
file.write(f'{t_interval}, {load:.1f}\r\n')
time.sleep_ms(10)
# Set save switch
def save(pin):
print('Save switch pressed.')
file.close() # file colse rise eception
sw = Pin(15, Pin.IN)
sw.irq(handler=save, trigger=Pin.IRQ_FALLING)
# File open for SD card writing
file = open('/sd/data.csv', 'a')
file.write('\r\n(ms), (N)\r\n') # Add blank line and unit
try:
led.value(1)
display.fill(0)
display.text('Measuring...', 0, 12, 1)
display.show()
measure_load()
except OSError:
print('end')
display.fill(0)
display.text('Completed!', 0, 12, 1)
display.show()
led.value(0)
動作例
自宅2階のベランダから約5kgの漬物石を落としたときの荷重-時間関係を下図のように取得できました。地上のアンカーにシングルロープを固定し、所定の高さから漬物石を落下させる、リード相当条件です。漬物石本体と地上のアンカーの両方から荷重が加わるので、静止時には、漬物石(約50N)の倍の約100Nが加わっています。また、ピーク荷重や約1100Nであり、漬物石の22倍程の衝撃力が瞬間的に加わっています。サンプリング周波数はたかだか80kHzで、動ひずみ計のようにkHzクラスでデータ取得している訳ではないので、ピーク荷重はもっと高い可能性はあります。DIYで組んだ装置と計測プログラムとしては、まあ、それなりに物理現象を計測できているのではと思います。今後、計装化クイックドローを使って、クライミング中の荷重がどうなっているのかを紐解いていく予定です。