GrowSpace

ESP32로 UWB 시작하기 — 배선부터 좌표 파싱까지

Contents

ESP32 UWB 연동을 처음 시도하는 사람은 대개 같은 자리에서 멈춘다. 보드는 멀쩡히 켜졌는데 시리얼 모니터가 조용하다. 아니면 글자가 깨져서 들어온다.

원인은 거의 둘 중 하나다. TX와 RX를 교차하지 않았거나, 전압이 다른 커넥터에 물렸거나,

ESP32 UWB 연동에서 가장 빠른 길은, 이미 계산이 끝난 좌표를 시리얼로 받아 파싱하는 것이다. 태그가 앵커들과 거리를 재고 x·y·z까지 뽑아 문자열로 뱉으면, ESP32는 그 줄을 읽어 쓰기만 하면 된다. 삼변측량을 직접 구현할 일이 없다. 관련해서 UWB 모듈 종류와 고르는 법도 참고할 수 있다. ESP32 공식 문서는 Espressif ESP-IDF 문서에서 확인 가능하다.


ESP32에 UWB를 붙이는 두 가지 방법

먼저 갈림길부터 짚고 간다. 어느 쪽을 고르느냐에 따라 직접 짜야 할 코드의 양이 완전히 달라진다.

첫 번째는 ESP32 보드에 UWB 칩이 함께 얹힌 모듈을 쓰는 방법이다. 두 노드 사이 거리를 재는 데까지는 예제로 금방 도달한다. 그다음이 문제다. 앵커 좌표 관리, 삼변측량, 튀는 값 필터링을 전부 직접 만들어야 한다.

두 번째는 좌표를 완성해서 내보내는 장치를 ESP32에 물리는 방법이다. GrowSpace 개발자 태그가 여기 해당한다. 태그가 앵커 3개 이상과 통신해 좌표를 계산하고, ESP32는 UART로 그 결과 줄만 받아 파싱한다.

측위 원리를 파고드는 게 목적이면 첫 번째, 동작하는 결과물이 목적이면 두 번째를 고르면 된다.

아래는 개발자 태그를 물리는 쪽 순서다. 배선, Arduino IDE 설정, 통신 확인, 좌표 파싱 네 단계로 간다.


ESP32 UWB 배선 — 왼쪽 3.3V 커넥터만 쓴다

배선이 이 작업에서 유일하게 되돌릴 수 없는 단계다. 먼저 커넥터부터 확인한다.

GrowSpace 개발자 태그에는 좌우로 시리얼 커넥터가 하나씩 있다. 핀 순서만 다른 게 아니라 전기적으로 다른 포트다. 왼쪽은 TX·RX·3.3V·GND, 오른쪽은 TX·RX·5V·GND다.

ESP32는 3.3V 로직이라 왼쪽 커넥터를 쓴다. 오른쪽 5V 포트에 물리면 UART 쪽 회로가 손상될 수 있다. 라즈베리파이 GPIO도 똑같이 3.3V만 허용한다. 꽂기 전에 커넥터의 전압 표기를 눈으로 확인하는 편이 안전하다.

연결은 이렇게 잡는다.

태그 핀ESP32 DevKitC 핀
TXGPIO 16 (RX2)
RXGPIO 17 (TX2)
3.3V3.3V
GNDGND

태그 TX가 ESP32의 RX2로, 태그 RX가 TX2로 간다. 교차다. 이걸 나란히 연결해 놓고 몇 시간을 날리는 경우가 생각보다 흔하다.

배선이 끝났으면 PC 쪽을 맞출 차례다.


2단계. Arduino IDE 준비

ESP32는 Arduino IDE에 기본으로 들어 있지 않다. 보드 정의를 먼저 받아야 한다.

File > Preferences의 Additional Board Manager URLs에 ESP32 보드 URL을 넣는다. 그다음 Tools > Board > Board Manager에서 ESP32를 검색해 설치한다. 설치가 끝나면 Tools에서 ESP32 Dev Module을 고르고 포트를 잡는다.

포트 목록에 아무것도 안 뜨면 USB-UART 드라이버 문제다. 보드에 올라간 브리지 칩에 맞는 드라이버를 깔면 장치 관리자의 포트 항목에 잡힌다. GrowSpace 장비를 PC에 직접 물려 설정할 때는 CP210x VCP 드라이버를 쓴다.

시리얼 조건은 두 개만 기억하면 된다. 속도는 115200, 송신 줄바꿈은 CR(\r)이다. 명령어 끝에 CR이 붙지 않으면 태그는 아무 반응도 하지 않는다.

여기까지가 준비다. 태그가 대답하는지부터 확인한다.


3단계. 통신이 살았는지 확인한다

파싱 코드를 짜기 전에 통신부터 확인해야 시간을 아낀다. PC 입력을 태그로 넘기고, 태그 응답을 PC로 되돌리는 중계 코드를 먼저 올린다.

#define SERIAL2_RX 16
#define SERIAL2_TX 17

String fromPC = "";

void setup() {
  Serial.begin(115200);
  Serial2.begin(115200, SERIAL_8N1, SERIAL2_RX, SERIAL2_TX);
}

void loop() {
  while (Serial.available()) {
    char ch = (char)Serial.read();
    if (ch == '\n') {
      Serial2.print(fromPC);
      Serial2.print('\r');   // CR 없으면 무응답
      fromPC = "";
    } else fromPC += ch;
  }
  while (Serial2.available()) Serial.write(Serial2.read());
}

