前回はロードセルを組み込んだ重量計本体を作りました。
今回はロードセルを利用するためにESP32にコードを書き込みます。
いろいろ便利なライブラリがあるようですが、個人的には中身を見て弄りたいので、こちらのサイトに載っている秋月電子のサンプルコードを拝借させていただきます。
<参考サイト>
<秋月のサイト>
サンプルソースをダウンロードします。
Amazonから送られてきたロードセルの詳細情報は不明ですが、秋月電子で販売されているこちらと同様のものだと仮定してデータシートを参考にすることにします。
<秋月で売られているロードセル>
ロードセル 4ポイント(薄型) 200kg(50kgx4): センサ一般 秋月電子通商-電子部品・ネット通販
ロードセル情報を書き換え
<HX711のデータシート 秋月電子>
http://akizukidenshi.com/download/ds/akizuki/ae-hx711_rev1_20180129.pdf
基準電圧はHX711内の20Kと8.2Kの分圧抵抗を利用して基準電圧と差異を求めているようです。グラム換算の関数は秋月のサンプルが5V(4.5~5.5V)用なので3.3V用に書き換える必要がありそうです。
よくわからない項目もありますが、こんなかんじ?
ひとまず、拝借したコードでそのままグラム換算した値をそのまま出してみました。
void loop() {
float data;
data = AE_HX711_getGram(1); //平均化しない
String S1 = String(data - offset, 2);
Serial.print("g:");
Serial.println(S1); // Print the String to the serial monitor
delay(1);}
ノイズを含めたセンサからの値が出力されます。(センサ値そのものではなく、上記秋月のコードでグラム換算しています。)
無事に重量の出力が確認できたら、キッチンスケーラーで100gの錘(ペットボトル含めた水の重量)を作って体重計の上に載せて誤差を確認しました。
中央だけでなく、4隅に置いた場合の値を確認しましたが、どこに置いても同じような値が取得できました。すばらしい!
確認したところ、100gの錘で約200g、200gの場合で約400gを出力しましたので、プログラムで補正1/2としました。(どうしてちょうど倍ぐらいの値が出力されているのかは謎だけど・・・まあいいです)
float AE_HX711_getGram(char num)
{
//基準電圧の分圧 HX711のデータシートから 20Kと8.2Kの抵抗分圧
#define HX711_R1 20000.0f
#define HX711_R2 8200.0f
//内部基準電圧(バンドギャップ電圧)。一般的には固定値
//5V=1.25とあるので、印加電圧の1/4? 3.3V/4 =0.825?
//#define HX711_VBG 1.25f <- 元データ
#define HX711_VBG 0.825f
//HX711_AVDD = 0.825 * ( ( 20000 + 8200.0) / 8200.0) = 2.83719512195121
//#define HX711_AVDD 4.2987f//(HX711_VBG* ( ( HX711_R1+HX711_R2)/HX711_R2)) <-元データ
#define HX711_AVDD 2.83719//1ビットあたりの電圧を表す。アナログ入力値を電圧に変換する際に使用
#define HX711_ADC1bit HX711_AVDD/16777216 //16777216=(2^24)
//プログラマブル・ゲイン・アンプ(PGA)のゲイン設定を表す。PGAはアナログ入力信号の増幅に使用され、正確な測定範囲を調整
#define HX711_PGA 128
//ADCから得られたデータをロードセルの重さに変換するためのスケーリングファクター。LOAD はロードセルの定格負荷。
//このスケーリングファクターによって、ADC値がロードセルの重さにどのように対応するかが計算される。
#define HX711_SCALE (OUT_VOL * HX711_AVDD / LOAD *HX711_PGA )
float data;
//指定回数だけADC値を読み取り、その平均値を計算
data = AE_HX711_Averaging( num )*HX711_ADC1bit;
data = (data / HX711_SCALE )/2; //<-ここを1/2に
return data;
}
実験中に猫が乗ってきたのでそのまま体重測定。
1g単位は難しいけど10g単位ならなかなか正確に測れていそうです。
アルミホイルでロードセルの線をシールドする前に動作確認した値がこちらなので、もしかしたらシールドが効果を発揮したのかもしれません。
シールド前は20gぐらいたまに大きく変化しています。
ここまでのロードセル用のコード。
(WiFi接続とかロードセルに不要な諸々のコードを切り取ったものなので、実際にこのままコンパイルするとどこかでエラーが出るかもしれません)
平均化は、ノイズ対策として、計測値の最大値と最小値を無視するという使用にしています。(他のブログで、「突然とんでもない値が出ることがある」と目にしたのですが、実験中に大きく値が飛ぶことはありませんでした。)
#include <Arduino.h>
void AE_HX711_Init(void);
void AE_HX711_Reset(void);
long AE_HX711_Read(void);
long AE_HX711_Averaging(long adc,char num);
float AE_HX711_getGram(char num);#define pin_dout 27
#define pin_slk 26//---------------------------------------------------//
// ロードセル シングルポイント( ビーム型) 50kG*4
//---------------------------------------------------//
#define OUT_VOL 0.001f //定格出力 [V]
#define LOAD 200000.0f //定格容量 [g]float offset;
void setup() {
Serial.begin(115200);Serial.println("AE_HX711 Init");
AE_HX711_Init();
AE_HX711_Reset();
delay(1000);
offset = AE_HX711_getGram(30);
Serial.println("offset : ");
Serial.println( offset );
}void loop() {
float data;
data = AE_HX711_getGram(10);
String S1 = String(data - offset, 2); // Convert float to String with 3 decimal places
Serial.print("g:");
Serial.println(S1); // Print the String to the serial monitor
delay(1);}
void AE_HX711_Init(void)
{
pinMode(pin_slk, OUTPUT);
pinMode(pin_dout, INPUT);
}void AE_HX711_Reset(void)
{
digitalWrite(pin_slk,1);
delayMicroseconds(100);
digitalWrite(pin_slk,0);
delayMicroseconds(100);
}long AE_HX711_Read(void)
{
long data=0;
while(digitalRead(pin_dout)!=0);
delayMicroseconds(10);
for(int i=0;i<24;i++)
{
digitalWrite(pin_slk,1);
delayMicroseconds(5);
digitalWrite(pin_slk,0);
delayMicroseconds(5);
data = (data<<1)|(digitalRead(pin_dout));
}
//Serial.println(data,HEX);
digitalWrite(pin_slk,1);
delayMicroseconds(10);
digitalWrite(pin_slk,0);
delayMicroseconds(10);
return data^0x800000;
}
/*
* 計測数+2で計測して最大と最小を除外する。
*/
long AE_HX711_Averaging(char num)
{
long sum = 0;// 最大値と最小値を保存
long maxVol = 0;
long minVol = 0;for (int i = 0; i < num + 2; i++)
{
long vol = AE_HX711_Read();
if ( i == 0 ){
maxVol = vol;
minVol = vol;
}if (vol > maxVol)
{
maxVol = vol;
}
if (vol < minVol)
{
minVol = vol;
}sum += vol;
}// 最大値と最小値を除いた合計を計算
sum -= maxVol + minVol;// 最大値と最小値を除いた合計を指定数で割って平均を返す
return sum / num;
}
float AE_HX711_getGram(char num)
{
//基準電圧の分圧 HX711のデータシートから 20Kと8.2Kの抵抗分圧
#define HX711_R1 20000.0f
#define HX711_R2 8200.0f
//内部基準電圧(バンドギャップ電圧)。一般的には固定値
//5V=1.25とあるので、印加電圧の1/4? 3.3V/4 =0.825?
//#define HX711_VBG 1.25f <- 元データ
#define HX711_VBG 0.825f
//HX711_AVDD = 0.825 * ( ( 20000 + 8200.0 ) / 8200.0 ) = 2.83719512195121
//#define HX711_AVDD 4.2987f//( HX711_VBG * ( ( HX711_R1+HX711_R2)/HX711_R2 ) ) <-元データ
#define HX711_AVDD 2.83719//1ビットあたりの電圧を表す。アナログ入力値を電圧に変換する際に使用
#define HX711_ADC1bit HX711_AVDD/16777216 //16777216=(2^24)
//プログラマブル・ゲイン・アンプ(PGA)のゲイン設定を表す。PGAはアナログ入力信号の増幅に使用され、正確な測定範囲を調整
#define HX711_PGA 128
//ADCから得られたデータをロードセルの重さに変換するためのスケーリングファクター。LOAD はロードセルの定格負荷。
//このスケーリングファクターによって、ADC値がロードセルの重さにどのように対応するかが計算される。
#define HX711_SCALE (OUT_VOL * HX711_AVDD / LOAD *HX711_PGA )
float data;
//指定回数だけADC値を読み取り、その平均値を計算
//data = AE_HX711_Averaging(AE_HX711_Read(),num)*HX711_ADC1bit;
data = AE_HX711_Averaging( num )*HX711_ADC1bit;
//Serial.println( HX711_AVDD);
//Serial.println( HX711_ADC1bit);
//Serial.println( HX711_SCALE);
//Serial.println( data);
data = (data / HX711_SCALE )/2;
return data;
}
あとは猫が乗って降りたときの値を蓄積してサーバーへ飛ばしてやれば体重計はほぼ完成ですね。
後で思いついたのですが、重量計の上にキッチンスケーラーをおいてオフセット値としておけば、スケーラーの値との差分をリアルタイムで見比べることができます。
続き