# UM982 RTK Fixed 진단 기록 (2026-07-30, 옥상)

> 목적: `fhd_rtk_ws`(`um982_driver` C++ 드라이버) 기준으로 UM982 로깅 파이프라인을 검증하던 중,
> 옥상에서 RTK Fixed가 안 나오는 문제를 끝까지 추적한 기록. 결론부터 말하면 **안테나 위치(높이/
> 개방도)가 결정적 원인**이었고, 소프트웨어/설정 쪽에서 발견한 버그 2건은 실제 버그였지만
> 그것만으론 Fixed가 안 나왔다.
>
> ⚠️ 재현 검증 진행 중: RELIABILITY를 원래 엄격값(`3 1`)으로 되돌린 뒤 난간 위치에서 재테스트
> 예정(§2.9). 위치만으로 Fixed가 재현되는지, RELIABILITY 완화가 실제로 필요했는지를 분리해서
> 확인하기 위함.

---

## 1. 결과 요약

| 시점 | 안테나 위치 | 결과 |
|---|---|---|
| 옥상, 테이블 위 (여러 차례, 총 20분+) | 테이블(낮음, 난간보다 낮은 높이) | SINGLE ↔ PSRDIFF(위성 5~9개) 반복, **Float/Fixed 도달 못 함** |
| 옥상, 난간 위 | 난간(옥상 가장자리, 탁 트인 위치, 테이블보다 높음) | **NTRIP 접속 후 약 3.4초 만에 RTK FIXED**, 위성 31개, h_acc **2.9cm** |

두 위치 모두 안테나는 거치된 상태(손으로 든 적 없음)였다. 차이는 **높이와 개방도**다 —
테이블은 난간보다 낮고, 난간은 옥상 가장자리라 하늘이 훨씬 트여 있다.

```
[um982_driver]: 상태: SINGLE(pos_type=16)    | nSV=28 hσ=1.771m  diff_age=0.0s   (t+0.03s)
[um982_driver]: NTRIP 접속: RTS1.ngii.go.kr:2101/VRS-RTCM34                      (t+0.8s)
[um982_driver]: 상태: OTHER(pos_type=17)     | nSV=13 hσ=1.378m  diff_age=0.6s   (t+1.8s)
[um982_driver]: 상태: RTK FIXED(pos_type=50) | nSV=31 hσ=0.029m  diff_age=1.1s   (t+3.4s)
```

테이블 위치에서는 같은 옥상, 같은 NTRIP 계정/마운트포인트, 같은 RELIABILITY 설정으로
8분 넘게 시도해도 위성 8~9개, 정확도 4~6m에서 정체됐던 것과 극명히 대비된다.

---

## 2. 조사 경과 (시간순)

### 2.1 파이프라인 기초 검증 (실내 → 실외 이동 전)
- `ros2 launch um982_driver um982_driver.launch.py` 정상 기동, `/ublox_driver/receiver_pvt` **10Hz** 발행 확인.
- 실내에서는 `num_sv=0`/`fix_type=NONE` — 예상된 정상 동작(위성 미포착).
- `ros2 bag record` 15초 테스트 → 148개 메시지 정상 기록 확인.

### 2.2 시리얼 권한 문제
- `/dev/ttyUSB0`가 `dialout` 그룹 소유인데 사용자가 그룹 미가입 → `Permission denied`.
- 임시 조치: `sudo chmod a+rw`. 영구 조치는 `sudo usermod -aG dialout $USER` 권장(재로그인 필요).

### 2.3 ⚠️ 버그 발견 #1 — install 설정이 stale
- `ros2 launch`는 `src/`가 아니라 `install/share/um982_driver/config/um982.yaml` **복사본**을 읽는데,
  최초 빌드(11:30) 이후 리빌드가 안 돼서 `ntrip_user`/`ntrip_pass`가 계속 **빈 문자열**이었음.
- 즉 그동안의 모든 실행이 **NTRIP 인증 없이** 시도되고 있었을 가능성이 큼.
- 조치: `colcon build --packages-select um982_driver` 리빌드 → 계정 정보 반영 확인.
- 이후 NTRIP 계정을 `hyuk` → `hyuk6578`로 수정(사용자 확인), 재빌드로 반영.

### 2.4 데이터 무결성 검증 (드라이버와 별개로 원시 데이터 직접 확인)
- BESTNAV 바이너리: SYNC(`AA 44 B5`) + CRC-32(Appendix 1 알고리즘)를 파이썬으로 재구현해
  원시 시리얼 60프레임 캡처 → **CRC 통과율 100%**. 콘솔에 뜨는 "CRC 불일치" 경고 1회는
  포트를 여는 시점에 이미 스트리밍 중이던 프레임 중간에 끼어든 것으로, 실제 재현 안 됨(benign).