업로드가 끝나면 시리얼 모니터를 115200bps, Newline으로 맞춘다. 그 상태에서 si를 입력한다. panid와 mode, label이 주르륵 올라오면 배선과 속도가 모두 맞은 것이다.

si가 떴다면 통신은 해결됐다. 남은 건 좌표를 읽는 일이다.


4단계. 좌표는 어떤 모양으로 오나

명령어는 두 개만 알면 된다. lep는 위치만, lec는 앵커별 거리까지 함께 준다.

POS,-3.41,9.54,-1.53,74
DIST,4,AN0,365D,-2.92,0.35,0.00,9.22, ... ,POS,-3.34,9.49,-1.34,75

POS 뒤는 x, y, z 그리고 QF다. QF는 측위 품질 지수이고 0에서 100 사이 값이 온다. 60~80 위로 유지되면 비교적 안정적인 상태로 본다.

두 응답 모두 한 줄 단위로 들어온다. 3단계 중계 코드는 받은 글자를 곧바로 흘려보내기만 하므로, 파싱하려면 줄이 끝날 때까지 모아야 한다. \n이 나오면 한 줄로 보고 머리글자로 갈라주면 된다.

String fromTag = "";

void readTag() {
  while (Serial2.available()) {
    char ch = (char)Serial2.read();
    if (ch != '\n') { fromTag += ch; continue; }

    fromTag.trim();
    if (fromTag.startsWith("POS,"))       parseLEP(fromTag);
    else if (fromTag.startsWith("DIST,")) parseLEC(fromTag);
    fromTag = "";
  }
}

둘을 언제 쓰는지가 실제로는 더 중요하다. lec는 태그가 어느 앵커와 몇 미터 떨어져 있는지를 그대로 보여준다. 좌표가 이상할 때 원인을 좁히는 용도다. 앵커 하나만 거리가 튄다면 그 앵커의 설치 위치나 입력 좌표를 의심하면 된다. 로그를 길게 쌓아 분석할 때는 lep가 가볍다.

데이터가 너무 잦아 버겁다면 aurs로 전송 주기를 늘린다. 단위는 100ms고, 이동 시와 정지 시 값을 따로 준다. aurs 2 5면 움직일 때 200ms, 멈춰 있을 때 500ms 간격이다.


안 될 때 어디부터 보나

네 단계 중 어딘가 어긋나면 증상은 대개 아래 넷 중 하나로 나타난다.

증상확인할 것
응답이 전혀 없음TX/RX 교차, 115200, 송신 CR 여부
글자가 깨짐양쪽 baudrate 설정, 케이블 접촉
데이터는 오는데 파싱 실패\n 기준 버퍼 분리, POS,/DIST, 판별
거리는 나오는데 좌표가 없음앵커 3개 이상 연결, 앵커 좌표 입력 상태

마지막 항목이 초기에 가장 많다. 2D 좌표에는 앵커가 3개, 높이까지 보려면 4개 이상이 필요하다. 앵커 좌표는 mm 단위 정수로 넣고, Z값을 빼먹지 않는다.


자주 묻는 질문

ESP32에 UWB 칩이 올라간 일체형 보드와 뭐가 다른가요?

ESP32가 맡는 역할이 다르다. 일체형 보드에서는 ESP32가 UWB 칩을 직접 제어한다. 신호를 주고받고 거리를 재고 좌표까지 만드는 코드가 전부 ESP32 위에서 돈다. 개발자 태그를 물리면 ESP32는 UART로 들어온 좌표 문자열을 읽는 일만 한다. 측위는 태그 쪽에서 이미 끝나 있다. 그래서 측위 로직을 바꿔 실험하려면 일체형, 좌표를 빨리 받아 쓰려면 태그 쪽이다.

ESP32 말고 다른 보드도 되나요?

시리얼만 열리면 보드는 가리지 않는다. 라즈베리파이는 pyserial로 같은 방식이다. 아두이노 Uno는 하드웨어 시리얼이 USB와 겹쳐 AltSoftSerial을 쓴다. Mega 2560은 Serial1을 그대로 쓴다. Uno와 Mega는 5V라 오른쪽 커넥터다.

정확도는 어느 정도인가요?

실내 기준 10~30cm다. 앵커 간격은 15m 이내를 권하고, 최대 측정 거리는 25m다. 금속이나 유리처럼 반사율 높은 면 옆은 멀티패스 간섭이 생기니 피한다. 석고나 콘크리트 벽면이 낫다.

받은 좌표를 서버로 보내려면요?

게이트웨이를 쓰면 좌표가 MQTT로 발행된다. 별도 SDK 없이 구독만 하면 되고, 언어도 가리지 않는다. ESP32 직결은 서버 없이 보드 단에서 판단하고 움직여야 할 때 쓰는 방식이다.


ESP32 UWB로 오늘 안에 좌표를 볼 수 있다

앵커 3개를 세우고, 왼쪽 커넥터로 ESP32를 물리고, si가 뜨는지만 확인하면 된다. 그다음은 lep 한 줄이다.

공간 크기와 태그 수만 알려주면 맞는 구성을 잡아드린다. 설치와 연동 문의도 함께 받는다.

현장 도입을 검토 중이라면

우리 현장에는 어떤 구성이 맞을까요?

GrowSpace는 공장·물류센터·건설 현장의 조건에 맞춰 실시간 위치추적(RTLS) 시스템을 설계하고, 설치·기존 시스템 연동·운영까지 한 팀이 맡습니다. 적용 방식과 도입 절차를 먼저 확인해 보세요.

UWB 실시간 위치추적 살펴보기공장 안전관제 솔루션도입 상담 요청

Share this post