티스토리 뷰

Arduino

[Arduino] Nano에서 BLE 구현시 유의 사항

생각많은 소심남 2021. 7. 8. 22:47

회사에서 하는 일중에 Arduino Nano 33 BLE Sense에 센서를 붙이고, 측정값을 무선으로 수집하고자 하는 것이 있었다. 가장 쉽게 할 수 있는 일이 Arduino 라이브러리 중 ArduinoBLE.h를 붙이고, 통신에 필요한 속성을 설정하는 것인데, 이 예제 중에는 딱 내가 원하는 목적으로 구현된 것이 없었다.

내가 하고자 하는 것은 다음과 같다.

  • 아두이노에 센서를 붙이고, 주기적으로 센서값을 읽어온다.
  • 이 때 센서값은 String으로 넘겨준다.
  • PC에서는 아두이노에서 읽은 데이터값을 BLE를 통해서 String 포멧으로 받아온다.
  • String으로 받은 데이터를 시간 데이터와 묶어서 csv형태로 저장한다.
  • PC에서 보낸 명령어를 통해서 아두이노를 제어한다.
  • 만약 통신이 끊어질 경우, 다시 통신을 복원하는 과정을 수행한다.

그러다보니, 어떤 사람이 이 과정을 잘 정리해놔서 덕분에 뼈대는 만들어놨다.

 

Getting Started with Bluetooth LE on the Arduino Nano 33 Sense

Data engineer, hardware developer, machine learning practitioner, writer, and eternal hacker.

ladvien.com

간단하게 요약하자면, 아두이노에서는 Tx와 Rx에 대한 Characteristic을 지정하고, PC에서는 Bleak라는 프레임워크를 사용하여 아두이노에 정의한 Characteristic만 맞춰주면, 내가 원하는대로 데이터를 BLE로 가져와 csv로 저장해준다.
(참고로 예제에서는 PDM을 사용하여 마이크의 음량을 csv로 저장하는 형태로 되어 있다.)

 

hbldh/bleak

Bluetooth Low Energy platform Agnostic Klient for Python - hbldh/bleak

github.com

이 예제는 왠만하면 잘 될텐데, 내가 만든 코드는 이상하게 연결을 시도하다가 그냥 연결이 끊겼다. 처음에는 내가 만든 코드 문제이겠지 하고, 왠만한 debug log를 삽입했는데도, 원인을 찾지 못했었는데, 알고보니까 처음에 언급했던 BLE 라이브러리에 문제가 조금 있었다. 

조금 더 구체적으로 말하자면, 내가 쓰는 센서는 일반적인 센서값을 읽는 digitalRead나 analogRead가 아닌 pulseIn이란 함수를 사용한다. pulseIn은 단순히 값이 나오는게 아니라, 내가 센서값을 읽을 범위, 즉 레벨을 지정해주면, 그 레벨을 가진 시간을 반환해주는 것이다. 쉽게 표현하자면, 파형의 폭을 측정하는 것이다. 이 라이브러리에서 사용되는 timer 함수가 Nano용으로는 구현이 되지 않아, 해당 함수를 쓰는 순간 BLE 통신이 깨지는 것이다. 

방법은 pulseIn대신 custom화시킨 pulseIn을 사용하는 것이다.

// function prototype to define default timeout value
static unsigned int newPulseIn(const byte pin, const byte state, const unsigned long timeout = 1000000L);

// using a macro to avoid function call overhead
#define WAIT_FOR_PIN_STATE(state) \
  while (digitalRead(pin) != (state)) { \
    if (micros() - timestamp > timeout) { \
      return 0; \
    } \
  }

static unsigned int newPulseIn(const byte pin, const byte state, const unsigned long timeout) {
  unsigned long timestamp = micros();
  WAIT_FOR_PIN_STATE(!state);
  WAIT_FOR_PIN_STATE(state);
  timestamp = micros();
  WAIT_FOR_PIN_STATE(!state);
  return micros() - timestamp;
}

이에 대한 개발자 언급은 링크에 되어 있다. 이와 같이 기존의 pulseIn을 대체하고 나니까 내가 원하는대로 센서 데이터를 PC에서 csv로 저장할 수 있었다. 

혹시나 Arduino Nano 33에서 BLE를 가지고 뭔가 해보고자 하는 사람이라면 참고하면 좋을 것 같다.

(참고. 개인적으로는 이 문제에 너무 시간을 많이 쏟았다. 설마했지만, 기본적으로 구현되어 있는 함수에서 문제가 있다고는 생각을 못하고, UUID 문제인가? 아니면 BLE 통신 절차에 대한 문제인가?를 계속 생각하다가 문득 폰에 물려보면 되겠다 싶어서, 물려보고 원인을 찾아본 것이다. 이게 연관이 있을거라고는 생각도 못했지만...)

댓글