1. ESP32와 모바일 블루투스 통신하기(FSR,압력센서)
출처
https://esp32io.com/tutorials/esp32-force-sensor
ESP32 - Force Sensor | ESP32 Tutorial
Learn how force sensor sensor works, how to connect force sensor to ESP32, how to program ESP32 step by step. The detail instruction, code, wiring diagram, video tutorial, line-by-line code explanation are provided to help you quickly get started with ESP3
esp32io.com
1. 압력센서(FSR)
아래의 사이트를 참고했습니다.
https://learn.adafruit.com/force-sensitive-resistor-fsr
Force Sensitive Resistor (FSR)
FSRs are sensors that allow you to detect physical pressure, squeezing and weight. They are simple to use and low cost. This guide will show you how to wire an FSR, connect it to your Arduino, and give you some project ideas.
learn.adafruit.com
FSR 센서의 기본
FSR 센서는 대개 여러 개의 층으로 이루어져 있는데 중간에 있는 Spacer 층에 의해 각 면이 서로 분리 되어있다가 눌리는 힘에 의해서 맞닿는 방식이다. 측정 값이 아주 정확하진 않으며, 센서 종류 별로 감지할 수 있는 힘의 크기가 다르며, 센서마다 약 10% 정도 다르다.
하지만 이것을 압착했거나 눌렀는지 그리고 얼마만큼 눌렀는지와 같은 대부분의 터치 감지 응용 프로그램으로 사용하기에 좋다. 이는 우리 프로젝트에 필요한 센서임이 분명했기에 FSR을 사용했다.
FSR로 힘/압력을 측정하는 방법
FSR의 저항은 더 많은 압력이 가해질수록 변한다. 압력이 없으면 센서는 무한 저항기(개방 회로)처럼 보이며, 압력이 증가하면 저항이 감소한다. 이 그래프는 다양한 힘 측정에서 센서의 저항을 대략적으로 나타낸다.
그래프가 실제로 선형이 아니며 (로그/로그 그래프) 특히 낮은 힘 측정에서는 무한에서 100KΩ으로 빠르게 이동한다는 점을 알아두는 것이 중요하다.
(힘은 그램 단위로 측정되지 않으며 실제로 의미하는 것은 뉴턴 * 100입니다!)
2. 압력센서(FSR)과 ESP32
우리 팀은 esp32 devkit V1을 사용했다. 위와 비슷하지만 다르다.
Breadboard는 소형 으로 사서 사용했다.
우선 배터리 연결전에 c타입 잭으로 esp32와 연결한 후 노트북 전원으로 충전을했다.
FSR은 파워의 크기는 상관이 없지만 납땜해서 연결하지 말아야한다.
이유는 핀이 약하므로 1~2초 정도만 땜질 할 수 있고 길게 하면 핀이 녹아버리게 된다.
2. 아두이노 IDE를 통한 업로드(코드)
프레임워크: Arduino IDE 2.3.2
esp32를 연결한 후 DEV Module과 port를 선택한다.
<시리얼 모니터창 확인 코드>
/*
* This ESP32 code is created by esp32io.com
*
* This ESP32 code is released in the public domain
*
* For more detail (instruction and wiring diagram), visit https://esp32io.com/tutorials/esp32-force-sensor
*/
#define FORCE_SENSOR_PIN 36 // 센서 핀은 ADC핀을 사용하기만 하면 된다.
// ESP32 pin GIOP36 (ADC0): the FSR and 10K pulldown are connected to A0
void setup() {
Serial.begin(9600);
}
void loop() {
int analogReading = analogRead(FORCE_SENSOR_PIN);
Serial.print("The force sensor value = ");
Serial.print(analogReading); // print the raw analog reading
if (analogReading < 10) // from 0 to 9
Serial.println(" -> no pressure");
else if (analogReading < 200) // from 10 to 199
Serial.println(" -> light touch");
else if (analogReading < 500) // from 200 to 499
Serial.println(" -> light squeeze");
else if (analogReading < 800) // from 500 to 799
Serial.println(" -> medium squeeze");
else // from 800 to 1023
Serial.println(" -> big squeeze");
delay(1000);
}
아래와 같이 코드를 작성한다.
BLE는 Bluetooth Low Energy의 약자로, 저전력 블루투스 기술을 의미한다. 이 기술은 특히 전력 소모를 최소화해야 하는 작고 휴대 가능한 장치에 적합하게 설계되었다. BLE는 표준 블루투스 기술과는 다른 프로토콜을 사용하며, 특히 배터리 수명을 연장시키는 데 중점을 둔다.
<BLE 확인 코드>
#include <BLEDevice.h> // BLE 통신을 위한 기본 헤더 파일 포함
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#define FORCE_SENSOR_PIN 36 // 압력 센서를 연결할 핀 번호 정의
BLEServer *pServer = NULL; // BLE 서버 객체 초기화
BLECharacteristic *pTxCharacteristic = NULL; // 데이터 전송용 캐릭터리스틱 객체 초기화
bool deviceConnected = false; // 장치 연결 상태 표시
bool oldDeviceConnected = false; // 이전 연결 상태 표시
// 고유 식별자(UUID) 정의
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" // 서비스의 UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // 데이터 수신을 위한 캐릭터리스틱 UUID
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // 데이터 전송을 위한 캐릭터리스틱 UUID
xb
// BLE 서버 연결 및 해제 이벤트를 처리하기 위한 콜백 클래스 정의
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true; // 장치가 연결되면 연결 상태를 true로 설정
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false; // 장치 연결이 해제되면 연결 상태를 false로 설정
}
};
// 데이터 수신 시 호출되는 콜백 함수를 정의하는 클래스
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
// 클라이언트로부터 데이터를 수신 받았을 때 실행
std::string rxValue = pCharacteristic->getValue(); // 수신된 데이터를 가져옴
if (rxValue.length() > 0) {
// 수신된 데이터가 있을 경우 시리얼 모니터에 출력
Serial.println("*********");
Serial.print("수신된 값: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200); // 시리얼 통신 시작
pinMode(FORCE_SENSOR_PIN, INPUT); // 압력 센서 핀을 입력 모드로 설정
BLEDevice::init("ESP32 Force Sensor"); // BLE 디바이스 초기화 및 이름 설정
pServer = BLEDevice::createServer(); // BLE 서버 객체 생성
pServer->setCallbacks(new MyServerCallbacks()); // 서버 연결/해제 이벤트 처리를 위한 콜백 설정
BLEService *pService = pServer->createService(SERVICE_UUID); // BLE 서비스 생성
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
); // 데이터 전송을 위한 캐릭터리스틱 생성 및 속성 설정
pTxCharacteristic->addDescriptor(new BLE2902()); // 캐릭터리스틱에 알림(Notify) 속성 추가
BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
); // 데이터 수신을 위한 캐릭터리스틱 생성 및 속성 설정
pRxCharacteristic->setCallbacks(new MyCallbacks()); // 데이터 수신 시 실행될 콜백 함수 설정
pService->start(); // 서비스 시작
pServer->getAdvertising()->start(); // BLE 광고 시작
Serial.println("클라이언트 연결을 기다리는 중..."); // 클라이언트 연결 대기 메시지 출력
}
void loop() {
if (deviceConnected) {
if (!oldDeviceConnected) {
// 장치가 새로 연결됐을 때 처리
oldDeviceConnected = deviceConnected;
}
// 압력 센서 값 읽기 및 BLE 캐릭터리스틱 업데이트
int analogReading = analogRead(FORCE_SENSOR_PIN);
String forceValue = String(analogReading); // 압력 값
String forceValue2 = "test"; // 추가 데이터 (예시)
// 압력 값과 추가 데이터를 하나의 문자열로 결합
String combinedValue = forceValue + "," + forceValue2;
pTxCharacteristic->setValue((uint8_t*)combinedValue.c_str(), combinedValue.length());
pTxCharacteristic->notify(); // 변경된 값을 클라이언트에 알림
delay(10); // 너무 빈번한 업데이트 방지를 위한 지연
} else if (oldDeviceConnected) {
// 장치 연결이 해제됐을 때 처리, 광고 재시작
pServer->startAdvertising();
Serial.println("광고 시작");
oldDeviceConnected = deviceConnected;
delay(500); // 연결 해제 후 짧은 지연
}
delay(1000); // 연결 해제 후 짧은 지연
}
3. 시리얼 모니터 창에서 확인
4. BLE Scanner앱에서 확인
우선, BLE로 전송했기에 "BLE 스캐너" 애플리케이션을 플레이스토어에서 다운로드 받는다.
위의 Value는 964라는 값을 받고 있고, Hex는 각각 값을 스트링으로 받고, 그 값을 아스키 코드에 대입해서 얻은 값이다.
즉, "9": 0x39 "6": 0x36 "4": 0x34 이므로 "964"가 정상적으로 문자열 값으로 전달 됐음을 확인했다.
다음 시간은 압력센서+ esp32를 1개 더 만들고 esp32와 통신해서 모바일 앱에 전송해보겠다.
Esp32로 부터 ble로 압력값을 수신하며 플러터 앱으로 전송하는 코드
#include <BLEDevice.h> // BLE 통신을 위한 기본 헤더 파일 포함
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#define FORCE_SENSOR_PIN 36 // 압력 센서를 연결할 핀 번호 정의
BLEServer *pServer = NULL; // BLE 서버 객체 초기화
BLECharacteristic *pTxCharacteristic = NULL; // 데이터 전송용 캐릭터리스틱 객체 초기화
bool deviceConnected = false; // 장치 연결 상태 표시
bool oldDeviceConnected = false; // 이전 연결 상태 표시
String forceValueFromB = ""; // ESP32 B로부터 읽은 데이터를 저장할 전역 변수
// 고유 식별자(UUID) 정의
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" // 서비스의 UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // 데이터 수신을 위한 캐릭터리스틱 UUID
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // 데이터 전송을 위한 캐릭터리스틱 UUID
// BLE 서버 연결 및 해제 이벤트를 처리하기 위한 콜백 클래스 정의
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true; // 장치가 연결되면 연결 상태를 true로 설정
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false; // 장치 연결이 해제되면 연결 상태를 false로 설정
}
};
// 데이터 수신 시 호출되는 콜백 함수를 정의하는 클래스
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
// 클라이언트로부터 데이터를 수신 받았을 때 실행
std::string rxValue = pCharacteristic->getValue(); // 수신된 데이터를 가져옴
if (rxValue.length() > 0) {
// 수신된 데이터가 있을 경우 시리얼 모니터에 출력
Serial.println("*********");
Serial.print("수신된 값: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
Serial.println("*********");
}
}
};
// BLE 클라이언트 초기화 및 설정 부분
BLEClient* pClient = BLEDevice::createClient();
BLEAdvertisedDevice myDevice; // 이전에 발견한 디바이스 저장용
void connectToServer() {
Serial.println("Connecting to ESP32 B...");
if(pClient->connect(&myDevice)) { // ESP32 B에 연결 시도
Serial.println("Connected to ESP32 B");
BLERemoteService* pRemoteService = pClient->getService(SERVICE_UUID);
if (pRemoteService != nullptr) {
BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID_TX);
if (pRemoteCharacteristic != nullptr && pRemoteCharacteristic->canRead()) {
std::string readValue = pRemoteCharacteristic->readValue();
forceValueFromB = String(readValue.c_str()); // 전역 변수에 값 저장
Serial.print("Read from ESP32 B: ");
Serial.println(forceValueFromB);
}
}
} else {
Serial.println("Failed to connect to ESP32 B");
}
pClient->disconnect();
}
void setup() {
Serial.begin(115200); // 시리얼 통신 시작
pinMode(FORCE_SENSOR_PIN, INPUT); // 압력 센서 핀을 입력 모드로 설정
BLEDevice::init("ESP32 Force Sensor"); // BLE 디바이스 초기화 및 이름 설정
pServer = BLEDevice::createServer(); // BLE 서버 객체 생성
pServer->setCallbacks(new MyServerCallbacks()); // 서버 연결/해제 이벤트 처리를 위한 콜백 설정
BLEService *pService = pServer->createService(SERVICE_UUID); // BLE 서비스 생성
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
); // 데이터 전송을 위한 캐릭터리스틱 생성 및 속성 설정
pTxCharacteristic->addDescriptor(new BLE2902()); // 캐릭터리스틱에 알림(Notify) 속성 추가
BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
); // 데이터 수신을 위한 캐릭터리스틱 생성 및 속성 설정
pRxCharacteristic->setCallbacks(new MyCallbacks()); // 데이터 수신 시 실행될 콜백 함수 설정
pService->start(); // 서비스 시작
pServer->getAdvertising()->start(); // BLE 광고 시작
Serial.println("클라이언트 연결을 기다리는 중..."); // 클라이언트 연결 대기 메시지 출력
}
void loop() {
if (deviceConnected) {
if (!oldDeviceConnected) {
oldDeviceConnected = deviceConnected;
// 연결된 후 최초 한 번 ESP32 B로부터 데이터 읽기
connectToServer(); // ESP32 B로부터 데이터 읽어오기
}
// 압력 센서 값 읽기 및 BLE 캐릭터리스틱 업데이트
int analogReading = analogRead(FORCE_SENSOR_PIN);
String forceValue = String(analogReading); // 압력 값
String forceValue2 = forceValueFromB; // ESP32 B로부터 읽은 데이터 사용
String combinedValue = forceValue + "," + forceValue2;
pTxCharacteristic->setValue((uint8_t*)combinedValue.c_str(), combinedValue.length());
pTxCharacteristic->notify(); // 변경된 값을 클라이언트에 알림
delay(10); // 너무 빈번한 업데이트 방지를 위한 지연
} else if (oldDeviceConnected) {
// 장치 연결이 해제됐을 때 처리, 광고 재시작
pServer->startAdvertising();
Serial.println("광고 시작");
oldDeviceConnected = deviceConnected;
delay(500); // 연결 해제 후 짧은 지연
}
delay(1000); // 연결 해제 후 짧은 지연
}
다른 Esp32로 압력값을 전송하는 코드
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#define FORCE_SENSOR_PIN 36 // 압력 센서 핀
BLEServer *pServer = NULL;
BLECharacteristic *pCharacteristic = NULL;
// BLE 서비스와 캐릭터리스틱의 UUID
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
void setup() {
Serial.begin(115200);
pinMode(FORCE_SENSOR_PIN, INPUT);
BLEDevice::init("ESP32 B Force Sensor");
pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
pServer->getAdvertising()->start();
}
void loop() {
int sensorValue = analogRead(FORCE_SENSOR_PIN);
String sensorStr = String(sensorValue);
pCharacteristic->setValue(sensorStr.c_str());
delay(2000); // 데이터 갱신 주기
}