- GPGGA(`$GNGGA`): 1Hz로 정상 출력, fix quality=1, 체크섬 정상 → NTRIP GGA 부트스트랩 조건 충족.

### 2.5 NTRIP/RTCM 검증 (드라이버와 별도로 직접 접속)
- 리빌드 후 재실행 → 로그에 `NTRIP 접속: RTS1.ngii.go.kr:2101/VRS-RTCM34` 출력(=서버가 `200 OK`
  응답해야만 찍히는 로그이므로 **인증 성공** 확인).
- 드라이버 코드에 진단 로그 2건 추가(파일: `src/um982_driver/src/um982_driver_node.cpp`):
  - 상태 로그에 `pos_type`(정수) + `diff_age` 표시
  - NTRIP 수신 누적 바이트 수(5초 스로틀)
- 이 코드로 확인: RTCM이 **꾸준히 초당 800B 이상** 안정적으로 유입됨.
- 드라이버와 독립적으로 같은 NTRIP 스트림에 파이썬으로 직접 접속해 RTCM3 프레임을 파싱:
  정상적인 VRS 네트워크 RTK 메시지 세트 확인 —
  `1005/1007`(기준국 좌표/안테나), `1030~1033`(네트워크 RTK 보조), `1075/1085/1095/1115`
  (GPS/GLONASS/Galileo/QZSS MSM5). **북두(BeiDou) 보정 메시지는 이 마운트포인트에 없음**
  (단, 이후 §2.7에서 이게 핵심 원인이 아니었음이 드러남 — 수신기가 애초에 북두를 포함해
  31개까지 위성을 쓸 수 있었기 때문).

### 2.6 수신기 설정 검증 (`CONFIG` 명령으로 직접 조회)
- `MODE` 쿼리 → `MODE ROVER UAV` 확인(정상, 필수 사전조건 충족).
- `CONFIG SIGNALGROUP 4 5` 확인 → Unicore 매뉴얼 Table 4-32 대조 결과 **UM982 공장 기본값**
  그대로였음(Master=4/Slave=5, BDS+GPS+GLO+GAL+QZSS 5개 위성군 추적하는 넓은 설정). 문제 아님.

### 2.7 RTK RELIABILITY 조정 (테이블 위치에서 시도)
- `CONFIG` 덤프에서 `CONFIG RTK RELIABILITY 3 1` 확인(매뉴얼 Table 4-10: 파라미터1=RTK
  포지셔닝 엔진 신뢰도, 3=Relatively high=기본값 / 파라미터2=ADR 신뢰도, 1=Low=기본값).
- 과거 기록(`~/rtk/RTK_Fixed_달성기록.md`, 2026-06-09)에 따르면, 위성 27~31개/HDOP 0.5~0.6인
  좋은 조건에서도 `RELIABILITY 3`이면 **5분 넘게 Float에서 Fixed로 안 넘어갔고**, `1 1`로
  낮춘 뒤에야 약 3분 만에 Fixed 달성한 전례가 있음. 이 설정은 RAM에만 있으면 전원 재시작/
  FRESET 시 3으로 되돌아간다고 명시돼 있었고, 실제로 되돌아가 있었음(아마 매뉴얼 참고 재설정
  과정에서 초기화된 것으로 추정).
- 조치: `CONFIG RTK RELIABILITY 1 1` + `SAVECONFIG` 실행, 재조회로 영구 저장 확인.
- **그런데도** 테이블 위치에서는 4분 이상 재시도해도 위성 8~9개, PSRDIFF에서 못 벗어남 →
  RELIABILITY만으로는 해결되지 않았고, 그 이전 단계(Float 진입 자체)가 위성 수 부족으로
  막혀 있었다는 뜻이었음.

### 2.8 테이블 vs 난간 위치 비교 (결정적 실험)
- 옥상, 옆 건물 있음 → 초기엔 "옆 건물發 멀티패스"로 추정.
- 위성 수 격차(테이블 8~9개 vs 과거 성공 기록 27~31개)가 "옆 건물 정도"로 설명하기엔
  과도하게 크다고 판단해 다른 원인(안테나 흔들림 등)도 검토했으나, 실제로는 흔들림이
  아니라 **테이블 자체가 난간보다 낮은 위치**였던 것이 원인이었음(사용자 확인).
- **난간(옥상 가장자리, 트인 위치)으로 옮겨 재시도 → §1의 결과.** 위성 수 8~9개 → 28~31개로
  즉시 회복, NTRIP 접속 3.4초 만에 RTK FIXED.

### 2.9 재현 검증 (진행 중)
- 난간 테스트는 RELIABILITY가 `1 1`(완화값)로 설정된 상태에서 이루어짐 → 위치 개선과
  RELIABILITY 완화 중 무엇이 실제로 결정적이었는지 분리가 안 된 상태.
