Embedded/Arduino

Arduino Nano iot 33를 이용한 센서 데이터 전송 Beacon 만들어 보기

변화의 물결1 2024. 10. 16. 00:36

 

 

 

안녕하세요.

 

 Arduino Nano iot 33을 가지고 Beacon과 유사한 하게 작동하는 것을 테스트해 보았습니다.

그런데, 타업체 BLE 스캐너(BLE to WiFi(MQTT)) 제품이 있는데, UUID를 자체를 센서데이터로 보내는 것을 확인했습니다.

 

 BLE에 대해 정확하게 모르는 부분도 있고, BLE to WiFi(Scanner) 제품을 업체 제품과 연동 용도로 사용하는 것이 아니다 보니 업체에 직접 문의하지는 못하고 Arduino와 연동이 가능할까 해서 테스트해 보았습니다.

 

그래서 참고로 이렇게 하는 것도 있고, 이렇게 해도 되는구나 참고로 보면 어떨까 합니다.

 


 

1. BLE를 위한 제품 선택

 

 Arduino로 간단하게 Beacon을 테스트를 할 때, HM-10과 같은 BLE 모듈을 연결해서 사용하는데, 이번에는 가지고 있던 nano iot 33로 테스트했습니다.

 

 만약 저전력으로 몇 개월씩 가는 제품으로 개발을 생각한다면 Nano는 비추천입니다. 나노도 저전력이긴 하지만, Beacon으로 사용하기에는 소비전력이 큰 편이라, nRF52840 Dongle, ESP32 Pico D4 등과 같은 제품으로 먼저 테스트하는 것이 좋을 것으로 생각됩니다.

 

 

<참고사이트 1>

 

 

 대략 약 22 mA 소비한다고 생각하고 예를 들어, 하루 24시간 동안 BLE 기능을 계속 사용하면 다음과 같은 소비 전력을 계산할 수 있습니다:

 

  24시간 동안: 24시간 x 22mA = 528 mAh

 

그렇다면, 배터리 용량에 따라 가동 시간은

 

  1000 mAh 배터리를 연결할 경우, 약 45시간 사용 가능하다는 이론상 결과가 나옵니다. 전송주기와 주변환경등에 따라 달라질 수 있습니다.

 

 

2. 소스코드 설명

 

1) 라이브러리 포함

 

#include <ArduinoBLE.h>

 

 BLE 기능을 제공하는 ArduinoBLE 라이브러리를 포함합니다. 이 라이브러리는 BLE 장치 초기화, 광고 시작 및 서비스 설정과 같은 기능을 제공합니다. “Tool->Manage Libraries”에 들어가서 검색한 후 설치하면 됩니다.

 

 

 

2) 핀 정의 및 전역 변수 설정

 

#define ANALOG_PIN A0  // 아날로그 입력 핀

 

 아날로그 핀으로 센서값을 받는다는 가정하에 A0 핀을 아날로그 입력으로 정의합니다. 여기에 센서를 연결해 데이터를 읽어올 것입니다.

  

static unsigned int counter = 0;  // 카운터 변수

 

BLE 광고에 포함될 카운터 변수입니다. 이 값은 매 초 증가하여 브로드캐스팅됩니다.

 

 

3) setup() 함수

 

void setup() {
  Serial.begin(9600);
  while (!Serial);  // Serial 포트가 연결될 때까지 대기

  if (!BLE.begin()) {
    Serial.println("BLE 초기화 실패");
    while (1);  // 초기화 실패 시 멈춤
  }

  BLE.setLocalName("SensorBeacon");
  // 광고 간격 설정 (100ms ~ 10.24s 범위)
  BLE.setAdvertisingInterval(1600);  // 100ms 간격 (1 unit = 0.625ms

  Serial.println("BLE 장치가 광고 중입니다...");
  BLE.advertise();
}

 

Serial 통신 초기화:  로그 출력을 확인할 수 있도록 Serial.begin()을 사용합니다.

BLE 초기화 : BLE.begin()을 호출하여 BLE 기능을 초기화합니다. 만약 초기화에 실패하면 무한 루프에 빠지도록 설정합니다.

BLE 장치 이름 설정: BLE.setLocalName()을 사용해 장치 이름을 설정합니다.

 

BLE 광고 간격설정 :

 광고 간격을 0.625ms 단위로 표현합니다. 예를 들어, 1 unit = 0.625ms, 2 units = 1.25ms

160 units = 100ms (0.625ms × 160) 1초마다 광고할 경우 1600을 입력하면 됩니다.

  

광고 시작: BLE.advertise()로 BLE 광고를 시작합니다.

 

 

4) loop() 함수

 

void loop() {
  Serial.print("카운트 값: ");
  Serial.println(counter);

 

매 루프마다 카운터 값을 Serial 모니터에 출력합니다.

 

 

5) 아날로그 값 읽기 및 UUID 생성

 

int analogValue = analogRead(ANALOG_PIN);
char uuid[37];  // UUID 형식: 8-4-4-4-12 + NULL

snprintf(uuid, sizeof(uuid), "%08X-0000-0000-0000-%012X", analogValue, counter);

 

아날로그 입력값을 analogRead()로 읽습니다. 이 값은 UUID의 첫 번째 필드에 사용됩니다.

