重さを計る、ロードセルを使ってみました。
前回の豆知識で紹介した、2021年大学入学共通テスト 物理の、実際の使用例です。

電子回路は、ロードセル → HX711モジュール → Arduinoの流れです。
ロードセルは、ホイーストンブリッジの形にひずみゲージが貼られ、ひずみを電気信号にし、出力します。
ロードセルだけでは、重りを載せた際、うまくひずんでくれません。
そこで上手くひずむよう、2点で固定させています。
物を載せる面は、アクリル板を使い、乗せやすくなっています。
ロードセルを使うには、上手くひずませたり、物を乗せやすくするなど、工夫が必要な事が分かります。
|
|
|
|
|
5kgまで測定できるタイプです。 |
|
|
|
|
|
|
2点で固定し、ひずみやすくなっています。 |
|
円形のアクリルの上に、物をのせます。 |
ロードセル用のICは、HX711を使います。
HX711は、24ビットの信号を出力するADコンバーターです。
アンプとしての機能もあります。
ロードセルには、このICを使った、HX711モジュールが良く使われています(2021年2月現在)。
アマゾンだけでなく、秋月電子でも購入できます。
HX711使用 ロードセル用ADコンバータ モジュール基板 K-12370 ¥350
モジュールなので配線は、ロードセルにつなぐだけです。
Arduino側は、VCC(プラス5V)、GND(0V)、DT(データ線)、SCK(シリアルクロック)の4端子です。
HX711のデータシートに記載されたクロックを、ArduinoからHX711へ入力すると、HX711からArduinoへシリアル24ビットでデータが送られきます。
HX711から送られてくるデータの値は、HX711独特のデータです。
データシートを見ると、2の補数と記載されています。

Arduinoの配線は、簡単です。
HX711モジュールからきている線を、配線します。
VCC(プラス5V)、GND(0V)はArduinoの電源端子に、DT(データ線)は8番端子、SCK(シリアルクロック)は9番端子です。
別に8番端子と9番端子以外でも良いのですが、ネットの情報に8番と9番を使う事が多いので、同じようにしました。

プログラムは、HX711モジュールから値を読み出すプログラムが、データーシートに記載されています。
アセンブリとCの2つが記載されています。
今回は、Arduinoに移植するため、Cを参考にしました。
Arduinoのスケッチに、移植したソースは、これです。
ロードセルからの信号を値にし、Arduinoのシリアルコンソール画面に表示します。
値は、HX711特有の値なので、gやkgではありません。
Arduinoに書き込み、重りを載せると、数字が変わるのが分かります。
プログラム1 Arduinoのシリアルコンソール画面に、値を出力するプログラム
void setup() {
Serial.begin(9600);
pinMode(9, OUTPUT);
pinMode(8, INPUT);
}
void loop() {
long atai=0;
for (char i = 0; i < 24; i++) {
digitalWrite(9, 1);
delayMicroseconds(1);
digitalWrite(9, 0);
delayMicroseconds(1);
atai = (atai << 1) | (digitalRead(8));
}
atai = atai ^ 0x800000;
Serial.println(atai);
delay(300);
} |

