본문 바로가기

카테고리 없음

[Arduino] 무게 측정 센서 Load Cell을 이용하여 저울 만들기

아두이노를 통해 무게를 측정하기 위해서 주로 로드셀 모듈을 이용한다.

로드셀에는 가변저항 역할을 하는 스트레인 게이지가 포함되어 있다. 로드셀에 무게가 가해지면 스트레인 게이지가 변형되는 정도에 따라 저항값이 변하게 되고 이때 발생하는 전기 신호를 통해 무게를 측정할 수 있게 된다.

그러나 로드셀에서 발생하는 전기신호는 매우 미세하기 때문에 HX711 증폭기와 함께 사용하는 것이 일반적이다.

이미 로드셀을 통해 무게를 측정하는 좋은 라이브러리가 개발되어 있기 때문에 해당 라이브러리의 예제를 살펴보고 응용하여 간단한 저울을 제작해보았다.

 

1. 회로 구성 및 로드셀 조립

로드셀에는 전원용 케이블 2개와 시그널 케이블 2개가 존재하는데 이들을 HX711 증폭기의 input 단자에 아래 그림과 같이 연결해주면 된다.

그 후, HX711 증폭기의 output 단자는 아두이노의 D2와 D3핀에 연결해주었다.

아두이노 나노에 로드셀을 결선한 모습

 

로드셀을 다룰 때, 물리적으로 올바르게 구성하는 것은 회로 결선 못지않게 중요한 일이다.

이를 위해 두 개의 평평한 판을 로드셀 위쪽과 아래쪽에 조립하여 사용하는 것이 일반적이다.

로드셀에는 아래 사진과 같이 조립을 위한 4개의 나사 구멍이 있으며 측정 가능한 최대 무게와 힘이 가해지는 방향이 표기되어 있다.

힘의 방향을 표기 한 스티커를 기준으로 가까운 2개의 구멍에는 위쪽 판을, 반대쪽 2개의 구멍에는 아래쪽 판을 연결하면 로드셀의 측정 방향에 맞게 무게가 가해지게 된다.

3d 프린터를 이용하여 적당한 판을 출력 후 조립 해주었다.

 

(왼쪽) 로드셀 모듈에 힘의 방향이 표기되어있는 모습. (오른쪽) 힘의 방향에 맞춰 평평한 판을 조립한 모

2. Calibration

HX711 증폭기를 이용하여 로드셀에 가해진 무게를 측정하기 위해 Rob Tillaart의 HX711 라이브러리를 사용했다.

해당 라이브러리는 아두이노 IDE의 라이브러리 매니저에서 다운로드할 수 있다. (이유는 모르겠지만, 공식 문서의 GitHub주소로는 더 이상 배포를 하지 않는 것 같다.)

 

이제, HX711 라이브러리의 몇 가지 예제들을 통해 작동 원리를 파악해보자.

아래 코드는 첫 번째 예제인 HX_calibration 코드이다.

해당 코드에서는 로드셀의 측정값은 기기마다 차이가 있을 수 있기 때문에 이를 보정하기 위한 동작을 한다.

#include "HX711.h"
HX711 myScale;

uint8_t dataPin =  3;   //HX711의 데이터(DT)핀
uint8_t clockPin = 2;  //HX711의 클럭(SCK)핀

uint32_t start, stop;
volatile float f;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("LIBRARY VERSION: ");
  Serial.println(HX711_LIB_VERSION);
  Serial.println();
  myScale.begin(dataPin, clockPin);
}

void loop()
{
  calibrate();
}

