산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

발 압력 분포를 정확하게 모니터링하는 스마트 인솔 제작하기

부품 및 소모품

부품 수량 비고
아두이노 MKR1000 1 대부분 3.3V/5V 와이파이 보드면 가능. 다만 ESP 보드는 이 프로젝트에서 부정확한 측정값을 반환하므로 비추천
힘 감지 저항 (FSR) 3 인터링크 모델 402 사용 (100N)
오픈빌드 와이어 케이블 (피트 단위) 1
저항 10k 옴 3
파워 뱅크 1
스파크펀 트리플 축 가속도계 브레이크아웃 - ADXL345 1

필요한 도구 및 기계

앱 및 온라인 서비스

프로젝트 소개

압력 측정은 이미 다양한 상황에서 활용됩니다. 보행 역학 정보를 제공하며 임상 상황과 스포츠 등 광범위한 응용 분야가 있습니다. 이 프로젝트에서는 센서를 사용해 체중 분포에 대한 통찰을 얻습니다. 실시간 압력 매핑 시각화도 포함해 데이터를 훨씬 쉽게 이해할 수 있게 했습니다.

필요 하드웨어

배선하기

발 압력 분포를 정확하게 모니터링하는 스마트 인솔 제작하기

회로에 대한 간단 메모:

FSR: 납땜 전 반드시 읽어보세요: FSR에 와이어를 납땜할 때 극도로 주의하세요. 기술이 확실하지 않다면 시도하지 마세요. 매우 빠르게 납땜하지 않으면 플라스틱이 녹습니다. 뼈저리게 배웠습니다...

FSR에는 양극/음극이 없으므로 극성 걱정은 안 해도 됩니다.

앞서 언급했듯 저항을 변경해 측정값을 원하는 범위로 스케일링할 수 있습니다.

접지/5V: 모든 센서가 5V 라인과 공통 라인에 납땜되어 있습니다.

가속도계: 프로젝트에 필요 없다면 가속도계를 생략해도 됩니다. 압력 측정만 원한다면 필수는 아니지만, 가속도 측정이나 보행 주기 분석이 필요하면 유용합니다. 이 튜토리얼에서는 엄밀히 필수는 아닙니다.

인솔에 하드웨어 부착하기

코드를 먼저 실행해 보고 하드웨어를 부착하는 것을 추천합니다. 납땜 실수가 있으면 그 시점에 발견할 수 있어, 재납땜이 필요할 경우 인솔 부착/탈착 번거로움을 줄일 수 있습니다.

FSR 세 개를 인솔 세 지점에 부착합니다. 왼쪽 위 FSR은 외반(eversion), 오른쪽 위 FSR은 내반(inversion), 뒤꿈치 FSR은 뒤꿈치 압력을 측정합니다. 적절한 FSR 위치는 걷는 동안 아날로그 값이 가장 많이 변하는 지점을 찾아 결정합니다.

테이프로 와이어를 고정하세요. 움직이면 FSR 측정에 간섭이 생길 수 있습니다. 인솔 바닥과 신발 안쪽에 벨크로 테이프를 붙여 인솔이 제자리에 있도록 했습니다.

가속도계를 사용하는 경우 신발 뒤꿈치 뒷면에 부착하세요. 양면 테이프를 사용했습니다.

발 압력 분포를 정확하게 모니터링하는 스마트 인솔 제작하기

힘 측정하기

이제 힘을 측정할 준비가 되었습니다. 참고: 다음 두 섹션에서는 Thinger.io 라이브러리 익숙함을 가정합니다. 자세한 내용은 'Thinger.io로 데이터 전송' 섹션 참조.

프로그램 헤더가 꽤 깁니다. 와이파이 연결 데이터 등 설정에 필요한 변수들과 전역 변수(대부분 배열)가 포함됩니다. 중요한 선택으로 배열을 최대한 활용했습니다. 각 FSR 센서별로 개별 배열 요소를 사용하는 방식입니다. 여기서는 배열 길이가 3입니다.

전역 변수를 너무 많이 쓰는 습관은 부작용 때문에 피해야 하지만, Thinger.io로 데이터를 전송하기 위해 여러 경우 필요했습니다.

코드는 주석으로 설명되어 있습니다. 단계별로 살펴보겠습니다. 전체 코드는 아래에서 다운로드 가능합니다.

