05주차 ‐ 블루투스 통신 실습 - movie-01/SmartDevice GitHub Wiki

05주차 - 블루투스 통신 실습


개요

  • 무선통신
  • 블루투스
  • 클래식 블루투스 데이터 송수신
  • BLE
  • BLE를 이용한 RGB LED 제어 실습

무선통신

전선 없이 전자기파(라디오파, 마이크로파, 적외선 등)를 이용하여 정보를 주고받는 통신 방식.

  • 예시: 라디오, TV 방송, 위성통신, 모바일 통신, Wi-Fi

근거리 무선통신 (Short-Range Wireless Communication)

짧은 거리(수 cm ~ 수십 m)에서 정보를 주고받는 무선통신 기술

  • 특징:
    • 저전력
    • 실내/개인용 기기 간 통신에 최적
    • 연결 속도는 빠르지만 전송 거리는 제한적

📡 대표적인 근거리 무선통신 기술 비교표

기술명 전송 거리 전송 속도 주요 용도 특징
Bluetooth 최대 100m 최대 3 Mbps 이상 무선 이어폰, 웨어러블, 차량 연결 등 저전력, 짧은 거리에서 안정적인 연결
Wi-Fi 약 20~50m 최대 수 Gbps 인터넷 접속, 데이터 공유 고속 전송, 네트워크 기반 연결
NFC 약 10cm 이내 424 kbps 모바일 결제, 인증, 교통카드 등 매우 짧은 거리, 빠른 반응, 높은 보안성
Zigbee 약 10~100m 250 kbps 스마트홈, IoT 센서 저전력, 다기기 네트워크 구성 가능
Infrared 수 m 이내 수백 kbps 수준 리모컨, 센서 통신 직선 통신 필요, 장애물에 민감

💡 Tip: 위 기술들은 각각 용도와 환경에 따라 선택되며, 상호 보완적으로 사용되기도 다.


📡 블루투스 (Bluetooth)

블루투스(Bluetooth)는 단거리 무선 통신 기술이며, 모바일 기기, 컴퓨터, 웨어러블 기기 등에서 데이터를 송수신하는 데 사용된다. 블루투스는 **클래식 블루투스(Classic Bluetooth, BR/EDR)**와 **저전력 블루투스(Bluetooth Low Energy, BLE)**로 구분된다.


클래식 블루투스 (Classic Bluetooth, BR/EDR)

클래식 블루투스는 지속적인 데이터 전송이 필요한 장치에서 주로 사용된다. 무선 오디오 장치🎧, 키보드⌨, 마우스🖱 등이 대표적인 예시이다.

📌 주요 특징

  • 연결을 지속적으로 유지해야 한다.
  • 전력 소비가 상대적으로 크다. 🔋
  • 최대 전송 속도는 3Mbps이다.
  • A2DP(오디오 전송), HFP(핸즈프리), HID(입력 장치) 등의 프로파일을 지원한다.

코드 작성

image

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32-BT-Slave"); // 블루투스 장치 이름 설정
  Serial.println("Bluetooth Started! Pair with ESP32-BT-Slave");
}

void loop() {
  if (Serial.available()) {
    char incoming = Serial.read();
    SerialBT.write(incoming); // 시리얼 데이터를 블루투스로 전송
  }
  if (SerialBT.available()) {
    char incoming = SerialBT.read();
    Serial.write(incoming); // 블루투스 데이터를 시리얼로 출력
  }
}

1. 클래식 블루투스 데이터 송수신 텍스트 확인

안드로이드 스마트폰 플레이스토어 앱에서 "Serial Bluetooth Terminal" 다운로드 image


스마트폰에서 “Serial Bluetooth Terminal”앱 실행후 페어링


2. 클래식 블루투스 led on/off

📌 회로 연결 방법

  • LED 모듈
    • S: D4
    • VCC: 3.3V
    • GND: GND

image

코드 작성

#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

const int ledPin = 4; // LED가 연결된 핀 번호

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32-BT-LED"); // 블루투스 장치 이름 설정
  Serial.println("Bluetooth Started! Pair with ESP32-BT-LED");

  pinMode(ledPin, OUTPUT); // LED 핀을 출력으로 설정
  digitalWrite(ledPin, LOW); // 초기 상태를 OFF로 설정
}