void calibrate()
{
  Serial.println("\n\nCALIBRATION\n===========");
  Serial.println("remove all weight from the loadcell");
  //  flush Serial input
  while (Serial.available()) Serial.read();
  Serial.println("and press enter\n");
  while (Serial.available() == 0);
  Serial.println("Determine zero weight offset");
  myScale.tare(20);  // average 20 measurements.
  uint32_t offset = myScale.get_offset();
  Serial.print("OFFSET: ");
  Serial.println(offset);
  Serial.println();
  Serial.println("place a weight on the loadcell");
  //  flush Serial input
  while (Serial.available()) Serial.read();
  Serial.println("enter the weight in (whole) grams and press enter");
  uint32_t weight = 0;
  while (Serial.peek() != '\n')
  {
    if (Serial.available())
    {
      char ch = Serial.read();
      if (isdigit(ch))
      {
        weight *= 10;
        weight = weight + (ch - '0');
      }
    }
  }
  Serial.print("WEIGHT: ");
  Serial.println(weight);
  myScale.calibrate_scale(weight, 20);
  float scale = myScale.get_scale();
  Serial.print("SCALE:  ");
  Serial.println(scale, 6);
  Serial.print("\nuse scale.set_offset(");
  Serial.print(offset);
  Serial.print("); and scale.set_scale(");
  Serial.print(scale, 6);
  Serial.print(");\n");
  Serial.println("in the setup of your project");
  Serial.println("\n\n");
}

 

dataPin과 clockPin은 각각 HX711의 DT핀과 SCK핀을 의미한다.

나는 이들을 아두이노의 D3과 D2핀에 연결했기 때문에 각각 3과 2로 설정했다.

 

코드를 실행하면 무게를 가하지 않은 상태와 알고 있는 무게를 가한 상태 각각 한 번씩 센서를 측정하게 된다.

아래와 같이 시리얼 모니터에 나오는 지시대로 입력해 주면 정상적으로 실행된다.

 

HX_calibration 코드를 실행 한 결과

 

모든 과정을 마치면 scale.set_scale이라는 calibration 값을 얻게 된다. 

이제 이 값을 보정값으로 사용하면, 로드셀의 센서값을 정상적으로 무게로 변환할 수 있다.

 

3. 무게 측정

calibration을 통해 얻은 보정값을 이용하여 두 번째 예제인 HX_delta_scale 코드를 실행하면 로드셀에 가해진 무게를 측정할 수 있다.

아래 코드는 해당 예제 코드이다. scale.set_scale() 함수에 앞서 calibration을 통해 구한 보정값을 입력해 준다.

#include "HX711.h"
HX711 scale;

uint8_t dataPin = 3;
uint8_t clockPin = 2;
float w1, w2, previous = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("LIBRARY VERSION: ");
  Serial.println(HX711_LIB_VERSION);
  Serial.println();
  scale.begin(dataPin, clockPin);
  Serial.print("UNITS: ");
  Serial.println(scale.get_units(10));
  scale.set_scale(390.345611);       // 여기에 calibration에서 얻은 보정값을 입력
  scale.tare();
  Serial.print("UNITS: ");
  Serial.println(scale.get_units(10));
}

void loop()
{
  // read until stable
  w1 = scale.get_units(10);
  delay(100);
  w2 = scale.get_units();
  while (abs(w1 - w2) > 10)
  {
     w1 = w2;
     w2 = scale.get_units();
     delay(100);
  }
  Serial.print("UNITS: ");
  Serial.print(w1);
  if (w1 == 0)
  {
    Serial.println();
  }
  else
  {
    Serial.print("\t\tDELTA: ");
    Serial.println(w1 - previous);
    previous = w1;
  }
  delay(100);
}

 

아래 이미지는 코드를 실행시킨 결과이다. UNITS에 측정된 무게가 표기되고 DELTA에 이전 측정과의 무게 변화가 나타난다.

로드셀에 스마트폰을 올린 뒤 내린 결과

 

4. 무게를 LCD에 표기하기

이제 위 예제 코드를 응용하여 로드셀로 무게를 측정하여 LCD에 표기하는 코드를 작성해 보자.

LCD를 다루는 내용은 이전 포스팅을 참조하기 바란다.

2024.04.04 - [분류 전체보기] - [Arduino] I2C LCD 이용해보기

 

[Arduino] I2C LCD 이용해보기