#define _DEBUG_ // Serial Monitor 사용 가능하게 함
#include <WiFi101.h>
#include <ThingerWifi101.h>
#include <Wire.h> // 가속도계
#include <Adafruit_Sensor.h> // 가속도계
#include <Adafruit_ADXL345_U.h> // 가속도계
#include <Adafruit_NeoPixel.h>

#define USERNAME "yourUsername"
#define DEVICE_ID "yourDeviceID"
#define DEVICE_CREDENTIAL "yourDeviceCredential"
#define SSID "yourSSID"
#define SSID_PASSWORD "yourSSIDPassword"

// FSR 센서
#define noFSRs 3
#define FSR1 A1
#define FSR2 A2
#define FSR3 A3

float fsrVoltageArray[3];
float fsrForceArray[3];
float fsrWeightInGramsArray[3];
int pinArray[3] = {FSR1, FSR2, FSR3};
float forceMaxArray[3] = {100.0, 100.0, 100.0};
float million = 1000000.0;
float conversionToKgrams = 1.0/9.80665;
long K = 1000;
long R = 10*K;
long Vcc = 5000;
float voltageMax = 0.98 * Vcc;

ThingerWifi101 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

아직 다 이해 안 되어도 괜찮습니다. 나머지 코드를 보면 더 명확해질 것입니다.

결과를 시각화하기 위해 Thinger.io 와이파이 라이브러리를 사용합니다. 연결은 다음 줄로 설정:

ThingerWifi101 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

입력 인자는 Thinger.io 계정에서 얻으므로 먼저 계정을 설정해야 합니다.

setup() 함수에서 시리얼 연결을 먼저 설정한 후 와이파이 연결 생성 함수를 호출합니다.

void setup(void) {
  Serial.begin(115200);
  thing.add_wifi(SSID, SSID_PASSWORD);
}

void loop(void) {
  thing.handle();
}

다음으로 "pressure"라는 "thing"을 정의합니다. "thing"은 Thinger.io 라이브러리의 핵심 개념으로, 함수처럼 동작하지만 특수 구조를 가집니다. 클라우드로 결과 데이터를 전송하는 데 필요합니다. 자세한 내용은 'Thinger.io로 데이터 전송' 섹션 참조.

"pressure" thing은 세 FSR 센서 값을 읽어 시리얼 콘솔에 출력하고, 같은 값을 "out" 채널로 전송합니다. 이렇게 원시 입력 데이터를 쉽게 검증할 수 있습니다.

"voltage" thing에서는 전압 값을 읽어 "fsrReading" 지역 변수에 저장합니다. "map" 함수로 최소/최대 지원값 기준으로 스케일링해 "fsrVoltageArray" 배열에 반환합니다. for 루프로 각 FSR이 결과 배열의 고유한 위치를 갖도록 합니다.

주의: 모든 코드는 setup 함수 안에 넣으세요. loop 안에 넣지 마세요(익숙한 것과 다릅니다). Thinger.io 라이브러리는 loop 안의 코드를 처리하지 못합니다.

void setup(void) {
  Serial.begin(115200);
  thing.add_wifi(SSID, SSID_PASSWORD);
  
  /* FSR 센서 */
  thing["pressure"] >> [](pson & out) {
    out["FSR1"] = analogRead(FSR1);
    Serial.print("FSR1:"); Serial.println(analogRead(FSR1));
    out["FSR2"] = analogRead(FSR2);
    Serial.print("FSR2:"); Serial.println(analogRead(FSR2));
    out["FSR3"] = analogRead(FSR3);
    Serial.print("FSR3:"); Serial.println(analogRead(FSR3));
  };
  
  thing["voltage"] >> [](pson & out) {
    for (int FSR = 0; FSR < noFSRs; FSR++) {
      fsrVoltageArray[FSR] = 0.0;
      fsrForceArray[FSR] = 0.0;
      int fsrPin = pinArray[FSR];
      int fsrReading = analogRead(fsrPin);
      fsrVoltageArray[FSR] = (float) map(fsrReading, 0, 1023, 0, 5000);
    }
    out["FSR1voltage"] = fsrVoltageArray[0];
    out["FSR2voltage"] = fsrVoltageArray[1];
    out["FSR3voltage"] = fsrVoltageArray[2];
  };
  
  void loop(void) {
    thing.handle();
  }
}

