UAM 프로젝트에서 보조항법용 거리 센서로 UWB를 사용하기로 하면서 DWM1001-DEV를 처음 만져봤다.
최종 구성에서는 여러 앵커의 거리값을 동시에 받아 위치를 계산해야 한다. 하지만 처음부터 측위 시스템 전체를 구성하면 문제가 생겼을 때 원인을 나누기 어렵다.
그래서 이번에는 DWM1001-DEV 두 대 사이에서 거리값이 계속 나오는지, 그리고 그 값을 PC로 받아 저장할 수 있는지부터 확인했다. 두 보드의 역할과 UART 출력을 확인한 뒤 MATLAB 로거를 구성했고, 브링업이 끝난 뒤에는 0.5 m, 1.0 m, 1.5 m에서 간단한 정적 측정도 진행했다.

UWB와 DWM1001
UWB(Ultra-Wideband)는 넓은 대역폭의 무선 신호를 사용하는 기술이다. 위치 측정에서는 수신 신호 세기만 비교하기보다, 전파가 장치 사이를 오가는 데 걸린 시간을 이용해 거리를 추정할 수 있다.
이번에 사용한 TWR(Two-Way Ranging)은 두 장치가 신호를 주고받은 왕복 시간을 바탕으로 거리를 계산하는 방식이다. 한쪽 장치가 측정을 시작하는 initiator, 다른 장치가 응답하는 responder 역할을 맡는다.
DWM1001은 DW1000 UWB 송수신기와 nRF52832 마이크로컨트롤러, UWB·Bluetooth 안테나 등을 하나의 모듈에 넣은 제품이다. 이번에 사용한 DWM1001-DEV는 여기에 USB 연결과 온보드 J-Link 디버거 등을 추가한 개발보드라서 PC에 연결해 실험하기 편한다.
이번에 사용한 두 보드에는 이미 initiator와 responder용 펌웨어가 올라가 있었다. 따라서 이번 글에서는 펌웨어를 빌드하고 플래시하는 과정이 아니라, 현재 보드의 역할을 확인한 뒤 UART로 출력되는 거리값을 MATLAB에 저장하는 과정부터 다룬다.
DWM1001 두 대로 TWR 거리값 받기
처음 구성은 단순했다.
- COM5: initiator, 거리 계산과 UART 출력
- COM4: responder, initiator 요청에 응답
- PC: MATLAB으로 COM5의 거리값 수집
COM 번호는 보드에 고정된 값이 아니라 당시 제 PC에서 할당된 번호이다. 다른 환경에서는 실제로 잡힌 포트를 다시 확인해야 한다.
이번 단계에서는 TWR 원리를 직접 구현하지 않았다. 두 포트의 출력을 비교해 보드 역할을 구분하고, COM5 쪽에서 거리값이 계속 갱신되는지를 먼저 확인했다.
COM5에서는 아래와 같은 문자열이 반복해서 들어왔다.
Distance A : 0.578477
Transmission # : 204
Transmission # : 205
Reception # : 95
Distance A : 0.406498
Transmission # : 206
...
송신 횟수가 증가하고 응답을 받은 뒤 Distance A가 계산됐다. 반면 responder인 COM4에서는 같은 형태의 거리 출력이 계속 나타나지 않았다. 한쪽 포트가 조용하다고 바로 통신 실패로 판단하면 안 됐던 이유이다.
여기까지 확인하면 적어도 아래 구간은 연결됐다고 볼 수 있었다.
DWM1001-DEV initiator ↔ DWM1001-DEV responder
↓
거리 계산
↓
COM5 UART 출력
MATLAB에서는 raw UART부터 확인했다
터미널에서 숫자가 나온다고 끝은 아니었다. 나중에 정확도와 흔들림을 비교하려면 화면을 보고 값을 적는 대신 원시 데이터(raw data)가 남아 있어야 했다.
처음부터 CSV 저장과 통계 계산을 한꺼번에 붙이면 문제가 생겼을 때 포트 연결이 잘못된 것인지, 문자열 파싱이 잘못된 것인지 구분하기 어렵다. 그래서 MATLAB에서는 세 단계로 나눠 확인했다.
1. 15초 동안 원문 그대로 읽기
uwb = serialport("COM5", 115200);
configureTerminator(uwb, "LF");
flush(uwb);
t0 = tic;
while toc(t0) < 15
line = readline(uwb);
disp(line);
end
여기서는 COM 포트, 115200 baud, LF 줄바꿈이 맞는지만 봤다. Transmission, Reception, Distance A가 MATLAB Command Window에 그대로 나오면 PC와 보드 사이의 serial 연결은 된 상태이다.
2. Distance A만 숫자로 바꾸기
raw 문자열이 들어오는 것을 확인한 다음에는 Distance A가 포함된 줄만 골랐다.
s = serialport("COM5", 115200, "Timeout", 2);
configureTerminator(s, "LF");
flush(s);
while true
line = readline(s);
if contains(line, "Distance A")
parts = split(line, ":");
distance_m = str2double(strtrim(parts(2)));
fprintf("거리: %.3f m\n", distance_m);
end
end
예를 들어 Distance A : 0.406498가 들어오면 콜론 뒤의 숫자만 꺼내 0.406498 m로 저장하는 방식이다.
3. 정적 시험용 로거로 확장하기
마지막으로 이 수신 코드를 uwb_static_test.m으로 확장했다. 정적 시험용 스크립트는 ChatGPT로 초안을 작성했고, 실제 DWM1001 UART 출력 형식과 시험 조건을 반영해 실행·검증했다.
DWM1001 TWR
↓
UART 거리 출력
↓
MATLAB 실시간 수신
↓
time_s와 기준거리 기록
↓
측정 로그 CSV 저장
↓
통계 계산과 그래프 저장
이 단계까지 만들어두니 이후에는 기준거리와 시험 이름만 바꿔 같은 형식으로 데이터를 모을 수 있었다. 센서가 숫자를 한 번 출력하게 만드는 데서 끝내지 않고, 같은 조건으로 반복 저장할 수 있는 형태까지 연결한 셈이다.
사용한 전체 MATLAB 코드는 아래 파일에 첨부했다.
측정 파일은 어떻게 남겼나
한 번 측정하면 MATLAB Current Folder에 같은 시험 이름과 timestamp를 공유하는 세 종류의 결과가 생성됐다.
[MATLAB Current Folder]
├─ uwb_static_test.m
├─ LOS_1m_run1_20260805_231554.csv
├─ LOS_1m_run1_summary_20260805_231554.csv
└─ LOS_1m_run1_graph_20260805_231554.png
| 파일 | 저장 내용 |
| 측정 로그 CSV | 샘플별 시간, 기준거리, 측정거리와 오차 |
| summary CSV | 표본 수, 평균, Bias, 표준편차, RMSE, P95, 갱신률과 측정 간격 |
| graph PNG | 시간에 따른 측정거리, 실제 거리와 측정 평균 |
측정 로그 CSV의 열은 다음과 같다.
test_name
time_s
true_distance_m
measured_distance_m
error_m
absolute_error_m
파일명 앞부분에는 LOS_거리_run번호, 뒤에는 YYYYMMDD_HHMMSS 형식의 저장 시각을 붙였다. 같은 test_name으로 다시 실행해도 이전 결과를 덮어쓰지 않고 별도 파일로 남길 수 있었다.
0.5 m / 1.0 m / 1.5 m에서 직접 재봤다
통신과 로깅까지 확인한 뒤 간단한 정적 거리 측정을 진행했다.
두 보드를 실내 바닥에 놓고 LoS(Line of Sight), 즉 두 장치 사이를 사람이 가리지 않는 조건에서 측정했다.
- 기준거리: 0.5 m / 1.0 m / 1.5 m
- 반복 횟수: 거리마다 run1, run2
- 측정 시간: 한 run당 약 30초
- 기준점: 두 보드의 같은 안테나 위치
- 측정 중 보드 고정
줄자의 같은 눈금을 두 보드의 안테나 기준점에 맞췄다. 이 실험은 DWM1001의 공식 성능을 검증하려는 목적이 아니라, 현재 장비와 현재 환경에서 어느 정도 값이 나오는지 확인하는 초기 측정에 가까웠다.
측정 결과
두 번의 유효 측정 데이터를 거리별로 합쳐 계산한 결과이다.
Bias는 측정값이 기준거리에서 어느 방향으로 얼마나 치우쳤는지 보여주는 평균 오차이고, 표준편차는 정지 상태에서 값이 얼마나 흔들렸는지를 나타낸다. RMSE는 전체 오차 크기를, 95% 절대오차는 전체 샘플의 95%가 어느 오차 범위 안에 들어왔는지를 보기 위해 함께 계산했다.
| 기준거리 | 샘플 수 | 평균 측정거리 | Bias | 표준편차 | RMSE | 95% 절대오차 |
| 0.5 m | 126 | 0.6112 m | +11.12 cm | 4.51 cm | 12.00 cm | 18.79 cm |
| 1.0 m | 127 | 1.0146 m | +1.46 cm | 2.49 cm | 2.88 cm | 6.31 cm |
| 1.5 m | 125 | 1.5167 m | +1.67 cm | 3.45 cm | 3.82 cm | 7.91 cm |
실제로 들어온 데이터의 평균 갱신률(update rate)은 약 2.1 Hz였다.
![]() |
![]() |
![]() |
| 0.5 m run1. 실제 거리는 0.5 m였지만 평균 측정거리는 약 0.595 m였다. | 1.0 m run1. 평균 측정거리는 약 1.015 m였다. | 1.5 m run2 재측정본. 평균 측정거리는 약 1.524 m였다. |
1.0 m와 1.5 m에서는 평균값이 기준거리보다 약 1–2 cm 크게 나왔다. 반면 0.5 m에서는 평균 측정거리가 0.6112 m로, 두 번의 측정 모두 같은 방향으로 크게 벗어났다.
0.5 m 값은 바로 보정하지 않았다
처음 결과를 봤을 때는 일정한 offset을 하나 정해서 빼면 되지 않을까 생각했다. 하지만 아직은 그렇게 처리하지 않았다.
이번 측정은 보드를 실내 바닥에 바로 놓은 상태였다. 바닥과 주변 물체에 의한 다중경로(multipath), 근거리 측정 특성, 안테나 방향, USB 케이블의 영향이 섞였을 수 있다. 현재 데이터만으로는 어느 원인이 지배적이었는지 구분할 수 없다.
무엇보다 1.0 m와 1.5 m의 Bias는 약 1–2 cm인데 0.5 m에 맞춰 전체 거리에서 10 cm를 빼면 나머지 구간이 오히려 나빠진다.
그래서 이번 결과는 0.5 m 바닥 배치 조건에서 큰 양의 바이어스가 반복해서 관측됐다는 수준으로만 기록했다. 보정값을 정하기 전에 보드를 바닥에서 띄운 조건과 비교하는 편이 먼저라고 판단했다.
두 번 측정했을 때 얼마나 달랐나
같은 거리에서 run1과 run2의 평균 측정거리 차이도 비교했다.
- 0.5 m: 약 3.18 cm
- 1.0 m: 약 0.12 cm
- 1.5 m: 약 1.38 cm
1.0 m에서는 두 번 측정한 평균이 거의 같았다. 반대로 0.5 m는 평균 Bias도 가장 컸고 두 run 사이 차이도 상대적으로 컸다.
아직 측정 횟수가 두 번뿐이라 이것만으로 DWM1001의 반복성을 평가하기에는 부족한다. 다만 다음 실험에서 0.5 m 조건을 따로 확인해야 할 이유는 생겼다.
멀쩡히 저장된 데이터도 한 번 버렸다
1.5 m의 첫 번째 run2를 측정할 때 USB 케이블 장력이 보드를 뒤로 당기면서 보드 자세가 살짝 달라졌다.
CSV에는 거리값이 정상적으로 저장됐다. 하지만 run1과 비교하려고 만든 실험에서 장치 배치 조건이 달라졌기 때문에 그대로 사용하기는 어려웠다.
그래서 23:18:50에 측정한 첫 번째 run2는 분석에서 제외하고, 보드 위치와 자세를 다시 맞춘 뒤 23:19:56에 측정한 두 번째 run2를 최종 결과에 사용했다.
나중에 숫자만 보면 첫 번째 파일도 정상 데이터처럼 보였을 것이다. 값이 마음에 들지 않아 제외한 것이 아니라, 실험 조건이 깨졌기 때문에 제외했다는 점을 따로 기록했다.
약 2.1 Hz도 같이 남긴 이유
정상적인 run의 평균 측정 간격은 약 0.47초였고, 거리값은 평균 약 2.1 Hz로 들어왔다.
1.5 m run2에서는 약 1.03초의 공백이 한 번 보였다. 이후 필터나 센서 융합에 연결할 때 UWB 측정값이 항상 같은 주기로 들어온다고 가정하면 안 된다는 뜻이다.
그래서 측정 로그 CSV에 각 샘플의 time_s를 함께 저장했다. 새로운 거리값이 실제로 들어온 시점을 기준으로 처리해야 같은 값을 여러 번 사용하거나 누락된 샘플을 정상 주기로 착각하는 일을 피할 수 있다.
이번 브링업에서 확인한 범위
이번 작업으로 DWM1001-DEV 두 대의 1:1 TWR이 동작하는 것을 확인했다. 거리값을 PC에서 실시간으로 받아 MATLAB으로 저장했고, 0.5 m / 1.0 m / 1.5 m에서 반복 측정할 수 있는 기본 파이프라인도 만들었다.
다만 여기서 나온 수치를 그대로 DWM1001의 정확도라고 보기는 어렵다. 현재 측정은 아래 조건에서 진행한 초기 실험이다.
- 실내
- 바닥 배치
- LoS
- 1:1 TWR
- 각 거리 2회
야외나 NLoS에서는 아직 측정하지 않았고, 바닥에서 띄웠을 때 값이 어떻게 달라지는지도 확인하지 않았다. 여러 앵커의 거리값을 동시에 받는 환경 역시 다음 단계에서 별도로 확인해야 한다.
현재 단계에서는 센서 성능을 결론내리기보다 실제 센서 → 거리 출력 → 샘플별 측정 로그 → 분석까지 한 번 연결했다는 데 의미를 두고 있다.
다음에는 바닥 반사의 영향을 줄인 조건에서 다시 측정하고, 여러 거리값을 동시에 받는 쪽으로 넘어갈 예정이다.
참고자료
'Measurement & Debug' 카테고리의 다른 글
| FPGA Verilog 디버깅 - Claude 답변을 Waveform으로 검증한 과정 (0) | 2026.08.22 |
|---|---|
| [수강신청 꿀팁] 수강신청 서버 타이밍을 분석해보자 (0) | 2026.08.11 |