void loop() {
  if (SerialBT.available()) {
    char incoming = SerialBT.read();
    Serial.write(incoming); // 수신된 데이터를 시리얼 모니터에 출력

    if (incoming == '1') {
      digitalWrite(ledPin, HIGH); // '1'을 수신하면 LED ON
      Serial.println("LED ON");
    } else if (incoming == '0') {
      digitalWrite(ledPin, LOW); // '0'을 수신하면 LED OFF
      Serial.println("LED OFF");
    }
  }
}

Serial Bluetooth Terminal앱에 "0" 입력 시 LED 불빛이 꺼지고 "1" 입력 시 불빛이 켜진다.

LED.mp4

📡 데이터 송수신 방식

클래식 블루투스는 RFCOMM (Radio Frequency Communication) 프로토콜을 사용하여 직렬 포트(Serial Port) 기반으로 데이터를 송수신한다. 이를 활용하면 텍스트, 파일📂, 센서 데이터 등을 쉽게 전송할 수 있다.


🔹 BLE (Bluetooth Low Energy)

BLE는 저전력 소모를 특징으로 하며, IoT(사물 인터넷) 기기, 웨어러블, 센서 등의 장치에서 활용된다.

📌 주요 특징

  • 필요할 때만 데이터를 전송하여 배터리 소모를 최소화한다. 🔋
  • 낮은 대역폭을 사용하여 센서 데이터 및 알림 전송에 적합하다.
  • 최대 전송 속도는 1Mbps이다.
  • GATT (Generic Attribute Profile) 구조를 사용하여 데이터 통신이 이루어진다.

🎨 BLE를 이용한 RGB LED 제어 실습

BLE를 활용하면 스마트폰📱이나 기타 BLE 지원 기기에서 RGB LED💡를 원격으로 제어할 수 있다. 스마트폰에서 특정 값을 전송하면, BLE 모듈이 이를 수신하고 LED의 색상을 변경한다.

image

🔹 회로 연결

  • RGB LED 모듈
    • R 핀 → D4
    • G 핀 → D15
    • B 핀 → D2
    • VCC → 3.3V
    • GND → GND

🔹RGB LED 제어 값 입력으로 RGB LED 제어 테스트

image

코드작성

image

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// BLE 서버와 특성 객체 포인터 선언
BLEServer* pServer;
BLECharacteristic* pCharacteristic;

void setup() {
  Serial.begin(115200); // 시리얼 통신 시작 (디버깅용)

  BLEDevice::init("ESP32-RGB-Control"); // BLE 장치 이름 초기화

  pServer = BLEDevice::createServer(); // BLE 서버 생성

  // BLE 서비스 생성 (UUID: 0x1812는 HID 서비스로 예시 사용)
  BLEService *pService = pServer->createService(BLEUUID((uint16_t)0x1812));

  // 쓰기 및 알림 속성을 가진 특성 생성 (UUID: 0x2A56)
  pCharacteristic = pService->createCharacteristic(
                     BLEUUID((uint16_t)0x2A56),
                     BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY
                   );

  pService->start(); // 서비스 시작

  // 광고 시작 (BLE 주변 장치에서 탐색 가능하게 함)
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(pService->getUUID());
  pAdvertising->start();
}

void loop() {
  // 클라이언트로부터 값이 수신되었을 때 처리
  if (pCharacteristic->getValue().length() > 0) {
    std::string rgbValue = pCharacteristic->getValue();
    Serial.println(rgbValue.c_str()); // 수신된 RGB 값 출력
  }
}

하지만 24줄 코드에서 오류가 발생하는 상황이 나온다.

image

🚨 Arduino BLE 개발 시 발생하는 std::string 관련 오류 해결법

🧩 오류 메시지


❗ 문제 원인

Arduino에서는 기본적으로 String 클래스(Arduino 전용)를 사용한다.
하지만 BLECharacteristic의 getValue() 함수는 **C++ 표준의 std::string**을 반환한다.

std::string rgbValue = pCharacteristic->getValue();  // ❌ 오류 발생

✅ 해결 방법

  1. std::string 대신 String 사용하기 String rgbValue = String(pCharacteristic->getValue().c_str()); // ✅ 안전하게 변환