아두이노 프로젝트를 진행하다 보면, 기기의 현재 상태나 사용 중인 데이터등을 눈으로 확인해야 하는 경우가 자주 발생한다. 시리얼 모니터를 통해 아두이노와 연결된 PC에서 확인하는 것이 가

silverstone.tistory.com

 

위 예제코드의 setup부분을 살펴보면 처음 실행 될 때,scale.set_scale()를 통해 calibration값을 보정한 이후 scale.tare()를 통해 영점 보정을 해주는 것을 알 수 있다. 

이를 이용하여 아두이노 D5핀에 스위치를 연결한 후, 스위치를 누를 때 저울이 영점 보정 되는 기능을 추가했다.

또한 위 예제 코드에서는 측정값을 소수점아래 2자리까지 나타내어 측정값이 미세하게 변하는 노이즈까지 표기가 되고 있었다. 따라서 노이즈를 표기하지 않기 위해 측정 정밀도를 낮춰 소수점 아래는 반올림해주었다.

 

#include <LiquidCrystal_I2C.h>     // LCD 라이브러리 포함
#include "HX711.h"                 // HX711 라이브러리 포함
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x3F for a 16 chars and 2 line display
HX711 scale;

uint8_t dataPin = 3;
uint8_t clockPin = 2;
float w1, w2, previous = 0;
const int sw = 5;

void setup()
{
  lcd.init();           // lcd 객체 초기화
  lcd.clear();          // 화면 초기화         
  lcd.backlight();      // 백라이트 on
  lcd.setCursor(2,0);   // 커서 옮김. 0행에 2열
  lcd.print("Loading...");	// 문자 출력
  pinMode(sw, INPUT);   // 스위치핀 인풋 설정
  scale.begin(dataPin, clockPin);  // HX711 객체 설정
  scale.set_scale(390.345611);       // calibration 보정 값
  scale.tare();         // 첫 실행 시 영점 보정
}

void loop()
{
  // read until stable
  w1 = scale.get_units(10);
  delay(100);
  w2 = scale.get_units();
  while (abs(w1 - w2) > 10)
  {
     w1 = w2;
     w2 = scale.get_units();
     delay(100);
  }

  int roundedWeight = round(w1);  //무게값 소수점 위로 반올림
  lcd.clear();         
  lcd.setCursor(3,0);   
  lcd.print("weight (g)");
  lcd.setCursor(6,1);   
  lcd.print(roundedWeight);

  if (roundedWeight == 0)
  {
    previous = previous ;
  }
  else
  {
    previous = roundedWeight;
  }
  delay(100);

  // Tare functionality
  if (digitalRead(sw)==HIGH) // 스위치를 누를경우 영점 보정
  {
    lcd.clear();
    lcd.setCursor(4,0);   
    lcd.print("Tare");
    scale.tare();
  }
}

 

 

아래는 코드를 실행한 모습니다. 전자저울을 통해 측정한 생수병의 무게 531.0g의 무게가 약 1g의 오차를 가지고 LCD에 측정되는 것을 볼 수 있다. 이후 스위치를 눌러 영점 조절을 한 뒤 생수병을 내리자 -531g이 표기된다.

 

여기서 재밌는 점은 사실 내가 사용한 전자저울도 3kg이 측정 가능한 로드셀로 만들어진 저울이다. 이렇게 시중에 판매되는 저울에서도 로드셀 모듈을 찾아볼 수 있다.

내가 아두이노로 구현한 저울과 차이점은 아마도 전자저울은 측정값의 노이즈를 이동평균값과 같은 방식으로 스무딩 하여 표기되고 있을 것이다. 이러한 기능 또한 아두이노를 이용하여 충분히 구현이 가능하다.

 

다음 기회에는 로드셀을 통해 3D프린터의 필라멘트의 남은 용량을 무게로 가늠할 수 있는 저울 겸 필라멘트 홀더를 제작하여 포스팅해 볼 예정이다.