for 루프 완료 후 값들이 "out" 출력 채널로 전송됩니다. 각 센서마다 "FSR1voltage" 같은 고유 문자열을 가집니다.

"newton" thing은 이 프로그램에서 가장 복잡한 함수입니다. 전압을 뉴턴 단위 힘으로 변환합니다. 다시 for 루프로 각 FSR별로 처리합니다.

전압 값이 너무 작거나 너무 큰 경우 등 여러 예외 상황을 구분해야 해 계산이 꽤 복잡합니다. 전압이 컷오프 값 사이에 있으면 기울기를 줄이기 위해 로그 함수를 사용해 힘을 계산합니다.

이 공식들은 근사치입니다. 각 센서마다 다소 다른 곡선을 가질 수 있지만 단순화를 위해 여기서는 구분하지 않습니다.

계산 결과는 "fsrForceArray"에 저장되고, 각 FSR별로 고유한 위치를 가집니다. 세 최종 값이 "out" 채널로 전송됩니다.

마지막 "thing" 함수인 "weight"는 뉴턴 단위 힘을 그램 단위 무게로 단순 변환합니다.

thing["newton"] >> [](pson & out) {
  for (int FSR = 0; FSR < noFSRs; FSR++) {
    float force_value = (forceMaxArray[FSR]/voltageMax) * fsrVoltageArray[FSR];
    if (fsrVoltageArray[FSR] < voltageMax) {
      if (force_value <= 1.00) {
        fsrForceArray[FSR] = 0.0;
      } else {
        fsrForceArray[FSR] = log10(force_value);
      }
    } else {
      fsrForceArray[FSR] = log10(forceMaxArray[FSR]);
      Serial.print("Cut off activated for FSR = "); Serial.println(FSR);
    }
  }
  out["FSR1newton"] = fsrForceArray[0];
  out["FSR2newton"] = fsrForceArray[1];
  out["FSR3newton"] = fsrForceArray[2];
};

thing["weight"] >> [](pson & out) {
  for (int FSR = 0; FSR < noFSRs; FSR++) {
    fsrWeightInGramsArray[FSR] = fsrForceArray[FSR] * conversionToKgrams * 1000.0;
  }
  out["FSR1weight"] = fsrWeightInGramsArray[0];
  out["FSR2weight"] = fsrWeightInGramsArray[1];
  out["FSR3weight"] = fsrWeightInGramsArray[2];
};

Thinger.io 대시보드 설정도 잊지 마세요. 어떻게 하는지 아시리라 봅니다.

힌트: 모든 게 정상 작동하면 대시보드가 아래와 비슷하게 보일 것입니다.

발 압력 분포를 정확하게 모니터링하는 스마트 인솔 제작하기

가속도 측정하기

이건 압력 측정보다 훨씬 쉽습니다. 헤더 부분에 코드를 추가해야 합니다. "Wire.h"(SDA/SCL 핀 통신용), "Adafruit_Sensor.h", "Adafruit_ADXL345_U.h" 라이브러리를 포함합니다. x, y, z 축 가속도를 측정하고 전송할 세 개의 새 전역 변수도 필요합니다.

앞서 추가한 라이브러리는 지우지 마세요. Thinger.io 연결에 필요합니다.

다음 코드 블록에서 가속도계 응답을 확인합니다. 응답 없으면 아무것도 하지 않습니다. 그렇지 않으면 범위를 설정하고 "accelerometer" thing을 실행합니다. 이 함수는 장치를 쿼리해 x, y, z 방향 가속도 세 값을 "out" 채널로 전송합니다.

이 코드는 아다프루트 예제 코드(File > Examples > Adafruit ADXL345)와 유사하지만, 불필요한 부분은 뺐습니다.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>

Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
int x = 0, y = 0, z = 0;

void setup(void) {
  Serial.begin(115200);
  if(!accel.begin()) {
    Serial.println("No ADXL345 detected");
  } else {
    accel.setRange(ADXL345_RANGE_16_G);
    thing["accelerometer"] >> [](pson& out){
      sensors_event_t event;
      accel.getEvent(&event);
      out["x"] = event.acceleration.x;
      out["y"] = event.acceleration.y;
      out["z"] = event.acceleration.z;
      Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" ");
      Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" ");
      Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.println(" m/s^2");
    };
  }
}

