# RTK(UM982) ROS 2 녹화 명세서 > 대상: UM982(WTRTK-982) RTK 수신 데이터를 ROS 2 로 발행·**녹화**하기 위한 이관/구성 명세. > 구현체: `um982_driver` (C++ ROS 2 노드). 근거 문서: `rtk/UM982-명령어검토-및-바이너리포팅.md`. > 검증: 국가 통합기준점 U0373/U0374 대비 수평 1.4~2.6cm (rtk/Log.md). --- ## 1. 개요 & 데이터 흐름 ``` NTRIP(VRS,KGD2002) ──RTCM3──▶ UM982 ──BESTNAV(binary)+GGA(ascii)──▶ um982_driver ▲ │ └──────────────── GGA(VRS 유지, 10s) ◀───────────────────────────┘ │ GnssPVTSolnMsg (10Hz) ▼ /ublox_driver/receiver_pvt │ ros2 bag record ──▶ .db3/.mcap ``` - 시리얼 포트는 **한 프로세스만 점유** → RTCM 주입과 BESTNAV 파싱이 **한 노드**(`um982_driver`)에 통합. - 녹화는 이 노드가 발행하는 토픽을 `ros2 bag record` 로 담는다. --- ## 2. 이관 대상 & 워크스페이스 구성 (무엇을 어떻게 옮기나) **옮길 패키지 2개** (그 외 의존 없음 — 시리얼=termios, NTRIP=POSIX 소켓): | 패키지 | 역할 | 위치(원본) | |---|---|---| | `gnss_comm` | `GnssPVTSolnMsg`/`GnssTimeMsg` 메시지 정의 | `FAST-LIVO2-RTK-ROS2/thirdparty/gnss_comm` | | `um982_driver` | 드라이버 노드(파싱+NTRIP+발행) | `FAST-LIVO2-RTK-ROS2/src/um982_driver` | **녹화 전용 최소 워크스페이스** (전체 FAST-LIVO2 빌드 불필요): ``` fhd_rtk_ws/ └── src/ ├── gnss_comm/ ← thirdparty/gnss_comm 복사 └── um982_driver/ ← src/um982_driver 복사 ``` ```bash cd fhd_rtk_ws colcon build --packages-select gnss_comm um982_driver source install/setup.bash ``` > ROS 2 Humble, C++17. `um982_driver` 는 `rclcpp`, `gnss_comm` 만 의존. --- ## 3. 사전 조건 — 수신기 설정 (필수) 드라이버 실행 전 UM982 가 아래를 **저장(SAVECONFIG)** 하고 있어야 한다. 리포 `rtk/config_all.py` 한 번 실행: | 항목 | 값 | 이유 | |---|---|---| | `BESTNAVB COM3 0.1` | 10Hz 바이너리 | **파싱 소스** | | `GPGGA COM3 1` | 1Hz | NTRIP VRS 업링크 | | COM3 baud | `460800` | RTCM+로그 대역 | | `MODE ROVER` | — | 로버 측위 | | `CONFIG RTK RELIABILITY 3 1` | 기본 | 오확정 방지 | > ⚠️ `FRESET` 시 baud 가 115200 으로 초기화됨 → `rtk/set_baud.py` 재실행 필요. --- ## 4. 토픽 & 메시지 명세 ### 4.1 토픽 | 항목 | 값 | |---|---| | 토픽명 | `/ublox_driver/receiver_pvt` (파라미터 `gps_topic`) | | 타입 | `gnss_comm/msg/GnssPVTSolnMsg` | | 발행 주기 | BESTNAV 주기 = **10 Hz** (0.1s) | | QoS | `KeepLast(2000)`, 기본 신뢰성(reliable) | | 프레임/스탬프 | **메시지에 std_msgs/Header 없음.** 시간은 메시지 내부 `time.week/tow` | ### 4.2 `GnssPVTSolnMsg` 필드 (드라이버가 채우는 값) | 필드 | 타입/단위 | 채움 | BESTNAV 소스 | |---|---|---|---| | `time.week` | uint32 (GPS week) | ✅ | 헤더 Wn | | `time.tow` | float64 (초) | ✅ | 헤더 Ms÷1000 | | `latitude` | float64 (deg) | ✅ | lat | | `longitude` | float64 (deg) | ✅ | lon | | `altitude` | float64 (m, **타원체고**) | ✅ | hgt(MSL)+undulation | | `height_msl` | float64 (m) | ✅ | hgt | | `h_acc` | float64 (m) | ✅ | √(latσ²+lonσ²) | | `v_acc` | float64 (m) | ✅ | hgtσ | | `vel_n/vel_e/vel_d` | float64 (m/s, NED) | ✅ | hor·cos(trk)/hor·sin(trk)/−vert | | `vel_acc` | float64 (m/s) | ✅ | Horspd std | | `num_sv` | uint8 | ✅ | #solnSVs | | `fix_type` | uint8 (0=no,3=3D) | ✅ | pos_type | | `valid_fix` | bool | ✅ | pos_type≠NONE | | `diff_soln` | bool | ✅ | pos_type∉{NONE,SINGLE} | | `carr_soln` | uint8 (0/1/2) | ✅ | 48/49/50→2, 32/33/34→1, else 0 | | `p_dop` | float64 | ➖ 0 | BESTNAV 미제공(필요시 PVTSLN) | > `carr_soln`: **2=RTK Fixed(NARROW_INT 등), 1=RTK Float, 0=단독/DGPS**. --- ## 5. 드라이버 파라미터 명세 (`config/um982.yaml`) | 파라미터 | 기본값 | 설명 | |---|---|---| | `serial_port` | `/dev/ttyUSB0` | UM982 COM3(USB). 리눅스 `/dev/ttyUSB*` | | `serial_baud` | `460800` | 수신기 저장값과 일치 | | `gps_topic` | `/ublox_driver/receiver_pvt` | 발행 토픽(백엔드 `gps.gps_topic` 와 일치) | | `use_ntrip` | `true` | false 면 RTCM 주입 안 함(외부 보정 시) | | `ntrip_host/port/mountpoint` | `RTS1.ngii.go.kr` / `2101` / `VRS-RTCM34` | NTRIP 접속 | | `ntrip_user/pass` | `""` | ⚠️ 리포 평문 커밋 지양 — yaml/CLI/환경변수로 주입 | | `gga_send_period` | `10.0` | VRS 유지용 GGA 재전송 주기(s) | | `publish_fixed_only` | `false` | true=RTK Fixed 해만 발행 | | `inflate_cov_when_not_fixed` | `true` | fix 아님/코스팅 시 h_acc·v_acc 부풀림 | | `max_corr_age` | `30.0` | diff_age 초과 시 코스팅 간주(공분산↑). 0=비활성 | > NTRIP 끊겨도 UM982 는 `RTK TIMEOUT`(기본 600s) 동안 Fixed 를 코스팅 유지 → `max_corr_age` 로 신뢰 낮춤. --- ## 6. 시간 의미 (중요) - 메시지에 Header/stamp 가 **없다.** 시간은 `time.week`(GPS week) + `time.tow`(주 내 초). - UNIX 복원: `unix = week·604800 + tow + 315964800 − 18(leap)` (백엔드 `optimization.cpp::gpsHandler` 와 동일). - 유효 조건: 헤더 TimeStatus=`FINE` & week>1 (fix 전에는 week=1/UNKNOWN). - `ros2 bag` 은 **수신 시각(bag timestamp)** 을 별도로 기록하지만, **권위 시각은 메시지 내부 week/tow**. 센서와의 시각 동기는 이 값 기준. --- ## 7. 녹화 절차 ### 7.1 실행 ```bash source install/setup.bash ros2 launch um982_driver um982_driver.launch.py # 또는 아래 run # 자격증명을 CLI 로 주입: ros2 run um982_driver um982_driver_node --ros-args \ --params-file src/um982_driver/config/um982.yaml \ -p ntrip_user:= -p ntrip_pass:= ``` 콘솔에 `RTK FIXED` 전환 로그가 뜨고, `ros2 topic hz /ublox_driver/receiver_pvt` ≈ 10Hz 확인. ### 7.2 GNSS 단독 녹화 ```bash ros2 bag record -o rtk_$(date +%F_%H%M) /ublox_driver/receiver_pvt ``` ### 7.3 센서 + GNSS 동시 녹화 (FAST-LIVO2 후처리용) ```bash ros2 bag record -o run_$(date +%F_%H%M) \ /livox/lidar /livox/imu /left_camera/image \ /ublox_driver/receiver_pvt \ --storage mcap # 없으면 sqlite3(기본) ``` > 초기 수십 초 **RTK Fixed + 충분한 이동** 후 녹화(백엔드 SVD 정합 전제). `rtk/UM982-녹화-및-연동-구현.md` §7 참조. ### 7.4 (권장) 원시 BESTNAV 동시 녹화 — 재처리 대비 현재 드라이버는 파싱 결과만 발행한다. 파싱 로직을 나중에 고쳐 재생성하려면 **원시 바이트도 함께** 남기는 것을 권장(별도 옵션 필요 — §10). --- ## 8. 녹화 데이터 포맷 & 재생 - 저장: ROS 2 bag (`sqlite3` `.db3` 기본, 또는 `mcap` `.mcap`). - 확인: `ros2 bag info run_YYYY-MM-DD_HHMM` → 토픽/메시지 수/기간. - 재생: `ros2 bag play run_YYYY-MM-DD_HHMM` → `/ublox_driver/receiver_pvt` 재발행. - FAST-LIVO2 백엔드는 이 토픽을 구독해 첫 fix 를 ENU 원점으로 잡고 GTSAM 융합(`gps.gps_topic` 일치 필요). --- ## 9. 품질/필터 (녹화되는 데이터의 신뢰) - 백엔드에 fix 품질 필터가 **없으므로** 드라이버 단에서 처리: - `publish_fixed_only=true` → RTK Fixed 해만 녹화(가장 보수적). - `inflate_cov_when_not_fixed=true` + `max_corr_age` → fix 아님/코스팅 시 `h_acc/v_acc` 를 키워 후처리 가중 약화. - CRC(Unicore Appendix 1) 통과 프레임만 발행 → 손상 프레임 녹화 안 됨. --- ## 10. 확장(옵션) — 원시 스트림 동시 녹화 재처리·디버깅을 위해 원시 BESTNAV/GGA 바이트를 별도 토픽으로 녹화하려면 드라이버에 `std_msgs/msg/ByteMultiArray`(또는 String) 발행부를 추가하면 된다(예: `/um982/raw`). 필요 시 요청 → 드라이버에 `publish_raw` 파라미터로 추가. --- ## 11. 검증 체크리스트 - [ ] `rtk/config_all.py` 로 수신기 설정 저장(BESTNAVB/GPGGA, 460800, MODE ROVER) - [ ] `colcon build --packages-select gnss_comm um982_driver` 성공 - [ ] `serial_port` / NTRIP 자격증명(config or CLI) 확인 - [ ] `ros2 topic hz /ublox_driver/receiver_pvt` ≈ 10Hz, 콘솔 `RTK FIXED` - [ ] `ros2 topic echo` 로 lat/lon/altitude, time.week(>1)/tow, carr_soln=2 확인 - [ ] `ros2 bag record` → `ros2 bag info` 로 토픽·기간 확인 - [ ] (동시녹화) 센서 4종 + GNSS 토픽 모두 bag 에 존재 ```