2020년경부터 홈서버에 관심이 많았지만, 자고로 제대로 된 홈서버란 모든 인프라를 스스로 갖춰야 한다는 괴상한 신념을 갖게 되었습니다.
그래서... 위성에서 GNSS를 다이렉트로 받는 시간 서버를 만들어야 한다는 결론에 이르렀습니다.(?)
저는 인터넷을 뒤져가며 삽질한 내용이라 부정확한 정보가 포함될 수 있습니다.
가이드... 라기보단 그냥 이상한 기록으로 생각하고 읽어주세요.
▶ 준비물 - 배경지식
1. NTP (Network Time Protocol)
네트워크로 시간을 동기화하는 프로토콜입니다.
RFC958에서 최초로 제안되었고, RFC5905에서 현대에 주로 사용되는 NTPv4가 정의되었습니다.
NTP 시간 소스는 보통 Stratum(계층) 0~15로 구성됩니다.
Stratum0은 가장 정확한 기준 시각을 제공합니다.
보통 세슘 원자시계나 라디오 수신기 등의 고정밀 하드웨어를 가리킵니다.
Stratum1은 Stratum0에 직접 연결된 NTP 서버입니다.
협정 세계시(UTC)를 기준으로 하며, 123/UDP로 통신합니다.
Stratum 2~15는 하위 계층의 서버들입니다.
보통 자신의 바로 위 계층으로부터 시간을 동기화합니다.
NTP 패킷에는 이하 4개의 타임스탬프가 사용됩니다.
- Reference Timestamp: 시스템 시계가 동기화된 시각
- Originate Timestamp: 클라이언트가 요청을 보낸 시각
- Receive Timestamp: 서버가 요청을 받은 시각
- Transmit Timestamp: 서버가 응답을 보낸 시각
클라이언트는 여기에 자신이 패킷을 수신한 시간까지 더해 왕복 네트워크 지연을 계산합니다.
더 자세한 내용은 이 사이트를 참고
- [정보통신기술용어해설] NTP Network Time Protocol 네트워크 타임 프로토콜, NTP 프로토콜
2. GNSS (Global Navigation Satellite System)
지상 물체의 위치, 고도, 속도 등의 정보를 제공하는 위성 항법 시스템입니다.
미국 GPS, 러시아 GLONASS, 중국 BeiDou, 유럽연합 Galileo 등이 있습니다.
현대의 GNSS 수신기는 그냥 공짜로 전부 이용한다고 합니다.
통신 전공이 아니라서... 정확하진 않지만 이해한 대로 풀어보면,
위성은 다양한 종류의 GNSS Signal을 전송합니다.
가령 GPS의 경우 L1 C/A, L2C, L5, L1C 같은 형식, Galileo의 경우 E1, E5같은 형식을 사용합니다.
이 신호들은 각각 사용하는 주파수, PRN 코드 구조, 변조 방식이 모두 다릅니다.
여기서 민간에서 흔히 쓰이는 L1 C/A를 예시로 보자면,
L1 C/A에는 C/A PRN 코드와 LNAV 내비게이션 메시지가 포함됩니다.
C/A PRN은 GNSS 수신기가 특정 위성을 식별하는데 사용됩니다.
PRN은 무작위처럼 보이는데 무작위는 아닌(pseudo-random) 일종의 수열입니다.
LNAV 내비게이션 메시지는 50bps로 전송됩니다.
여기에는 위성의 상태와 날짜, 시간, 정밀 궤도정보(ephemeris), 위성군의 궤도정보(almanac)가 들어갑니다.
여기서 궤도정보에 특정 좌표가 직접 실리지는 않고, 케플러 궤도 6요소가 실리게 됩니다.
이 두 정보를 합쳐서 1575.42 MHz 대역 L1 반송파에 변조되어 송신됩니다.
그리고 지상의 GNSS 수신기는 위성으로부터 L1 C/A를 수신합니다.
GNSS 수신기의 수정발진기(crystal oscillator)는 거의 10MHz마다 발진합니다.
즉, 수신기는 자체적으로 정확한 1초 간격을 측정할 수 있습니다.
수신기는 알려진 PRN과 수신한 PRN을 비교해보면서, 자신의 자체 시간을 사용하여 지연 시간을 계산합니다.
그리고 이 지연 시간을 이용해서 위성과의 의사 거리(pseudorange)를 측정합니다.
그런데 수신기의 자체 시간 계산에도 오차가 있을 수 있습니다.
그래서 수신기는 3차원 공간 좌표를 계산하기 위해서, 그리고 자신의 시계 오차를 수정하기 위해서 최소 4개의 위성으로부터 신호를 받습니다.
이후 수신기는 항법 방정식을 풀어 현재 자신의 위치와 시간을 산출하고, 이때 수신기의 자체 시간 오차도 함께 보정됩니다.
이렇게 계산한 정보는 NMEA 0183 형식의 문장으로 변환되고,
리눅스에서는 연결 방식에 따라 /dev/serialX, /dev/ttyUSBX 같은 장치 파일로 NMEA를 읽을 수 있습니다.
NMEA에는 상당히 정확한 타임스탬프가 포함되어 있습니다.
하지만 GNSS 수신기 ~ 커널 ~ 프로세스까지 또 미세한 지연이 발생합니다.
그래서 GNSS 수신기가 내부적으로 보정한 정확한 1초 간격을 PPS 출력으로 받아야 합니다.
NTP 프로세스는 NMEA의 타임스탬프와 PPS의 초 경계를 조합하면 상당히 정확한 시간을 얻을 수 있습니다.
리눅스에서는 /dev/ppsX와 같은 장치 파일로 연동할 수 있습니다.
더 자세한 내용은 이 사이트를 참고
- [Quora] How do GPS devices communicate with satellites?
- [정보통신기술용어해설] GPS, GNSS Global Positioning System, Global Navigation Satellite System 범지구적 위성 측위 시스템
- [SBG SYSTEMS] PRN 코드 (Pseudo-Random Noise Code)
3. Chrony
리눅스용 NTP 유틸리티? 프로그램? 입니다.
크게 백그라운드 데몬인 chronyd와 클라이언트 툴인 chronyc로 나뉩니다.
과거에 자주 사용되던 ntpd에 비해 미세한 오차를 보정하는 능력이 뛰어나다고 합니다.
이 글에서는 Chrony를 NMEA, PPS와 연동하여 NTP 서버로 만들게 됩니다.
더 자세한 내용은 이 사이트를 참고
▶ 준비물 - 하드웨어