getValue()로 받은 std::string을 .c_str()로 const char*로 변환한 뒤

String() 생성자로 감싸서 Arduino 전용 String 객체로 변환한다.

🔁 잘못된 코드 vs 수정된 코드

잘못된 코드 ❌ 수정된 코드 ✅
std::string rgb = pCharacteristic->getValue(); String rgb = String(pCharacteristic->getValue().c_str());

코드작성

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
//서비스와 특성에 대한 UUID를 정의
#define SERVICE_UUID        "b42238ee-404f-4a11-bd3a-06d6eff0757d"
#define RGB_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define NOTYFY_CHARACTERISTIC_UUID "d501d731-f0f9-4121-a7f6-2c0f959f1583"
//RGB LED에 사용될 핀 번호를 정의
#define RED_PIN   4
#define GREEN_PIN 15
#define BLUE_PIN  2
//BLE 관련 객체를 선언
BLEServer *pServer; //BLE 서버 객체
BLEService *pService; // BLE 서비스 객체
BLECharacteristic *pRGBCharacteristic = NULL; //BLE 특성 객체
BLECharacteristic* pCharacteristic = NULL; //BLE 특성 객체
//RGB 값을 저장할 변수들을 초기화
int redValue = 0;
int greenValue = 0;
int blueValue = 0;
//BLE 특성에 대한 콜백 클래스를 정의
class MyCallbacks : public BLECharacteristicCallbacks {
  //특성의 값을 읽어와 RGB 값을 파싱하고 LED를 제어
  void onWrite(BLECharacteristic *pCharacteristic) {
    String value = pCharacteristic->getValue().c_str(); //특성의 값을 문자열로 읽음

    // 값이 유효한 경우에만 처리
    if (value.length() > 0) {
      // RGB 값을 파싱하여 각각의 변수에 저장
      int delimiterPos1 = value.indexOf(',');
      int delimiterPos2 = value.lastIndexOf(',');

      if (delimiterPos1 != -1 && delimiterPos2 != -1 \
             && delimiterPos2 < value.length() - 1) {
        redValue = value.substring(0, delimiterPos1).toInt();
        greenValue = value.substring(delimiterPos1 + 1, delimiterPos2).toInt();
        blueValue = value.substring(delimiterPos2 + 1).toInt();

        // RGB 값을 LED의 밝기로 변환하여 제어
        analogWrite(RED_PIN, 255 - redValue);
        analogWrite(GREEN_PIN, 255 - greenValue);
        analogWrite(BLUE_PIN, 255 - blueValue);
      }
    }
  }
};

void setup() {
  // BLE 초기화하고 이름을 "RGB LED Control"로 설정
  BLEDevice::init("RGB LED Control");
  pServer = BLEDevice::createServer();
  pService = pServer->createService(SERVICE_UUID);
  
  // RGB 특성 생성 및 설정
  pRGBCharacteristic = pService->createCharacteristic(
    RGB_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_WRITE
  );  
  pRGBCharacteristic->setCallbacks(new MyCallbacks());

  // Notify/Indicate 특성 생성 및 설정
  pCharacteristic = pService->createCharacteristic(
                      NOTYFY_CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );
    // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // 서비스를 서버에 추가
  pService->start();

  // BLE 광고 시작
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

    // 모든 핀을 HIGH로 설정하여 LED를 꺼진 상태로 초기화
  digitalWrite(RED_PIN, HIGH);
  digitalWrite(GREEN_PIN, HIGH);
  digitalWrite(BLUE_PIN, HIGH);
}

void loop() {
  // RGB 값을 16진수 형태로 변환하여 Notify
  char hexValue[8]; 
  sprintf(hexValue, "#%02X%02X%02X", redValue, greenValue, blueValue);
  //Notify 특성의 값을 hexValue로 설정
  pCharacteristic->setValue(hexValue); 
  pCharacteristic->notify(); //Notify를 통해 값을 전달

  delay(100);  // 알림 간격을 조절할 수 있다.
}

코드를 실행하기 위해서는 UUID 값을 조정해야 실행이 된다.

빨간색은 "255,0,0", 초록색은 "0,255,0,", 파란색은 "0,0,255"

⚠️ **GitHub.com Fallback** ⚠️