↑右上のコンソール画面の数字が、パラパラ変わります。
プログラム1では使い難いので、g表示になるように追記したプログラムが、プログラム2です。
setupで、何も乗っていない時の値を1回だけ読み込みます。
重さを測定した結果は、omosa = ((atai - saisyo) / 1000) *2.2;の部分です。
測定結果ataiから、何ものっていない時の値saisyoをひいています。
さらにHX711特有の値は桁数が大きいので、1000で割っています。
2.2の部分は、g換算している部分です。
g換算にする式の求め方は、次のとおりです。
1kgの重りを乗せた時、HX711特有の値を求めます。
求めたHX711特有の値が1kgのため、
求めたHX711特有の値 × g換算する係数 = 1kg
これを計算すると、
g換算する係数=2.2でした。
値の微調整は、
omosa = ((atai - saisyo) / 1000) *2.2;の式の中で行えば良いです。
プログラム2 g表示にしたプログラム
long saisyo = 0;
void setup() {
Serial.begin(9600);
pinMode(9, OUTPUT);
pinMode(8, INPUT);
delay(300);
for (char i = 0; i < 24; i++) {
digitalWrite(9, 1);
delayMicroseconds(1);
digitalWrite(9, 0);
delayMicroseconds(1);
saisyo = (saisyo << 1) | (digitalRead(8));
}
saisyo = saisyo ^ 0x800000;
}
void loop() {
long atai = 0;
for (char i = 0; i < 24; i++) {
digitalWrite(9, 1);
delayMicroseconds(1);
digitalWrite(9, 0);
delayMicroseconds(1);
atai = (atai << 1) | (digitalRead(8));
}
atai = atai ^ 0x800000;
long omosa;
omosa = ((atai - saisyo) / 1000) *2.2; //saisyoは何も乗っていない時の出力の値、桁が大きいので1000で割っている
Serial.println(omosa);
delay(300);
} |
測定すると、次のようになりました。
何も乗せていない時は、Arduinoのシリアルコンソール画面は、0と表示されています。
500gの鉛インゴットを乗せると、508と表示されます。
1000gの鉛インゴットを乗せると、1011と表示されます。
まだ、誤差があります。
シビアな値を求めるには、まだ改善の余地がありますが、重さがかかった、かからないといった、デジタルセンサーとして使うなら、すぐに使えます。
今回、データシートを見てプログラムしていますが、ArduinoのHX711ライブラリーが多く出回っています。
正確な測定をするなら、ライブラリーを使う事をお勧めします。
|
|
|
|
|
Arduinoのシリアルコンソール画面
やや誤差があります。
|
|
|
|
|
|
|
1000gのインゴットを乗せた所 |
|
1011と表示されています。
最初の220と886は、重りを載せた直後の値です。 |
ちなみに台全体をを引っ張ると、マイナスの表示になります。

