動機
うちの猫はかわいい。1歳、しろきじ、前の飼い主が飼えなくなって最近来た。
とにかく抱っこが大っ嫌いだ。なのでよほどのことがなければ抱っこなんてしない。
だから体重が量れない!
爪が切れない!!(寝ているときにそっと切らせてもらう)
抱っこがダメな猫のために、良い体重の測り方はないものか??
市販の体重計は使えないのか?
普通に乗ることがない
餌を置いても、体重計をONにすると逃げる。
遠くにいると体重が見えない。
オートオフ機能
WIFIでとばす体重計があるらしいが、いつ乗るかわからんしね
体重量るのがめんどくさくなってしまう。
かわいい猫よ!!!人類の英知をなめるなよ!!抱っこしなくても体重くらい量ってやる!
ってことで、産業用、研究用なら24時間重さを計測するなにか変な物があるはずや!!
それが・・・意外とないんですよね。。
「上皿自動秤」「ばねばかり」が一番それに近いんです。アナログだし24時間量ってるようなもんだし・・・
カメラ仕込めば24時間量れるなぁ・・っと
でもこれブニョブニョして猫がいそうなところに仕込めないんですよ。そもそも小さいし・・
物理的に負荷が延々かかっている状態って校正必要になるしなぁ・・・
重量センサーってないんですかね?って検索するとあるわ!。
こんな感じの金属
これから出る電圧をプリアンプ通してPCのオーディオインプットに入れたらいけるんじゃね??
96Khz24bitという無駄なサンプリングレートで体重を計測しまくるんや!!
(そもそもローカットされて入力されないじゃん!)
ってことでADコンバータにつなげる何かを・・・・そしたら
「ロードセル専用のA-DコンバータHX711」ってすげーー便利なもんがあるんですよ。
そうよね。。。あるよね。。センサーだもん。
AMAZONで早速購入!
「デジタルロードセル重量センサ20KGポータブル電子キッチンスケール HX711計量センサーモジュールArduinoと互換」
組み立て
いろいろ準備とかすっ飛ばしてこんな感じです。
20年ぶりくらいの電子工作ですよ!
ひさしぶりの半田付け・・・おっさんには・・こまかいっす。
余っていたRaspberryPiを使います。
AMAZONクオリティーなので配線図?とかデータシートとか一切なし。基盤透かして確認しました。
秋月電子でちゃんとしたの買ってください。安いし。。
1時間ほどしらべて、チップのどの足がどれにつながっていればいいか、やっとわかりました。。
(こちとら素人なんだよ)
くみたて、なんでグルーガン?ってのは・・・・この板に取り付けたからです。
400*350の板に設置したら、ユラユラでかさ上げしないと接地しちゃうんです。
かさ上げにはナットを使ってるんですが、この設置個所だと一度ナットを積み上げないといけないのでグルーガンです。
で・・・・
https://github.com/tatobari/hx711py.git
をcloneして校正して・・・
qiita的にここが重要だろう!!と思いますが他のqiitaの記事にあるのでそこは書きません。
今回は「猫と体重計」です!!
取得したデータをElasticsearchへ送ってKibana で確認。
一秒単位のグラフです。
猫があそんでるときに、たまたま計測した
世界で一番しょうもないと思われるElasticsearchとKibanaの使い方です。
なにも重さがかかってないときでも、+-4gほどノイズが乗るんですよ。
さらに最大20グラムの大きな波が30分間隔であるっぽい。
ここからが本題
このままだと、ユラユラでブニョブニョしてロードセルにしっかりと荷重がかからない。
ユラユラ揺れるので猫が乗らないという実用に耐えられない体重計が出来上がってしまいました。
これじゃぁー人間の体重計にもならん。
工作中にたまたま獣医師さんが見に来て、
「なにやってんすか(笑)」
「だっこできないから・・・人類の英知で・・・」
「ねこの体重そんなに量らなくていいですから!(笑)」
というやりとりをする
本気出すぜ
もうここまで来たら引き下がれません。4ポイントでささえます。
秋月電子へ発注!
秋月電子のHX711は秒10回のサンプリング固定みたいです。
1枚で2つのロードセルを接続できます。
このターミナルって部品がね・・よくわからなくて。。ジョイントできるんですよ。
1枚はしらなくて無理やりくっつけた。
いろいろすっ飛ばしてこんな感じです。
困ったときのダクトテープです!
DIYだ!!
RaspberryPiの設置部分がなくて・・・収まりどころが悪くて・・・
ノミで削って・・・ノミの刃が切れなくて苦しかった。
こんな感じです。
プログラム
上記のgithubのソースを変えていきます。
hx = HX711(5, 6)
hx.set_reading_format("MSB", "MSB")
hx.set_reference_unit_A(104.2003)
hx.set_reference_unit_B(-24.513)
hx.reset()
hx2 = HX711(13, 19)
hx2.set_reading_format("MSB", "MSB")
hx2.set_reference_unit_A(103.3425)
hx2.set_reference_unit_B(-23.62031)
hx2.reset()
hx.tare_A()
hx.tare_B()
hx2.tare_A()
hx2.tare_B()
while True:
try:
val_A = hx.get_weight_A(5)
val_B = hx.get_weight_B(5)
val_C = hx2.get_weight_A(5)
val_D = hx2.get_weight_B(5)
val=val_A+val_B+val_C+val_D
print(val, val_A, val_B, val_C, val_D)
hx.power_down()
hx.power_up()
hx2.power_down()
hx2.power_up()
time.sleep(0.8)
except (KeyboardInterrupt, SystemExit):
cleanAndExit()
2枚のHX711を使うので、二つのインスタンスを作ります。
4ポイントあるので合算します。
実際に使ってみてわかったこと
- hx711のデータシートを見るとBチャンネルはおまけみたいな感じでgain32固定です。
- 英語の理解が正しいかよくわかりませんがBチャンネルを使うには5Vを入力しろって書いてあります。
- Bチャンネルの入力は逆相になってる。(だからマイナスが返ってくる)
- Bチャンネルのgainが小さいからreferenceUnitが小さい
バグ
https://github.com/tatobari/hx711py/blob/master/hx711.py
のコードが間違っているので修正します。
def get_reference_unit(self):
return get_reference_unit_A()
selfがないので
def get_reference_unit(self):
return self.get_reference_unit_A()
こんな感じで修正。
完成!!
3700グラム付近を指しています。
寝始めから1時間後に20グラムほど軽くなってます。これは水分が抜けているのか??20グラムの波なのか??
猫がこのベッドで寝ている時間が分かるのでスゴイなぁ
ちょっと前に獣医師のところに行って量ったときは3666グラムでしたので誤差ですね。(餌とか水分とか)
久しぶりに半田つかったので楽しかったです。
追記:設置から48時間ほど経過したデータ
10グラム毎のヒストグラム(回数)です。3690グラムが一番多い
良い分布してる
追記2019-12-14 : 設置から1週間くらいたった
日ごとのデータをヒストグラム化した
横軸にグラム、縦軸にそのグラムを計測した回数。
計測回数が多いバケットほど正しいと思われる。
これなら猫の体重変動を余すことなく把握できる。
ベッドにいる時間の計測
簡単に出せるので分単位を日ごとに出してみました。
0の行は3500グラム以下(ノイズだし)を0に変えています。
朝5時30分にはニャーニャーうるさいので、この時間は決まって起きちゃうんでしょう。
1分でも計測した場合ベッドに居たことにしてベットにいる時間を合計してみます。
- 2019/12/09,372分,6.2時間
- 2019/12/10,460分,7.6時間
- 2019/12/11,646分,10.7時間
- 2019/12/12,771分,12.8時間
- 2019/12/13,570分,9.5時間
これは最低でもベッドに居る時間なので、ほかで寝てる時間はわからないが・・
すやすや寝てダラダラと幸せに過ごしてほしい
2019/12/15 追記:ロードセルの大きな波の原因は・・・
ノイズではなく温度ではないか?。
18:00に暖房をONにしてどんどん重さが上がっていき
19:15あたりの温度が26.5度、熱いので暖房をOFFにした時刻
20:00過ぎの温度が22度、こりゃ温度だな。
2020/01/02 追記:ロードセルに温度計張り付けて誤差を修正する
「Raspberry Pi DS18B20」 で検索するとワラワラでてくるので、ラズベリーパイで計測できるようにする。
DS18B20は1信号線で温度が計測できる。
parasite power modeという電源と信号線を共通で使おうと思ったら85000というエラー値が取れるだけでダメだったのでVDD,DQ,GNDを素直に接続して、プルアップ抵抗4.7KをDQ,VDDの間にいれた。
あとはコマンドをたたいて接続を確認する
#
sudo vi /boot/config.txt
#以下の設定を書き込む
dtoverlay=w1-gpio,gpiopin=4,pullup=no
sudo reboot
#w1の確認
lsmod | grep w1
#DS18B20の確認、28で始まるのがDS18B20
ls /sys/bus/w1/devices/
#温度を確認
cat /sys/bus/w1/devices/28-00000xxxxxx/w1_slave
pullup=noのpullupってのはpullup抵抗のことじゃないみたい。
信号線と電源を共通で使いたい場合に設定するみたい。
たぶん??電源を充電して信号を送り出すのでリアルタイム性がなくなるんだと思う。
今回は素直につないだのでnoにした。
↓DS18B20の足を半田付け&チューブで覆う
金属の菅に入っているのもあるんだけど、ロードセンサーにペッタリつけたいのでこんな感じのやつにした。
↓ユニバーサル基盤で2個のDS18B20をつなげる。
(VDDとGND逆につなぐと一気に高温になって持ってられないので注意!)
↓センサーの合体!!
センサーの結合にはインシュロックが一番具合がよかったです。
PYTHONプログラムはこちらの方
https://qiita.com/masato/items/cf5a27af696a27b73b86
の記事をコピペしました。
複数のセンサーに対応するので、ちょっと変えます。
↓どこをどう変えたかわからないので全部!
# -*- coding: utf-8 -*-
import os
import glob
import time
import subprocess
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
def read_temp_raw(deviceId):
base_dir = '/sys/bus/w1/devices/'+deviceId
device_file = base_dir + '/w1_slave'
catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out,err = catdata.communicate()
out_decode = out.decode('utf-8')
lines = out_decode.split('\n')
return lines
def read_temp(deviceId):
lines = read_temp_raw(deviceId)
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw(deviceId)
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
#temp_f = temp_c * 9.0 / 5.0 + 32.0
return temp_c
w1.pyで保存
温度と重さの関係をしらべる計測
アルミは金属なので温度で歪む。歪むから重さが変わる。
金属の歪って数百グラム載せただけじゃ誤差やろ?(歪パワーすごすぎて)と思い、無負荷でおこなった。
やったことは・・・正月なので・・そとに出して、部屋に入れれば行って来いでなんか取れそうなので・・・
外にだして5度くらいまで冷やす。そのあと部屋の中にいれて25度付近まで温めるという作業をしました。
↑横が温度。縦がA/Dの生値の散布図
きれいな直線とにフニャフニャした線がみえる
よくわからん。。がなんか傾いてる。。
なるほど・・・ロードセルが温度の影響を受けるのに時間がかかるんだ。。。
だから、温度と重さの相関がいい感じではないんだ。ゆっくり温度が変化していくか、温度を固定させるしかない。
セル毎にいい感じの部分だけをとりだして・・・・・・とは行かない。
セル毎にやるなら、4セル全部に温度センサーを結合しないとダメなやつなので
温度センサーとこの体重計全体の重さのいい感じの部分だけを散布図に起こす。
あら・・きれい。
疑似曲線を描いて、数式をだして・・・・2.9613って数字がでました。
ねんのためにSLOPE関数でも確認して1度あたりの重さの傾きは2.96132とでました。
温度の影響を打ち消すプログラム
重さを取る部分と混ぜる
import w1
start_temp = (temp_a+temp_c)/2
while True:
#重さとる
val_A = hx.get_weight_A(5)
val_B = hx.get_weight_B(5)
val_C = hx2.get_weight_A(5)
val_D = hx2.get_weight_B(5)
val=val_A+val_B+val_C+val_D
print('w',val, val_A, val_B, val_C, val_D)
#温度とる
temp_a = w1.read_temp('28-00000a72xxxx')
temp_b=0.0
temp_c = w1.read_temp('28-00000a72yyyy')
temp_d=0.0
dif_temp= ((temp_a + temp_c) / 2)-start_temp
#+方向だと1度あたり2.96132重くなる
print('補正前,補正後,補正値',val,val-dif_temp*2.96132,dif_temp*2.96132)
やってみてわかったこと
-
全部のロードセルにつけたかったのですが、DS18B20にリード線付ける半田付けが死ぬほどめんどかったので2個にしました。
2個あれば個体差確認できるやろ?くらいな感じでした。
ちなみに、DS18B20の個体差はわかりませんでしたがロードセルが温度に影響する個体差はあるようで・・・
ちょっと全部に取り付けないと精密に温度によって変化する重さを吸収できないなぁーという感じです。 -
ロードセル毎に無負荷状態生値がすごい違う。(283000、150000くらい違う)
-
温度を足したり割ったりしてるのがすごい気持ち悪い
けど・・・どうして美しい回帰直線(2.96132)がでるんだろう?温度範囲が狭い?0~80度までとったら、グニャグニャしてるんだろうか?
おまけのうれしいこと
思わぬことで、部屋の温度もKibana で管理できるようになった。
正月から何してんだろう。。。
2020/01/05 追記:ロードセルは温度補償されてるらしい
傾きを追い込んでみたら、うまく行かなった。というより悪くならなかった。
温度が下がっても重さが変わらないポイントがある。
補正がかかってるのかな?
調べてみたら温度補償というらしい。
秋月電子の「ロードセル シングルポイント(ビーム型) SC133 20kg」にそれがあるのかわからないけど・・・上のグラフを見る限り温度補償されてる??
なので、プログラムから温度補正の計算を外したほうがいい結果がでそうだ。
そもそも製品精度のスペックがでてるんだろうか?
秋月電子の説明には、「精度:0.05%(フルスケールに対して)」とあるので、20Kgの0.05%は10グラムになる。
載せている重さが307g、上のグラフでは283.2gが下限なので、誤差23.8gになる。
4ポイントで支えているので5.95gの誤差。
温度影響を受けて5.95gなのでスペックでてるじゃん!
20Kのセルよりもっと小さい重さをはかれるセルにしたほうが良いってことですね。。
2020/09/20 追記:壊れた
**人間が膝たてて乗ってしまいパックリ割れてしまった!!**人間にケガなくてよかった。
ラワン材だから強度もなかったし・・・しょうがない。
物作りの難しさを痛感しました。人乗るな!って書いておこう。
対策
木はだめだな・・・
鉄板を買いました。
400mm × 400mm 2.3mm厚です。
重い!頑丈だけど重い!これ落としたらダメなやつだ。
足の上に落としたらケガする。
鉄はあかんのでアルミ板買いました。
400mm × 400mm 2.0mm厚です。
んーーーもうちょい厚いのがよかった・・
ちゃんとした製品でした。コーナー丸加工やバリなどが無いのでケガのリスクは低いです。
ケガいて、穴開けて。じゃーーん
コの字金具、スペーサーなどを入れて厚みを出しています。
ラズパイを中に入れたほうが都合がいいのでね。。。
あとラズパイの発熱が結構きつい。8月の猛暑で心配になり計測を止めてしまいました。
なのでCPUの速度を可能な限り落として運用します。
/boot/config.txtに以下を追加!
# CPU freqencies
force_turbo=0
arm_freq=600
arm_freq_min=300
CPUは100だと起動しないです。
CPUの速度を落とすとDS18S20が正常にとれないようです。(自分のラズパイではそうなりました)
USBの先にあるのはTWELITE。猫部屋の端っこにセンサーを付けているのでそいつを受信している。
蓋をして完成!!
コレに128×64ドット有機ELディスプレイを付けたら体重計じゃん!!!と思った。
皿ねじを使ってるので皿取りしたんですが薄すぎて怖くて中途半端になりました。アルミ板は3ミリくらいがいい。
初号機と比べて、だいぶ成長した。
もっと小さくしたらいいかな?とは思うんですが。猫がいそうなところに仕掛けて猫がゆったり過ごせることを考えると長辺で400mmはほしいんです。
そうすると人間が乗れちゃう大きさになってしまうので難しいところですね。
10カ月弱運用してきて季節やら温度やらトラブルやらを乗り越えてきたのでノウハウがたまってきましたよ。
本当はESP化してコストダウンしたいのですがラズパイで動いてるしね売るわけでもないしね
猫場所がたくさんあるので、全部に設置したいけどね