힌트: 위 코드 실행 후 출력은 아래 예시와 비슷해야 합니다.

발 압력 분포를 정확하게 모니터링하는 스마트 인솔 제작하기

모든 것 통합하기

전체 코드는 페이지 하단에서 확인하세요 :)

Thinger.io로 데이터 전송하기

이 라이브러리는 여기에 잘 문서화되어 있지만, "thing" 작성과 사용을 더 쉽게 만드는 중요한 정보를 소개합니다.

Thinger.io는 매우 방대한 라이브러리입니다. 여기선 우리 애플리케이션에 필요하고 사용된 기능만 다룹니다. 구조는 다음과 같습니다(닫는 중괄호 "}" 뒤에 세미콜론 ";") 주의):

thing[] >> [](pson& out)
{
  
};

이를 C++의 람다 함수라고 합니다. 정의를 시작하는 필수 첫 단어는 "thing"이며, 전체 함수를 "thing"이라고도 부릅니다.

문자열(예: thing["myFirstThing"])이 함수 이름을 부여합니다. 각 "thing"은 고유한 이름이 필요합니다.

">>" 기호는 이 "thing"이 출력 값만 가짐을 나타냅니다. 입력이 필요하면 "<<"로, 입출력 둘 다 필요하면 "="를 사용합니다. 우리 경우는 출력만 있습니다.

인자 "pson &out"은 출력 값이 "out"이라는 데이터 구조를 통해 전송됨을 의미합니다. "pson" 데이터 타입은 매우 유연해 다양한 변수 타입과 JSON 문서를 지원합니다.

우리 코드에서는 out[""] = value 형태로 값을 시각화 디스플레이로 전송합니다. 이는 프로그램 처음 부분의 ThingerWifi101 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL) 호출과 연결됩니다.

눈치채셨겠지만 loop 함수 안에는 일반적으로 많은 코드가 없습니다. "thing.handle()"만 호출하면 됩니다. 엔드포인트 호출과 스트림 리소스도 loop에서 가능합니다. 나머지 모든 코드는 정의한 "things"에서 처리됩니다.

"things" 안의 코드는 지속적으로 루프됩니다. 우리 경우처럼 데이터가 정기적으로 업데이트되면 계산을 "things" 안에 넣는 것이 중요합니다.

FAQ

아무 일도 안 일어나요!

와이어를 확인하세요. 이 레벨에서 뭔가 망가졌을 확률이 높습니다. 시리얼 모니터에 아무것도 안 뜨면 코드 첫 줄에 "#define _DEBUG_"가 있는지 확인하세요. TLS가 방해할 수도 있습니다. 비활성화할 수 있지만 주의하세요. Thinger.io 연결이 잘 되는지도 확인하세요.

출력이 예상과 달라요

업데이트가 필요한 모든 코드가 "thing" 안에 있나요? 밖에 있으면 업데이트되지 않습니다. ESP 기기들이 FSR 센서와 이유 없이 잘 안 작동하는 것도 발견했습니다.

출력이 정기적으로 업데이트되지 않아요

코드에 delay를 추가했나요? 지우세요 :) Thinger.io에서 새로고침 비율을 설정할 수 있습니다.

모든 출력을 한 그래프에 보고 싶어요

모든 코드를 단일 "thing" 안에 넣으세요

수고하셨습니다!

이 튜토리얼이 FSR 센서, 가속도계, Thinger.io 기초를 이해하는 데 도움이 되었길 바랍니다. 코드 개선 제안이 있으면 언제든 환영하며, 여러분의 창작물도 부끄러워하지 말고 공유해 주세요!

코드

Smart-Insole-Tutorial (아두이노)

이 튜토리얼의 전체 코드

#define _DEBUG_ // 다른 include 전에 와야 함, 아니면 보드 크래시 가능
/* 튜토리얼: https://www.hackster.io/projects/a5ceae */
#include <WiFi101.h>
#include <ThingerWifi101.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>

#define USERNAME "yourUsername"
#define DEVICE_ID "yourDevice"
#define DEVICE_CREDENTIAL "yourCredential"
#define SSID "yourSSID"
#define SSID_PASSWORD "yourSSIDPassword"

Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
int x = 0, y = 0, z = 0;

#define noFSRs 3
#define FSR1 A1
#define FSR2 A2
#define FSR3 A3

