Board 및 각 설정은 앞에 내용 참고
ESP32C3 에서는 작동하지 않는다고 명시되어 있다.
Serial1을 직접적으로 사용할 경우, usb 포트가 작동하지 않을 수 있기 때문에.
해당 센서는 단일 생명체에서만 탐지가 가능하며, 두 명 이상의 사람에게서 감지가 어렵다


탐구할 코드 : 60ghzbreathheart.cpp 코드로
raw데이터 들이 어떠한 변환을 거쳐서 출력되는지 나와있다.
아래는 해당 코드들에 대해 전체 내용이 담겨져 있으며, 코드에 대한 주석과 해석부분을 추가로 작성해두었다.
#include "Arduino.h"
#include "60ghzbreathheart.h"
// BreathHeart_60Hz 클래스의 생성자 : Stream 객체를 받아들여 초기화
BreathHeart_60GHz::BreathHeart_60GHz(Stream *s)
: stream(s){
this->newData = false; // 데이터 수신 상태 초기화, 'newData'는 새로운 데이터가 수신되었는지 여부를 나타내는 플래그
}
/* 데이터를 스트림에서 읽으며, 'MESSAGE_HEAD1'과 'MESSAGE_HEAD2' 바이트를 확인하여 유효한 데이터 프레임인지 확인한다
또한, 유효한 데이터 프레임이 수신되면, 이를 MSG 배열에 저장하고, 'newData' 플래그를 true로 설정하여 새로운 데이터가
수신 되었음을 알린다. */
// 데이터를 수신하고 처리하는 메서드
void BreathHeart_60GHz::recvRadarBytes(){
while (stream->available()) { // 데이터를 수신할 준비가 되었는지 확인
if(stream->read() == MESSAGE_HEAD1){ //Receive header frame 1(첫 번째 헤더 바이트 확인)
if(stream->read() == MESSAGE_HEAD2){ //Receive header frame 2
dataLen = stream->readBytesUntil(MESSAGE_END2, Msg, 20); // 데이터 끝까지 읽음
if (dataLen > 0 && dataLen < 20){
Msg[dataLen] = MESSAGE_END2; // 종료 바이트 추가
this->newData = true; // 새로운 데이터가 수신되었음을 표시
}
}
}
}
}
/* 아래 함수는 수신된 데이터를 직렬 포트로 출력하며,
데이터 출력을 완료한 후 'newData' 플래그를 'false'로 설정하고, 배열을 초기화*/
//데이터 출력 함수('showData') Radar transmits data frames for display via serial port
void BreathHeart_60GHz::showData(){
if(this->newData){
Serial.print(MESSAGE_HEAD1, HEX); // 첫 번째 헤더 출력
Serial.print(' ');
Serial.print(MESSAGE_HEAD2, HEX); // 두 번째 헤더 출력
Serial.print(' ');
char charVal[4];
for (byte n = 0; n < dataLen+1; n++) {
sprintf(charVal, "%02X", Msg[n]); // 데이터를 16진수로 변환하여 저장
Serial.print(charVal);
Serial.print(' ');
}
Serial.println();
this->newData = false; // 데이터 출력을 완료했으므로 플래그를 초기화
Msg[dataLen] = {0}; // 메시지 배열 초기화
}
}
/* 아래 함수는 레이더 데이터를 통해 사람이 존재하는지, 그리고 움직임이 있는지를 판단한다
recvRandarBytes()를 호출하여 데이터를 수신하고, reset_val()로 이전 데이터를 초기화한다.
사람의 존재, 움직임, 신체 신호, 거리, 방향 등의 정보를 판별하고 결과를 sensor_report에 저장한다. */
// 사람의 존재와 움직임 판단 함수('HumanExis_Func') Judgment of occupied and unoccupied, approach and distance
void BreathHeart_60GHz::HumanExis_Func(){
recvRadarBytes(); // 데이터를 수신
reset_val(); // 이전 데이터를 초기화
if(this->newData){ // 새로운 데이터가 수신되었는지 확인
switch(Msg[0]){ // 첫 번째 메시지 바이트에 따라 분기
case HUMAN_PSE_RADAR:
switch(Msg[1]){ // 두 번째 메시지 바이트에 따라 분기
case PRESENCE_INF:
switch(Msg[4]){ // 네 번째 메시지 바이트에 따라 사람의 존재 여부 판단
case NOONE_HERE:
showData();
sensor_report = NOONE; // 사람이 없음을 나타냄
break;
case SOMEONE_HERE:
showData();
sensor_report = SOMEONE; // 사람이 있음을 나타냄
break;
}
break;
case MOVE_INF:
switch(Msg[4]){ // 네 번째 메시지 바이트에 따라 움직임 정보 판단
case PSE_NONE:
showData();
sensor_report = NONEPSE; // 움직임이 없음을 나타냄
break;
case STATIONARY:
showData();
sensor_report = STATION; // 정지 상태임을 나타냄
break;
case MOVEMENT:
showData();
sensor_report = MOVE; // 움직임이 있음을 나타냄
break;
}
break;
case BODY_SIG:
showData();
sensor_report = BODYVAL; // 신체 신호가 있음을 나타냄
bodysign_val = Msg[4]; // 신체 신호 값을 저장
break;
case DISTANCE:
showData();
sensor_report = DISVAL; // 거리 값을 나타냄
distance = (Msg[4] << 8 | Msg[5]) / 100.0; // 거리를 계산(미터 단위)
break;
case DIRECTIONS:
showData();
sensor_report = DIREVAL; // 방향 정보를 나타냄
Dir_x = Byte2Int(Msg[4], Msg[5]); // x축 방향 계산
Dir_y = Byte2Int(Msg[6], Msg[7]); // y축 방향 계산
Dir_z = Byte2Int(Msg[8], Msg[9]); // z축 방향 계산
break;
}
break;
}
}
}
// 아래 함수는 레이더 데이터를 통해 호흡과 심박수를 측정한다.
//호흡과 심박수를 측정하는 함수('Breath_heart')Respiratory and heart rate data analysis
void BreathHeart_60GHz::Breath_Heart(){
recvRadarBytes(); // 데이터를 수신
reset_val(); // 이전 데이터를 초기화
if(this->newData){
switch(Msg[0]){
case HEART_INF:
switch(Msg[1]){
case HEART_RATE:
showData();
sensor_report = HEARTRATEVAL; // 심박수를 나타냄
heart_rate = Msg[4]; // 심박수 값을 저장(raw value)
break;
case HEART_RATE_WAVE:
showData();
sensor_report = HEARTRATEWAVE; // 심박수 파형을 나타냄
heart_point_1 = Msg[4]; // 심박 파형의 첫 번째 포인트 저장
heart_point_2 = Msg[5]; // 심박 파형의 두 번째 포인트 저장
heart_point_3 = Msg[6]; // 심박 파형의 세 번째 포인트 저장
heart_point_4 = Msg[7]; // 심박 파형의 네 번째 포인트 저장
heart_point_5 = Msg[8]; // 심박 파형의 다섯 번째 포인트 저장
break;
}
break;
case BREATH_RATE_RADAR:
switch(Msg[1]){ // 두 번째 메시지 바이트에 따라 분기
case BREATH_INF:
switch(Msg[4]){ // 네 번째 메시지 바이트에 따라 호흡 상태 판단
case BREATH_NORMAL:
showData();
sensor_report = BREATHNOR; // 정상 호흡
break;
case BREATH_RAPID:
showData();
sensor_report = BREATHRAPID; // 빠른 호흡
break;
case BREATH_SLOW:
showData();
sensor_report = BREATHSLOW; // 느린 호흡
break;
case BREATH_NONE:
showData();
sensor_report = BREATHNONE; // 호흡 없음
break;
}
break;
case BREATH_VAL:
showData();
sensor_report = BREATHVAL; // 호흡 속도를 나타냄
breath_rate = Msg[4]; // 호흡 속도 값을 저장
break;
case BREATH_WAVE:
showData();
sensor_report = BREATHWAVE; // 호흡 파형을 나타냄
breath_point_1 = Msg[4]; // 호흡 파형의 첫 번째 포인트 저장
breath_point_2 = Msg[5]; // 호흡 파형의 두 번째 포인트 저장
breath_point_3 = Msg[6]; // 호흡 파형의 세 번째 포인트 저장
breath_point_4 = Msg[7]; // 호흡 파형의 네 번째 포인트 저장
breath_point_5 = Msg[8]; // 호흡 파형의 다섯 번째 포인트 저장
break;
}
break;
}
}
}
/*아래 함수 다시 해석 */
void BreathHeart_60GHz::SleepInf_Decode(){
recvRadarBytes(); // 데이터를 수신
reset_val(); // 이전 데이터를 초기화
if(this->newData){ // 새로운 데이터가 수신되었는지 확인
switch(Msg[0]){ // 첫 번째 메시지 바이트에 따라 분기
case SLEEP_INF:
switch(Msg[1]){ // 두 번째 메시지 바이트에 따라 분기
case INOUT_BED:
switch(Msg[4]){
case OUT_BED:
showData();
sensor_report = OUTBED;
break;
case IN_BED:
showData();
sensor_report = INBED;
break;
case INOUT_NONE:
showData();
sensor_report = NOINOUT;
break;
}
break;
case SLEEP_STATE:
switch(Msg[4]){
case AWAKE:
showData();
sensor_report = SLEEPAWAKE;
break;
case LIGHT_SLEEP:
showData();
sensor_report = SLEEPLIGHT;
break;
case DEEP_SLEEP:
showData();
sensor_report = SLEEPDEEP;
break;
case SLEEP_NONE:
showData();
sensor_report = SLEEPNONE;
break;
}
break;
case AWAKE_TIME:
showData();
sensor_report = AWAKETIME;
awake_time = Msg[4] << 8 | Msg[5]; // Time: minutes
break;
case LIGHTSLEEP_TIME:
showData();
sensor_report = LIGHTTIME;
light_time = Msg[4] << 8 | Msg[5]; // Time: minutes
break;
case DEEPSLEEP_TIME:
showData();
sensor_report = DEEPTIME;
deep_time = Msg[4] << 8 | Msg[5]; // Time: minutes
break;
case SLEEP_SCORE:
showData();
sensor_report = SLEEPSCORE;
sleep_score = Msg[4];
break;
case SLEEP_STATUE:
showData();
sensor_report = SLEEPSTATUE; // 수면 상태를 나타냄
switch(Msg[4]){
case SOMEONE_HERE:
existence = true;
break;
case NOONE_HERE:
existence = false;
break;
}
switch(Msg[5]){
case DEEP_SLEEP:
sleep_status = SLEEPDEEP;
break;
case LIGHT_SLEEP:
sleep_status = SLEEPLIGHT;
break;
case AWAKE:
sleep_status = SLEEPAWAKE;
break;
case SLEEP_NONE:
sleep_status = SLEEPNONE;
break;
}
breath_rate = Msg[6];
heart_rate = Msg[7];
turn_num = Msg[8];
substantial_move_ratio = Msg[9];
samll_move_ratio = Msg[10];
apnea_num = Msg[11];
break;
case SLEEP_QUALITY:
showData();
sensor_report = SLEEPQUALITY;
sleep_score = Msg[4];
sleep_time = Msg[5] << 8 | Msg[6];
awake_time_radio = Msg[7];
light_time_radio = Msg[8];
deep_time_radio = Msg[9];
outbed_time = Msg[10];
outbed_num = Msg[11];
turn_num = Msg[12];
breath_rate = Msg[13];
heart_rate = Msg[14];
apnea_num = Msg[15];
break;
case SLEEP_ERROR:
switch(Msg[4]){
case SLEEP_LESS4H:
showData();
sensor_report = SLEEPLESS4H;
break;
case SLEEP_OVER12H:
showData();
sensor_report = SLEEPOVER12H;
break;
case SLEEP_LONGTIMENOONE:
showData();
sensor_report = LONGTIMENOONE;
break;
case SLEEP_ERRORNONE:
showData();
sensor_report = ERRORNONE;
break;
}
break;
}
break;
}
}
}
/* 아래 함수는 센서로 데이터를 전송하고, 그에 대한 응답을 처리한다.
cyclic 플래그가 설정되었거나 전송 횟수가 기준치('checkdata_len')보다 적을때 데이터를 전송한다
데이터를 전송한 후, recvRadarBytes()를 호출하여 응답을 수신하고 수신된 데이터를 출력한다. */
//Send data frame
void BreathHeart_60GHz::send_func(const unsigned char* buff, int len, bool cyclic /*=false*/){
if(cyclic || count < checkdata_len){ // 주기적으로 데이터를 전송할지 여부 확인
if(cyclic || count < 1){
stream->write(buff, len); // 데이터를 전송
stream->flush(); // 버퍼를 비움
}
do{
recvRadarBytes(); // 데이터를 수신
delay(20); // 약간의 대기 시간
}while(!(this->newData)); // 새로운 데이터가 수신될 때까지 반복
if(cyclic || count < 1){
Serial.print(" Sent ---> ");
data_printf(buff, len); // 전송한 데이터를 출력
}
if(count%2 == 1){
Serial.print("Receive <--- ");
showData(); // 수신한(받은) 데이터를 출력
}
this->newData = false; // 새로운 데이터 플래그 초기화
}
count++; // 전송 횟수 증가
}
/* 센서의 전송 모드를 설정한다.
사용자가 입력한 'mode' 값에 따라 센서를 실시간 데이터 전송 모드 또는 수면 상태 전송 모드로 설정
잘못된 모드가 입력되면 오류 메시지를 출력한다. */
//모드 선택 함수(Transfer mode selection)
void BreathHeart_60GHz::ModeSelect_fuc(int mode){
if (mode == 1){ // 모드 1 : 실시간 데이터 전송 모드
stream->write(realtime_mode_frame, mode_frame_len); // 실시간 모드 활성화
stream->flush(); // 버퍼를 비움
Serial.println("Real-time data transfer mode ON!");
}
else if (mode == 2){ // 모드 2 : 수면 상태 전송 모드
stream->write(sleepstatus_mode_frame, mode_frame_len); // 수면 상태 모드 활성화
stream->flush(); // 버퍼를 비움
Serial.println("Sleep state transfer mode ON!");
}
else Serial.println("Input error, please reselect the mode - 1: indicates real-time transmission mode, 2: indicates sleep state mode.");
}
//센서 리셋 함수(Reset radar)
void BreathHeart_60GHz::reset_func(){
stream->write(breath_reset_frame, reset_frame_len);
stream->flush();
Serial.println("Radar reset!");
}
/* 두 개의 바이트를 (2byte = 16bit) 16비트 정수로 결합하고, 이를 부호있는 정수로 변환
부호 비트를 확인하여 음수인지 양수인지를 판단한다.*/
//Two Byte to signed integer
float BreathHeart_60GHz::Byte2Int(unsigned int x, unsigned int y){
float z = ((x << 8 | y) & 0x7FFF) / 100.00;
if (((x << 8 | y) & 0x8000) == 0x8000)z = -z;
return z;
}
//print redirect
void BreathHeart_60GHz::data_printf(const unsigned char* buff, int len){
char charVal[4];
for(int i=0; i<len; i++){
sprintf(charVal, "%02X", buff[i]);
Serial.print(charVal);
Serial.print(' ');
}
Serial.println();
}
//reset the radar values
void BreathHeart_60GHz::reset_val(){
sensor_report = 0x00;
bodysign_val = 0x00;
distance = 0x00;
Dir_x = 0x00;
Dir_y = 0x00;
Dir_z = 0x00;
heart_rate = 0x00;
heart_point_1 = 0x00;
heart_point_2 = 0x00;
heart_point_3 = 0x00;
heart_point_4 = 0x00;
heart_point_5 = 0x00;
breath_rate = 0x00;
breath_point_1 = 0x00;
breath_point_2 = 0x00;
breath_point_3 = 0x00;
breath_point_4 = 0x00;
breath_point_5 = 0x00;
awake_time = 0x00;
light_time = 0x00;
deep_time = 0x00;
sleep_score = 0x00;
sleep_status = 0x00;
turn_num = 0x00;
substantial_move_ratio = 0x00;
samll_move_ratio = 0x00;
apnea_num = 0x00;
sleep_time = 0x00;
awake_time_radio = 0x00;
light_time_radio = 0x00;
deep_time_radio = 0x00;
outbed_time = 0x00;
outbed_num = 0x00;
}
반환 값
unsigned int heart_rate : 심박수 값 3초마다 보고되며, 값 범위는 0~100 이다
unsigned int heart_point1, heart_point2, heart_point3, heart_point4, heart_point5 : 심박수 파형 데이터. 5바이트는 실시간으로 1초 동안 5개의 값을 나타내며, 파형은 sin파 데이터 이고 중심축은 128이다.
즉, 심박수 강도가 0일때 128로 표시되며, 이 값은 1초에 한 번씩 보고 된다.
unsigned int breath_rate : 호흡 수치, 3초마다 보고되며, 값 범위는 0~20
열일하시네요 유빈씨