ラズパイを使って、重さをはかるよ
💡やること
ロードセル計量センサを使って、デジタルはかりをつくります。
液晶OLEDと連動して、重さを表示します。
🏁デモ
🔧パーツ一覧
no | 部品名 | 個数 | 備考 |
---|---|---|---|
1 | ラズベリーパイ | 1 | 今回は4Bで確認 |
2 | 電子スケール ロードセル計量センサセット(重量センサ+HX711) | 1 | Amazon |
3 | 128x64ドット有機ELディスプレイ | 1 | 秋月電子 |
4 | ジャンパー線 | 適量 | - |
5 | ブレッドボード | 1 | - |
6 | 分銅 | 1 | 代用可能 |
接続図
ピンの接続
Pin | HX711 | ディスプレイ | 備考 |
---|---|---|---|
5V | VCC | - | 赤色ケーブル |
GND | GND | GND | 黒色ケーブル |
BCM5 | DT | - | 黄色ケーブル |
BCM6 | SCK | - | 緑色ケーブル |
3.3V | - | VDD | 橙色ケーブル |
BCM2(SDA.1) | - | SDA | 紫色ケーブル |
BCM3(SCL.1) | - | SCL | 青色ケーブル |
💻環境
開発環境
- ラズベリーパイ
- Linux rpi 5.10.17-v7l+ #1403 SMP Mon Feb 22 11:33:35 GMT 2021 armv7l GNU/Linux
- Python
- Python 3.7.3 (default, Jan 22 2021, 20:04:44)
ラズベリーパイの設定
表示デバイスは、I2C通信を使って制御します。
I2C通信を使用できるように設定する必要があります。
I2Cの有効化は、以下のコマンドから実施できます。
$ sudo raspi-config
- Interface Optionsを選択
- I2Cを選択
- "はい"(or "Yes")を選択
- これで有効化されます(1回行えばOKです)
モジュールのインストール
apt
日本語を表示するためにフォントをインストールします。
$ sudo apt-get install fonts-ipafont
pip
Pythonに関するモジュールをインストールします。
$ python3 -m venv env
$ source env/bin/activate
# 表示機用
(env) $ pip install adafruit-circuitpython-ssd1306
(env) $ pip install smbus2
(env) $ pip install pillow
# 重さ計測用
(env) $ pip install RPi.GPIO
(env) $ git clone https://github.com/tatobari/hx711py
📝手順
- キャリブレーションの実施
- ディスプレイと連動させる
キャリブレーションの実施
センサーのばらつきや筐体の差などがあるため、キャリブレーション(校正)を行う必要があります。
tatobariさんが公開されているモジュールのサンプルに従って、キャリブレーションを実施します。
以下の手順で行います。
- 何も載せていない状態で、プログラムを実行
- 分銅(重さが分かっているもの)を置いて、データを取得する
- データからキャリブレーション値(referenceUnit)を算出
何も載せていない状態で、プログラムを実行
以下がキャリブレーション用のコードとなります。
import time
import sys
import RPi.GPIO as GPIO
from hx711py.hx711 import HX711
PIN_DAT = 5
PIN_CLK = 6
referenceUnit = 1 # <=これを決めたい
def cleanAndExit():
print("Cleaning...")
GPIO.cleanup()
print("Bye!")
sys.exit()
def main():
hx = HX711(PIN_DAT, PIN_CLK)
# データの並び順を指定
hx.set_reading_format("MSB", "MSB")
# キャリブレーション値を設定
hx.set_reference_unit(referenceUnit)
hx.reset()
hx.tare()
print("Tare done! Add weight now...")
while True:
try:
# Prints the weight.
val = hx.get_weight(5)
print(val)
hx.power_down()
hx.power_up()
time.sleep(0.1)
except (KeyboardInterrupt, SystemExit):
panel.display_clear()
cleanAndExit()
if __name__ == "__main__":
main()
プログラムを実行します。
(env) $ python samp_calibration.py
Tare done! Add weight now...
18.333333333328483
-3.6666666666715173
16.333333333328483
...
何も載っていない場合は、小さな値が行ったり来たりするようです。
分銅(重さが分かっているもの)を置いて、データを取得
今回、手持ちの分銅(200g)を使用しました。
分銅を載せると、プログラムの結果が以下のように変わります。
(env) $ python samp_calibration.py
Tare done! Add weight now...
18.333333333328483
-3.6666666666715173
16.333333333328483
-7.444444444437977
61824.55555555556 # <=分銅を載せた
92595.55555555556
94617.55555555556 # <= データが安定している
94591.55555555556 # <= データが安定している
94584.55555555556 # <= データが安定している
94592.55555555556 # <= データが安定している
94591.55555555556 # <= データが安定している
94613.55555555556 # <= データが安定している
94639.55555555556 # <= データが安定している
94630.55555555556 # <= データが安定している
略
94621.55555555556 # <= データが安定している
94621.55555555556 # <= データが安定している
データからキャリブレーション値(referenceUnit)を算出
"データが安定している"から平均値を算出し、リファレンスの重さ(g)で割ります。
今回の例だと以下となります。
# 分銅の重さ
REF_OMOSA = 200
# データの取得
SAMP_DATAS = [
94617.55555555556, 94591.55555555556, 94584.55555555556, 94592.55555555556,
94591.55555555556, 94613.55555555556, 94639.55555555556, 94630.55555555556,
94621.55555555556, 94621.55555555556, 94615.55555555556, 94643.55555555556,
94611.55555555556, 94614.55555555556, 94628.55555555556, 94596.55555555556,
94626.55555555556, 94600.55555555556, 94589.55555555556, 94591.55555555556,
94621.55555555556, 94618.55555555556, 94596.55555555556, 94622.55555555556,
94621.55555555556, 94548.55555555556, 94601.55555555556, 94595.55555555556,
94627.55555555556,
]
print("referenceUnit is ", sum(SAMP_DATAS) / len(SAMP_DATAS) //REF_OMOSA)
実行すると、
(env) $ python cal_ref.py
referenceUnit is 473.0
473であることが分かりました。
これでキャリブレーションが完了です。
ディスプレイと連動させる
ディスプレイの詳細は、以前書いた↓を参照してください。
hakari.pyとoled.pyを組み合わせて動作を確認します。
コード - 計測と表示
import time
import sys
import RPi.GPIO as GPIO
from hx711py.hx711 import HX711
from oled import Oled
PIN_DAT = 5
PIN_CLK = 6
# referenceUnit = 1
referenceUnit = 473 #<=算出した値
def cleanAndExit():
print("Cleaning...")
GPIO.cleanup()
print("Bye!")
sys.exit()
def main():
# 表示デバイスの作成
panel = Oled()
hx = HX711(PIN_DAT, PIN_CLK)
# データの並び順を指定
hx.set_reading_format("MSB", "MSB")
hx.set_reference_unit(referenceUnit)
hx.reset()
hx.tare()
print("Tare done! Add weight now...")
while True:
try:
# Prints the weight.
val = hx.get_weight(5)
print(val)
# データの表示
panel.display_weights(val)
hx.power_down()
hx.power_up()
time.sleep(0.1)
except (KeyboardInterrupt, SystemExit):
panel.display_clear()
cleanAndExit()
if __name__ == "__main__":
main()
表示のコードは以下となります。
import board
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
from time import sleep
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN
# SSD1306のピン設定
DEVICE_ADR = 0x3C
DISP_WIDTH = 128
DISP_HEIGHT = 64
class Oled():
def __init__(self, dev_adr=DEVICE_ADR, width=DISP_WIDTH, height=DISP_HEIGHT):
# Settings
RESET_PIN = digitalio.DigitalInOut(board.D4)
i2c = board.I2C()
self._oled = adafruit_ssd1306.SSD1306_I2C(width, height, i2c, addr=dev_adr, reset=RESET_PIN)
# Clear display.
self._oled.fill(0)
self._oled.show()
# load fonts
self._fonts = {}
self._fonts["28"] = ImageFont.truetype("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf", 28)
self._fonts["14"] = ImageFont.truetype("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf", 14)
return
def display_weights(self, gram):
# Draw the text
if gram < 1.0:
moji = "何も載ってないよ!"
fsize = "14"
else:
moji = str(Decimal(str(gram)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
moji += "gです"
fsize = "28"
# Create blank image for drawing.
image = Image.new("1", (self._oled.width, self._oled.height))
draw = ImageDraw.Draw(image)
# Write moji
draw.text((0, 0), moji, font=self._fonts[fsize], fill=255)
# Display image
self._oled.image(image)
self._oled.show()
def display_clear(self):
# Clear display.
self._oled.fill(0)
self._oled.show()
return
実行手順
(env) $ python hakari.py
デモのようにモノを置くと、重さが表示されます。
🔎ポイント
ロードセルモジュールの動作
ロードセルとは、力(質量、トルク)を検出するセンサーです。
今回は、ビーム型の5kgのモノを使っています。
- もっと重いものを計測したい場合は、最大20kg
- もっと軽いものを精度よく計測したい場合は、最大500g
を使用することもできます。
精度メモ
今回のリファレンスで確認したところ以下のような結果でした。
分銅の重さ | 取得データ |
---|---|
10g | 10.01~10.03 |
20g | 19.97~20.05 |
50g | 49.94~50.04 |
100g | 99.92~100.07 |
200g | 199.99~200.06 |
500g | 499.98~500.12 |
かなりの精度で取れています。
筐体がしっかりしていれば、様々なアプリケーションに応用できそうです。
さいごに
ラズパイの活用方法を
としてまとめ中です。
Discussion
大学生です。大学の講義でラズパイを使った作品を作っています。
kotaprojさんのラズパイを使って重さをはかるよという記事を参考にしてやっているのですが、「何も載せていない状態でプログラムを実行」というところのやり方が分かりません。詳しく教えてもらえたら助かります
何も載せていない状態とは、分銅などの重さのあるものを載せなていない状態という意味です。
この状態で、プログラムを実行し、出力される値を確認します。
極端に大きな値を行き来したり、値が一定の場合は、接続や筐体を疑うことにつながります。
こんにちは!
僕も大学でラズパイを使った作品を作る講義があり参考にさせてもらっているのですが、最後のモジュールのダウンロード際にメールアドレスとパスワード等を聞かれるのですが元のウェブサイトでアカウントを作成しなければならないのでしょうか?
gitコマンドのところでしょうか
githubの本レポジトリページより、"Code"からダウンロードできると思います。
はじめましてロードセルのセンサーの数値の異常について相談可能でしょうか?
わかることであれば大丈夫です
専門ではないので、あまり期待しないで頂けると助かります
ありがとうございます!
詳細をお伝えしたくオンラインでお打合せすることも可能ですか?
勝手ですが謝礼もお支払いさせてください。
今、旅行中のため、直近での対応は難しいです。
X(旧Twitter)しかSNSは行っていないので、@tw_kotatuに連絡いただければと思います。
自己紹介をみさせていただいたのですが、IoTのソリューションを提供しているとのこと。
本件、趣味レベルのなので、製品レベルのことは期待しないでください。
誠にありがとうございます。只今フォローさせて頂いたのですがDMが送れません。相互フォローにならないと送れないのでしょうか?
先ほどフォローしました
返信は遅くなります