float fsrVoltageArray[3];
float fsrForceArray[3];
float fsrWeightInGramsArray[3];
int pinArray[3] = {FSR1, FSR2, FSR3};
float forceMaxArray[3] = {100.0, 100.0, 100.0};
float million = 1000000.0;
float conversionToKgrams = 1.0/9.80665;
long K = 1000;
long R = 10*K;
long Vcc = 5000;
float voltageMax = 0.98 * Vcc;

ThingerWifi101 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

void setup(void) {
  Serial.begin(115200);
  thing.add_wifi(SSID, SSID_PASSWORD);
  
  if(!accel.begin()) {
    Serial.println("No ADXL345 detected.");
  } else {
    accel.setRange(ADXL345_RANGE_16_G);
    thing["accelerometer"] >> [](pson& out){
      sensors_event_t event;
      accel.getEvent(&event);
      out["x"] = event.acceleration.x;
      out["y"] = event.acceleration.y;
      out["z"] = event.acceleration.z;
    };
  }
  
  /* FSR 센서 */
  thing["pressure"] >> [](pson & out) {
    out["FSR1"] = analogRead(FSR1);
    out["FSR2"] = analogRead(FSR2);
    out["FSR3"] = analogRead(FSR3);
  };
  
  thing["voltage"] >> [](pson & out) {
    for (int FSR = 0; FSR < noFSRs; FSR++) {
      fsrVoltageArray[FSR] = 0.0;
      fsrForceArray[FSR] = 0.0;
      int fsrPin = pinArray[FSR];
      int fsrReading = analogRead(fsrPin);
      fsrVoltageArray[FSR] = (float) map(fsrReading, 0, 1023, 0, 5000);
    }
    out["FSR1voltage"] = fsrVoltageArray[0];
    out["FSR2voltage"] = fsrVoltageArray[1];
    out["FSR3voltage"] = fsrVoltageArray[2];
  };
  
  thing["newton"] >> [](pson & out) {
    for (int FSR = 0; FSR < noFSRs; FSR++) {
      float force_value = (forceMaxArray[FSR]/voltageMax) * fsrVoltageArray[FSR];
      if (fsrVoltageArray[FSR] < voltageMax) {
        if (force_value <= 1.00) {
          fsrForceArray[FSR] = 0.0;
        } else {
          fsrForceArray[FSR] = log10(force_value);
        }
      } else {
        fsrForceArray[FSR] = log10(forceMaxArray[FSR]);
        Serial.print("Cut off activated for FSR = "); Serial.println(FSR);
      }
    }
    out["FSR1newton"] = fsrForceArray[0];
    out["FSR2newton"] = fsrForceArray[1];
    out["FSR3newton"] = fsrForceArray[2];
  };
  
  thing["weight"] >> [](pson & out) {
    for (int FSR = 0; FSR < noFSRs; FSR++) {
      fsrWeightInGramsArray[FSR] = fsrForceArray[FSR] * conversionToKgrams * 1000.0;
    }
    out["FSR1weight"] = fsrWeightInGramsArray[0];
    out["FSR2weight"] = fsrWeightInGramsArray[1];
    out["FSR3weight"] = fsrWeightInGramsArray[2];
  };
}

void loop(void) {
  thing.handle();
}

회로도

세 개의 FSR(전압 분할 회로)과 가속도계.

발 압력 분포를 정확하게 모니터링하는 스마트 인솔 제작하기

제조공정

  1. 스마트 바텐더: 라즈베리파이 기반 나만의 칵테일 스테이션 만들기
  2. ABB, 베어링 건강 모니터링 스마트 센서 출시로 가동 중단 시간 감축
  3. 스마트 홈 진화: 커넥티드 라이프의 미래가 담긴 것들
  4. IoT 투자 ROI 극대화: 실용 가이드
  5. 빌딩 관리 시스템(BMS): IoT로 스마트 시티 구현
  6. 파이썬 객체 메모리 사용량 측정: sys.getsizeof() 완벽 가이드
  7. 분기별 공급망 건강 검진: 원활한 운영 보장
  8. 아두이노 우노로 정밀 반응 속도 테스터 만들기
  9. 가정용 워터 펌프 수압 저하: 원인과 해결책
  10. 압축 공기 시스템의 압력 손실 최소화하기