[IoT] IoT 쌩초보 - 실전 Demo

Jihyeon Yun·2023년 3월 10일
0

IoT 도전기

목록 보기
7/7

드디어 마무리 단계이다.
사실 프로젝트는 2월 말에 끝났는데 귀국과 개강으로 블로그 작성이 조금 늦었다.

결론부터 말하자면
데모 영상을 찍기로 한 날 아침 왼발의 ESP32가 죽었다.
여기저기 다른 팀들에 여분의 ESP32가 있는지 물어봤는데 다들 프로젝트 막바지라 남아있는 곳이 없어서 결국 오른발로만 테스트할 수 밖에 없었다.
데모영상 첫 시도는 중간에 Application이 죽어서 실패.
건물이 있는 블럭을 크게 도는 것이 목표였는데 Application이 꺼지는 바람에 다시 돌아왔다.
두 번째 시도부터는 건물 주위를 한바퀴 도는 것으로 목표를 바꿨다.

Outdoor Test

  • experiment period: 02/23/2023
  • Route
  • average time: 1min 15sec
  • 그 외 Runner의 정보는 너무 개인적이므로 넘어가도록 하겠다.

전체 코드

#include <Adafruit_MPU6050.h>     // library for Inertial Measurement Unit(MPU6050) object
#include <Adafruit_Sensor.h>      // library for common sensor
#include <Wire.h>                 // library for communicate with I2C
#include <WiFi.h>                 // library for WiFi connect
#include <WiFiClientSecure.h>     // library for WiFi Secure
#include <ThingsBoard.h>          // library for connect ThingsBoard and ESP32
#include <ArduinoJson.h>          // library for JSON format(MQTT)


#define FORCE_SENSOR_PIN1 36 // ESP32 pin GIOP36 (ADC0): the FSR and 10K pulldown are connected to A0
#define FORCE_SENSOR_PIN2 39 // ESP32 pin GIOP39 (ADC3): the FSR and 10K pulldown are connected to A3
#define FORCE_SENSOR_PIN3 34 // ESP32 pin GIOP36 (ADC6): the FSR and 10K pulldown are connected to A6
#define FORCE_SENSOR_PIN4 35 // ESP32 pin GIOP36 (ADC7): the FSR and 10K pulldown are connected to A7
#define LED 2                // ESP32's built-in LED for checking status

// ESP32 will send data if "isRunning" is changed to 'true'
// the callback will be called for every shared attribute changed on the device
constexpr std::array<const char*, 1U> SUBSCRIBED_SHARED_ATTRIBUTES = {
  "isRunning"
};

// Baud rate for the debugging serial connection
constexpr uint32_t SERIAL_DEBUG_BAUD PROGMEM = 115200U;
// WiFi information
constexpr char WIFI_SSID[] PROGMEM = "YOUR_WIFI_SSID_NAME";
constexpr char WIFI_PASSWORD[] PROGMEM = "YOUR_WIFI_PASSWORD";
// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
constexpr char TOKEN[] PROGMEM = "YOUR_THINGSBOARD_DEVICE_TOKEN";
// Thingsboard we want to establish a connection too
constexpr char THINGSBOARD_SERVER[] PROGMEM = "YOUR_THINGSBOARD_SERVER_IP";
// MQTT port used to communicate with the server, 1883 is the default unencrypted MQTT port
constexpr uint16_t THINGSBOARD_PORT PROGMEM = 1883U;
// Maximum size packets will ever be sent or received by the underlying MQTT client
constexpr uint32_t MAX_MESSAGE_SIZE PROGMEM = 256U;
// Initialize underlying client, used to establish a connection
WiFiClient espClient;
// Initialize ThingsBoard instance with the maximum needed buffer size
ThingsBoardSized<MAX_MESSAGE_SIZE> tb(espClient);
//create mpu object
Adafruit_MPU6050 mpu;
// create variables for save FSR signal
int fsrReading1, fsrReading2, fsrReading3, fsrReading4;
// create variables for save IMU signal,
//instances to read sensor value
// a: accelerometer, g: gyroscope, temp : temmperature
sensors_event_t a, g, temp;   

