DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

猫の体重管理のためにスマートトイレを自作してみた ③ロードセルの読み取りコード作成

前回はロードセルを組み込んだ重量計本体を作りました。

dreamerdream.hateblo.jp

 

今回はロードセルを利用するためにESP32にコードを書き込みます。

いろいろ便利なライブラリがあるようですが、個人的には中身を見て弄りたいので、こちらのサイトに載っている秋月電子のサンプルコードを拝借させていただきます。

 

<参考サイト>

wscat.cattaka.net

 

<秋月のサイト>

akizukidenshi.com

 

サンプルソースをダウンロードします。

 

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単位ならなかなか正確に測れていそうです。

youtu.be

 

アルミホイルでロードセルの線をシールドする前に動作確認した値がこちらなので、もしかしたらシールドが効果を発揮したのかもしれません。

シールド前は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;
}

 

あとは猫が乗って降りたときの値を蓄積してサーバーへ飛ばしてやれば体重計はほぼ完成ですね。

 

後で思いついたのですが、重量計の上にキッチンスケーラーをおいてオフセット値としておけば、スケーラーの値との差分をリアルタイムで見比べることができます。

 

続き

dreamerdream.hateblo.jp

 

 

 

kampa.me