1. 라즈베리파이 3A+
원래 pi-hole 용도로 사용하던 보드입니다.
하지만 GPIO 핀헤더가 있는 보드가 필요해서 징집했습니다.
납땜을 할 줄 아는 분이라면 그냥 GNSS 모듈을 보드에 바로 납땜해도 될 듯 합니다.
2. GNSS 모듈
위성에서 GNSS Signal을 받기 위해 필요한 물건. 아래서 자세히 작성하겠습니다.
3. GPS 안테나
수신 감도를 높이기 위해 (특히 실내에서) 필요합니다.
필수 사양으로는 SMA Male 방식, 3.3~5.0V 전압, 1575.42MHz 지원이 필요합니다.
RP-SMA 규격은 비스무리하게 생겼지만 호환이 되지 않으니 유의해주세요.
저는 대충 저렴한 5천원짜리 차량용 제품을 구입했습니다.
4. 듀폰 점퍼케이블
GNSS 모듈에 세트로 있을줄 알았다가 없어서 쿠팡 새벽배송으로 급하게 주문했습니다...
5. 3.5인치 LCD 디스플레이
시계 화면으로 사용하기 위해 구입했습니다.

GNSS 모듈
저는 L80-M39와 NEO-M8N 제품을 구입했습니다.
두 제품 모두 3.3V~5.0V VCC를 지원하고, 필요한 경우 Micro USB 전원도 쓸 수 있습니다.
모듈이 자체 세라믹 패치 안테나를 가지고 있고, 별도로 SMA Female 규격의 동축 커넥터도 있습니다.
저는 어차피 외장 안테나를 사용할거라 세라믹 패치 안테나는 필요없지만... 뭐 없는 것보다는 낫겠죠...?
모듈에서 신호를 받기 위한 TX핀, 모듈을 제어하기 위한 RX핀, 그리고 가장 중요한 PPS핀 헤더도 모두 포함되어 있습니다.
이제 이 모듈을 라즈베리파이 3A+에 연결해서 GPS를 테스트하겠습니다.