小数まで表示できるようにすると、次のようになります。
だんだんソースが長くなり、見にくくなってきました。
小数部分は、ロードセルの置く場所、電圧の状況、外部からのノイズ、内部の熱ノイズなど、色々な影響をうえているようで、パラパラ変動します。
小数まで正確に測るには、小さな値用のロードセルを購入したり、ロードセルの電圧を一定にするなど、対策が必要のようです。
プログラム3 小数も表示できるようにしたプログラム
long saisyo = 0;
void setup() {
Serial.begin(9600);
pinMode(9, OUTPUT);
pinMode(8, INPUT);
delay(1000);
for (char i = 0; i < 24; i++) {
digitalWrite(9, 1);
delayMicroseconds(1);
digitalWrite(9, 0);
delayMicroseconds(1);
saisyo = (saisyo << 1) | (digitalRead(8));
}
saisyo = saisyo ^ 0x800000;
}
void loop() {
long atai = 0;
for (char i = 0; i < 24; i++) {
digitalWrite(9, 1);
delayMicroseconds(1);
digitalWrite(9, 0);
delayMicroseconds(1);
atai = (atai << 1) | (digitalRead(8));
}
atai = atai ^ 0x800000;
long omosa;
omosa = ((atai - saisyo) / 10) * 2.2;
Serial.print(omosa / 100); Serial.print(".");
long syousuu = ((atai - saisyo) / 10) * 2.2;
// Serial.println(syousuu);
byte a[4];
a[0] = (syousuu % 10); syousuu = syousuu / 10;
a[1] = (syousuu % 10); syousuu = syousuu / 10;
a[2] = (syousuu % 10); syousuu = syousuu / 10;
a[3] = (syousuu % 10);
Serial.print(a[1]); Serial.print(a[0]); Serial.println("g");
delay(500);
} |
ロードセルのようなアナログセンサーは、出力されるデータが、一般的に馴染みのない値2の補数で出力される事があります。
特に今回のように、重りをのせた場合(プラスの値)と、引っ張った場合(マイナスの値)を出力するため、HX711モジュールからは、2の補数として値が出力されます。
なぜ、2の補数として出力するかと言うと、現代のコンピューターは、基本的に0又は1を足し計算しているため、基本的に引き算の回路がありません。
ロードセルを引っ張った場合、マイナスの値を出力させますが、コンピュータはマイナスの概念がないので、マイナスの変わりに、2の補数を出力します。
【補数について】
補数は、コンピュータでマイナスを扱う時に使います。
コンピュータは、引き算の回路がないので、引き算をする場合やマイナスを表現する場合は、2の補数を使い処理します。
例えば、7−6=1です。
6の補数は、補数の定義より、10−6=4なので、4です。
7+6の補数 = 7+4 = 11 です。
十の位の1を無視すると、一の位は1です。
7−6=1 ですが、一の位は1と同じ値です。
このように、補数を使うと、足し算を使って、引き算が出来るようになります。
なぜ足し算が引き算になるかと言うと、たくさん足して桁をあげ、あがった位は無視し、下の位だけ考えているからです。
コンピュータが計算する箱の大きさが、8桁しか無い場合、9桁の位は保存できず、無視されてしまうからです。
ちなみに、7−6=1で、6の補数は4でしたが、これは10進法における補数です。
コンピュータは2進法なので、2の補数を使います。 |
【センサーから出力されるデータについて】
センサーから出力される値(アナログ値)は、大きく分けると5つの分類があります。
|
SBC |
CSB |
OBC |
COB |
CTC |
+フルスケール |
1111 |
0000 |
1111 |
0000 |
0111 |
2 |
0010 |
0001 |
1010 |
0101 |
0010 |
1 |
0001 |
0010 |
1001 |
0110 |
0001 |
0 |
0000 |
1111 |
1000 |
0111 |
0000 |
−1 |
− |
− |
0111 |
1000 |
1111 |
−2 |
− |
− |
0110 |
1001 |
1110 |
−フルスケール |
− |
− |
0000 |
1111 |
1000 |
|
コンプリメンタリ |
コンプリメンタリ |
2の補数 |
SBC(ストレート・バイナリー・コード)
CSB(コンプリメンタリ・ストレート・バイナリー・コード)
OBC(オフセット・バイナリー・コード)
COB(コンプリメンタリ・オフセット・バイナリー・コード)
CTC(コンプリメンタリ・2’S・コード)
※2進数表記です。
SBCは、単純な比例で出力されます。
CSBは、SBCの0と1を逆にしたものです。
OBCは、SBCとCSBはマイナス表現が出来ないので、マイナス表現を可能にするために生まれました。
ビット数は増えますが、中央の0を基準にした考え方です。
COBは、OBCの0と1を逆にしたものです。
CTCは、アナログ値の0と、基準の0000を合わせた考え方です。
OBCとCOBでも良かったのでしょうが、合わせたほうがしっくりくるため合わせた考え方です。
2の補数を使って表現していて、結論だけ言えば、OBCのMSBだけ反転したものです。
|
【C言語(Arduino言語)の宣言について】
プログラムでは、定数や変数を使う場合、intやlongなどで、宣言します。
intを見てみると、int と unsigned int の2種類があります。
intは、符号付き整数型で、値の範囲は-32768から32767までです。
負の数は2の補数で表現し、最上位のビットは符号ビットともいわれ、1だとマイナス、0だとプラスを意味します。
unsigned intは、符号なし整数型で、負の数が扱えず、0から65535までの正の数だけを格納します。
unsigned intは符号なしのため、符号ビットの概念がありません。
その代わり、沢山の正の数が格納できます。 |
今回のロードセルは、人間にとっては、2の補数で出力されても分からないため、人が分かる単位、gやkgなどに変換する必要があります。
Arduinoのスケッチで、atai = atai ^ 0x800000;の部分で、2の補数を符号付の整数にしています。
これでOBCの状態になりました。
ataiは、longで定義しているので、符号ビット付きです。
そのため、Arduinoのコンソール画面では、符号ビット付きの場合は、マイナス表示に変換してくれます。
今回作ったロードセルのプログラムで、
g換算は
omosa = ((atai - saisyo) / 1000) *2.2;の部分です。
omosaもlongで定義しているので、符号ビット付きです。
そのため、Arduinoのコンソール画面では、符号ビット付きの場合は、マイナス表示に変換してくれます。
まとめると、信号の流れは次のとおりになります。
ロードセルは、ひずみゲージの抵抗値を電圧に変換
↓
HX711で増幅し、2の補数で出力
↓
Arduinoのプログラムで2の補数を受信し、OBCへ変換
↓
Arduinoのプログラムで人が分かるgに変更
↓
Arduinoのコンソール画面は、符号付きの場合はマイナスを表示
(2021年2月5日(金)作成)
|