// Statuses for subscribing shared attributes
bool subscribed = false;
// Change when Start/Stop Button is clicked
// true: user is running & false: user is stop
bool runningStatus = false;

/// @brief Initialzes Inertial Measurement Sensor,
/// setting accelerometer and gyroscope range, and filter's bandwidth
void InitMPU() {
  Wire.begin();
  while(!Serial){
    delay(100);
  }
  // finding MPU
  if(!mpu.begin()) {
    Serial.println("Failed to find mpu chip");   // code for debugging in Serial Monitor: when ESP failed to find MPU
    while(1) {
      delay(100);
    }
  }

  // MPU Setting start
  // The measurement range of accelerometer : 16g
  mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
  // The measurement range of Gyroscope: 250 dps
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  // Bandwidth of digital low pass filter (for callibration)
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  // Setting MPU end
  Serial.println("");   // code for debugging in Serial Monitor
  delay(100);
}

/// @brief Initalizes WiFi connection,
// will endlessly delay until a connection has been successfully established
void InitWiFi() {
  Serial.println("Connecting to AP ...");
  // Attempting to establish a connection to the given WiFi network
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  // checking WiFi connection
  while (WiFi.status() != WL_CONNECTED) {
    // Delay 500ms until a connection has been succesfully established
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
  // if WiFi is connected, built-in LED blinks once
  delay(100);
  digitalWrite(LED, HIGH);
  delay(100);
  digitalWrite(LED, LOW);
}

/// @brief Reconnects the WiFi uses InitWiFi if the connection has been removed
/// @return Returns true as soon as a connection has been established again
const bool reconnect() {
  // Check to ensure we aren't connected yet
  const wl_status_t status = WiFi.status();
  if (status == WL_CONNECTED) {
    return true;
  }
  // If we aren't establish a new connection to the given WiFi network
  InitWiFi();
  return true;
}
/// @brief callback function that called when the ThingsBoard's shared attribute is changed,
/// in this code, variable 'runningStatus' value will be replaced to "isRunning" value.
void processRunningStatusUpdate(const Shared_Attribute_Data &data) {
  // replace runningStatus's value to given isRunnning's value
  runningStatus = data["isRunning"];
  // check the runningStatus
  if(!runningStatus){
    // if runningStatus is _false_ send message to ThingsBoard that ESP32 is also stopped.
    tb.sendTelemetryData("isStop", true);
  }
  // When the shared attribute 'isRunning' is changed, built-in LED blinks 3 times.
  delay(100);
  digitalWrite(LED, HIGH);
  delay(100);
  digitalWrite(LED, LOW);
  delay(100);
  digitalWrite(LED, HIGH);
  delay(100);
  digitalWrite(LED, LOW);
  delay(100);
  digitalWrite(LED, HIGH);
  delay(100);
  digitalWrite(LED, LOW);
}

// callback when the shared attribute is changed
// it will check all shared attributes that includes in array "SUBSCRIBED_SHARED_ATTRIBUTES"
const Shared_Attribute_Callback callback(SUBSCRIBED_SHARED_ATTRIBUTES.cbegin(), SUBSCRIBED_SHARED_ATTRIBUTES.cend(), processRunningStatusUpdate);


// setup function for ESP32
void setup() {
  // If analog input pin 0 is unconnected, random analog
  // noise will cause the call to randomSeed() to generate
  // different seed numbers each time the sketch runs.
  // randomSeed() will then shuffle the random function.
  randomSeed(analogRead(0));
  // Initialize serial connection for debugging
  Serial.begin(SERIAL_DEBUG_BAUD);
  // set built-in LED for OUTPUT
  pinMode(LED, OUTPUT);
  // wait for a second
  delay(1000);
  InitWiFi();     // WiFi initializing
  InitMPU();      // MPU initializing
}

// ESP32 will conduct this code during its power is on
void loop() {
  // if the MPU6050's connection is lost, it will initialize MPU again.
  if(!mpu.begin()){
    InitMPU();
  }
  // if WiFi connection is lost, it will reconnect to WiFi
  if(WiFi.status() != WL_CONNECTED){
    reconnect();
  }
  // if ESP32 is not connected to ThingsBoard, it will try to connect with
  // ThinsgBoard Server IP, Device token, ThingsBoard MQTT port
  if(!tb.connected()) {
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if(!tb.connect(THINGSBOARD_SERVER, TOKEN, THINGSBOARD_PORT)) {
      Serial.println("Failed to connect");
      return;
    }

  }
  if(!subscribed) {
    tb.Shared_Attributes_Subscribe(callback);
    subscribed = true;
    // checking for subscription status, if subscribing success, built-in led will blink twice.
    delay(100);
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
  }
  // counting variable for sendingData
  int count = 0; 
  // when runningStatus is true, it will send data for 1s
  if (runningStatus) {
    while(count < 100){
      count++;
      sendData();
    }
  }
  tb.loop();
}

void sendData(){
  // Reading Start
  mpu.getEvent(&a, &g, &temp);
  fsrReading1 = analogRead(FORCE_SENSOR_PIN1);
  fsrReading2 = analogRead(FORCE_SENSOR_PIN2);
  fsrReading3 = analogRead(FORCE_SENSOR_PIN3);
  fsrReading4 = analogRead(FORCE_SENSOR_PIN4); 
  // Reading End

  // Make Json Document to send data
  StaticJsonDocument<500> SensorValues;
  SensorValues["acc_x"] = a.acceleration.x;   // MPU6050's acceleration value in x-axis direction
  SensorValues["acc_y"] = a.acceleration.y;   // MPU6050's acceleration value in y-axis direction
  SensorValues["acc_z"] = a.acceleration.z;   // MPU6050's acceleration value in z-axis direction
  SensorValues["gyro_x"] = g.gyro.x;          // MPU6050's gyro sensor value in x-axis direction
  SensorValues["gyro_y"] = g.gyro.y;          // MPU6050's gyro sensor value in y-axis direction
  SensorValues["gyro_z"] = g.gyro.z;          // MPU6050's gyro sensor value in z-axis direction
  SensorValues["fsr_1st"] = fsrReading1;      // The forefoot's force sensitive resistor value
  SensorValues["fsr_2nd"] = fsrReading2;      // The midfoot - left's force sensitive resistor value
  SensorValues["fsr_3rd"] = fsrReading3;      // The midfoot - right's force sensitive resistor value
  SensorValues["fsr_4th"] = fsrReading4;      // The rearfoot's force sensitive resistor value

  // Start sending data
  char buffer[500];
  serializeJson(SensorValues, buffer);
  tb.sendTelemetryJson(buffer);
  // End sending data

  delay(10);    //wait 0.01s for sending next data
}

Demo Video

왼발을 사용할 수 없던 게 너무 아쉽지만 그래도 어떻게 잘 끝마칠 수 있었다.
한국에 와서도 추가 작업을 할 수 있었다면 좋았겠지만 졸업 프로젝트가 또 처음 해보는 분야인 관계로...오른발로만 마무리를 지어야 할 것 같다.

더 많은 정보는 우리 팀 깃허브 에서 확인이 가능하다.
ESP32에 올린 코드 외에도 ThingsBoard의 RuleChain에 들어가는 부분이라든지 Flutter로 만든 Application 코드라든지 여러 개요들을 확인할 수 있다.

두 달간 진짜 쌩초보 상태에서 어떻게든 해냈다.
프로젝트 하나 끝!

0개의 댓글