- RELIABILITY를 원래 엄격값 `CONFIG RTK RELIABILITY 3 1` + `SAVECONFIG`로 **되돌림**(확인 완료).
- 이 상태로 난간 위치에서 재테스트 예정 — 위치만으로도 Fixed가 나오는지 확인.
  결과는 추후 이 문서에 추가.

---

## 3. 원인 분석

**핵심 원인 (결정적, primary): 안테나 위치 — 테이블(낮음, 상대적으로 덜 트임) vs 난간(옥상
가장자리, 높고 탁 트임).**
낮은 위치에서는 옆 건물 등에 의한 저고도 위성 신호 가림/멀티패스가 반송파 기반 RTK 모호성
해석을 방해했을 것으로 추정된다. SPP(단독측위)는 코드 신호만 쓰기 때문에 이 정도 환경엔
상대적으로 관대해서 SINGLE 상태의 좌표는 비교적 정상으로 보였지만, 그래서 오히려
"수신기가 위성은 잡는데 왜 Fixed가 안 되지"로 오인하기 쉬웠다.

**부차 원인 (실제 버그였지만 단독으론 불충분, contributing):**
1. `install/` 설정 파일이 stale해서 한동안 NTRIP 인증이 빈 계정으로 시도됨 — 리빌드로 해결.
2. `RTK RELIABILITY`가 엄격 기본값(3)으로 되돌아가 있었음 — `1 1` + `SAVECONFIG`로 임시 완화.
   (§2.9 재현 검증을 위해 이후 다시 `3 1`로 되돌림 — 위치 개선만으로 충분한지 확인 중.)

이 두 버그는 위치 개선 없이는 어차피 Fixed가 안 나왔을 것이므로 "고쳐도 소용없었다"고
오인할 수 있지만, RTCM 인증/유입이 정상화돼 있었기 때문에 난간 이동 직후 3.4초라는
이례적으로 빠른 Fixed가 가능했을 가능성이 있다. RELIABILITY 완화가 실제로 필수였는지는
§2.9 재현 결과로 확정한다.

---

## 4. 결론 및 권장 운용 방법

1. **UM982 안테나는 최대한 높고 트인 위치에 거치할 것.** 옆 건물 등 장애물이 있는 옥상이라면
   낮은 테이블보다 난간·삼각대 등으로 최대한 높이고, 장애물에서 수평으로도 떨어뜨리는 게
   좋다.
2. **`fhd_rtk_ws/src/um982_driver/config/um982.yaml`을 수정한 뒤에는 항상 리빌드할 것**
   (`colcon build --packages-select um982_driver`). `install/`은 심볼릭 링크가 아니라
   복사본이라 리빌드 없이는 반영되지 않는다. 아니면 `--symlink-install`로 한 번 다시
   빌드해두면 이후 src 수정이 즉시 반영된다.
3. **수신기 `CONFIG RTK RELIABILITY` 값을 상황에 맞게 확인.** 기본값은 `3 1`(엄격). 위치가
   좋은데도 Float에서 Fixed로 안 넘어가면 `CONFIG RTK RELIABILITY 1 1` → `SAVECONFIG`로
   완화를 시도해볼 수 있다(§2.9에서 위치만으로 충분한지 재검증 중이므로, 필요 여부는
   재현 결과 확인 후 최종 결론).
   FRESET이나 일부 재설정 작업 후 기본값으로 되돌아갈 수 있으니 `CONFIG` 응답의
   `CONFIG RTK RELIABILITY` 라인으로 주기적으로 확인.
4. **진단용 로그가 드라이버에 상시 포함됨** (`um982_driver_node.cpp`, 이번에 추가):
   상태 전환 로그에 `pos_type`/`diff_age`가 함께 찍히고, NTRIP 수신 바이트가 5초마다
   찍힌다. 다음에 비슷한 문제가 생기면 이 로그로 "NTRIP이 안 붙는지" vs "붙었는데 수신기가
   못 쓰는지"를 바로 구분할 수 있다.

---

## 5. 관련 파일

| 파일 | 내용 |
|---|---|
| `src/um982_driver/src/um982_driver_node.cpp` | pos_type/diff_age/NTRIP 바이트 진단 로그 추가됨 |
| `src/um982_driver/config/um982.yaml` | NTRIP 계정 갱신됨 (자격증명은 리포에 평문 저장 안 함) |
| `docs/Unicore Reference Commands Manual For N4 High Precision Products_V2_EN_R1.4.pdf` | MODE/RELIABILITY/SIGNALGROUP 명령 근거 |
| `~/rtk/RTK_Fixed_달성기록.md` | 2026-06-09 과거 Fixed 달성 기록(RELIABILITY 단서의 출처) |
| `~/rtk/save_reliability.py` | RELIABILITY 저장 스크립트(포트가 `/dev/ttyUSB0`로 하드코딩돼 있어 포트 바뀌면 수정 필요) |