UUID 생성: snprintf()를 사용해 UUID 문자열을 만듭니다. 예제 형식은 다음과 같습니다:

 

ABCD1234-0000-0000-0000-000000000001

첫 번째 필드: 아날로그 값(8자리), 예)  ABCD1234

마지막 필드: 카운터 값(12자리),  예)  000000000001

 

 

6) 동적으로 BLE 서비스 생성 및 광고 설정

 

BLEService *myService = new BLEService(uuid);
BLE.setAdvertisedService(*myService);

BLE.stopAdvertise();
BLE.advertise();

 

BLE 서비스 생성: 새롭게 생성된 UUID를 기반으로 BLE 서비스를 동적으로 만듭니다.

BLE 광고 재시작: 광고를 중지한 후 다시 시작하여 최신 UUID를 브로드캐스팅합니다.

 

 

7) 동적 메모리 해제

 

delete myService;

 

동적으로 생성된 BLEService 객체를 사용한 후, 메모리 누수를 방지하기 위해 delete로 메모리를 해제합니다.

 

 

8) 딜레이 및 카운터 증가

 

delay(1000);  // 데이터 전송 간격
counter++;

 

1초 간격으로 데이터를 전송하고 카운터 값을 증가시킵니다

  

 

3. 전체 소스 코드

 

 동작 내용을 설명하자면, 아날로그 신호의 값을 받고, 카운트 값을 UUID에 담아 보내는 것입니다.

아래코드에 추가로 데이터를 어떻게 처리할지 등 부과적인 코드를 추가해서 사용하시면 될 듯합니다.

 

 

#include <ArduinoBLE.h>

#define ANALOG_PIN A0  // 아날로그 입력 핀

void setup() {
  Serial.begin(9600);
  while (!Serial);  // Serial 포트가 연결될 때까지 대기

  if (!BLE.begin()) {
    Serial.println("BLE 초기화 실패");
    while (1);  // 초기화 실패 시 멈춤
  }

  // BLE 장치 이름 설정
  BLE.setLocalName("DynamicBeacon");
  // 광고 간격 설정 (100ms ~ 10.24s 범위)
  BLE.setAdvertisingInterval(1600);  // 100ms 간격 (1 unit = 0.625ms)
  Serial.println("BLE 장치가 광고 중입니다...");

  // 초기 광고 시작
  BLE.advertise();
}

void loop() {

  static unsigned int counter = 0;  // 카운터 변수
  Serial.print("카운트 값: ");
  Serial.println(counter);

  // 아날로그 값 읽기 (예시)
  int analogValue = analogRead(ANALOG_PIN);

  // UUID 문자열 생성 (UUID 형식에 맞게 포함)
  char uuid[37];  // UUID 형식: 8-4-4-4-12 + NULL
  snprintf(uuid, sizeof(uuid), "%08X-0000-0000-0000-%012X", analogValue, counter);

  // 서비스 UUID 업데이트
  BLEService *myService = new BLEService(uuid);
  BLE.setAdvertisedService(*myService);

  // 광고 재시작
  BLE.stopAdvertise();
  BLE.advertise();

  // 동적 할당 해제
  delete myService;
  delay(1000);  // 데이터 전송 간격

  // 카운트 값 증가
  counter++;
}

   

 

Arduino nano iot(beacon) -> BLE to WiFi(MQTT) -> Node-Red의 MQTT 노드로 데이터를 받아 Function 노드에서 Payload를 조금 수정해서 간단하게 출력해 보았습니다.

 

 

 

4. 참고 사항

 

 코드가 어려운 내용은 아닌데, ChatGPT에게 설명해서 코드를 생성해 달라고 하면, BLE서비스 생성하고,  BLEStringCharacteristic 객체를 만들어서 writeValue로 보내는 것으로 코드를 먼저 만들어 줍니다. 그러다 보니 UUID가 변경되지 않아 센서 데이터가 전송되지 않았습니다.

 

 다시 해서 UUID에 데이터를 담고 싶다고 했지만, 객체가 메모리 자동 해제되는 것으로 생각하고 코드를 생성하다 보니 어느 순간에 멈추는 현상 등이 발생하고 이렇게 저렇게 문제가 발생했서 쉽게 코드를 생성해주지 못했습니다.

 

 위의 코드도 완벽하지 않지만, 멈추지 않고 센서값과 카운트값을 전달하는 것은 확인했습니다. 이제 ChatGPT도 위의 내용으로 학습했기 때문에 유사하게 생성해 줄 수 있을 거라고 생각됩니다. ^^

 

 Beacon센서 데이터를 수신해 보면 앞에 몇 바이트가 추가되어 나타납니다. 예를 들면 020106 …  고정된 바이트가 나타납니다. 광고 플래그(flag) 데이터로 참고 사이트 2를 보면 의미를 알 수 있습니다. nRF Connect 앱과 같은 것으로 확인해 볼 수 있습니다.

 

 BLE 관련된 지식이 부족하다 보니, 실수한 부분이 있을 수 있습니다. 과감하게 지적부탁드립니다. ^^

 

 

감사합니다.

 

 

<참고사이트>

1. Arduino Nano 33 IoT - Ultimate Guide(소비전력)

https://fishpoint.tistory.com/4934

2. BLE 비콘

https://blog.naver.com/juke45ef/220834142021   

 

 

 

반응형