-
CZ-ME310G1모뎀 AGPS 꼭 쓰세요~!! 첫번째 이야기Asset tracking 2026. 6. 26. 20:55
CZ-ME310G1모뎀은 AGPS를 지원합니다.

GNSS 속도의 한계를 깨는 키, A-GPS
GNSS 모듈이 맨 처음 켜졌을 때(Cold Boot) 하늘에 떠 있는 위성 신호를 직접 다 잡아 위치를 계산하려면 보통 수분이 걸립니다. 하지만 A-GPS를 사용하면 이야기가 달라집니다.
- 동작 원리: LTE 기지국 네트워크를 통해 위성 좌표 데이터를 서버에서 초고속으로 다운로드하여 참조합니다.
- 성능 향상:
- 콜드 부트(Cold Boot): 최초 위치 확보(TTFF) 속도를 극적으로 단축합니다.
- 웜 부트(Warm Boot): 칩이 깨어나는 즉시 신속하게 현재 위치를 타겟팅합니다.
💡 검증된 퀄컴(Qualcomm) 인프라 활용 A-GPS의 성능은 데이터를 뿌려주는 서버의 상태에 좌우됩니다. CZ-ME310G1모뎀은 업계 표준인 퀄컴의 글로벌 위치 서비스 서버를 기본 제공하므로, 상용 제품 수준의 독보적인 신뢰성과 빠른 속도를 안정적으로 누릴 수 있습니다.
얼마나 빨리 접속하는지는 뒤에서 테스트코드와 데모영상으로 보여 드리겠습니다.
CZ-ME310G1모뎀은 AT커맨드 몇 줄로 간단하게 AGPS를 사용하실 수 있습니다.
일단 TransparentBridge example을 올려서 AT커맨드로 바로 사용해 보겠습니다.
부팅 후 모뎀을 사용할 수 있는 준비가 되면 아래와 같이 Bridge Communication Enabled 메시지가 출력됩니다.
이제 Serial Monitor를 Carriage Return, 115200baud로 설정합니다.
Serial Monitor 아래 입력창에 AT 입력 후 Enter키를 눌렀을 때 OK라고 나오면 이제 시작하겠습니다.
순서대로 살펴보겠습니다.
1. AGPS 준비과정 : AGPS 설정 후 REBOOT 해야 AGPS를 사용할 수 있음
1) AGPS 설정되어 있는가?
AT$AGNSS?
$AGNSS: 0,0,0
OK
--> 반환값이 $AGNSS: 0,0,0 이면 AGPS 설정이 안 되어 있는 상태
2) AGNSS 설정
AT$AGNSS=0,1
OK
3) Qualcomm XTRA 데이터 자동 다운로드 설정
아래 내용을 참고해서 설정 합니다.
- 1일 치 파일: 12.993 KB
- 3일 치 파일 (기본값): 17.827 KB
- 7일 치 파일: 27.489 KB
XTRA 데이터는 세 번째 값이 0이면 24시간에 1회, 1이면 72시간 1회(기본값), 2면 168시간 1회
AT$AGNSSCFG=0,0,0
OK
4) 셋팅값 확인
AT$AGNSS?
$AGNSS: 0,0,1 현재는 0이고 재부팅 후에는 1이 될 거야.
OK
5) REBOOT후 AT OK 반환될 때까지될때까지 대기 후 진행
AT#REBOOT
OK2. AGPS 사용
1) AGPS 설정되어 있는가? è 반환값이 $AGNSS: 0,1,1 이면 AGPS 설정 완료되어 있는 상태
AT$AGNSS?
$AGNSS: 0,1,1
OK
2) 망에 연결되었는지 체크, 연결되면 다음으로 진행
AT+CEREG?
+CEREG: 0,5
OK
3) 기지국에서 IP 획득
AT#SGACT=1,1
#SGACT: 10.87.179.130
OK
4) NTP 설정 준비
AT#NTPCFG=1,0
OK
5) NTP 서버를 통해 RTC설정
AT#NTP="216.239.35.0",123,1,5,36
#NTP: 26/06/24,21:26:56+36
OK
3. MQTT 통신으로 위도, 경도 좌표 전달연결 끊김 없이 LTE와 GPS를 번갈아 쓰는 비법
IoT 단말을 개발하다 보면 MQTT 데이터 전송과 GPS 위치 수신을 번갈아 해야 할 때가 많습니다. 다행히 매번 서버 접속을 끊고 다시 연결(Re-connect)하는 수고를 겪을 필요가 없습니다. 서버와 한 번 연결된 상태만 잘 이용하면 끊김 없는 연속 통신이 가능합니다.
비밀은 모뎀 내부의 '아비터(Arbiter)' 블록에 있습니다.
- 일시 중지(Suspend) 마법: 모뎀 내부의 중재자인 아비터는 GNSS 위치를 잡아야 할 때, 기존에 서버와 접속 중이던 LTE 통신 블록을 잠시 '일시 중지(Suspend)' 상태로 만듭니다.
- 타임아웃의 활용: 연결이 완전히 끊긴 것이 아닙니다! 설정해 둔 타임아웃(예: MQTT Keep-Alive 120초) 이내에 GPS 수신을 끝내고 다시 LTE 모드로 복귀하기만 하면 기존 접속이 그대로 유지됩니다.

이 개념을 염두에 두고 아래 AT커맨드 동작흐름을 살펴보겠습니다.
AT#MQEN=1,1
OK
AT#MQCFG=1,"broker.emqx.io",1883,1,0
OK
AT#MQCFG2=1,120,0 //Keep-Alive 120초 설정
OK
//MQTT 서버 연결
AT#MQCONN=1,"myIoTDevice","",""
OK
AT$GPSCFG=3,0 //RF우선순위를 GPS로 변경, 서버는 연결된 상태로 120초간 유지됨.모드 변경에 3초 소요
OK
AT$GPSP=1 //GPS를 켜준다. AGPS로 동작시작.
OK
AT$GNSSACP //8번째 매개변수가 2 이상이 되면 AGPS가 위치를 잡은 상태임. 그때부터 위도, 경도값 사용
$GNSSACP: ,,,,,,,1,,,,,,, //8번째 매개변수 값이 2 : 2D Fix, 3 : 3D Fix
OK
AT$GNSSACP
$GNSSACP: ,,,,,,,1,,,,,,,
OK
AT$GNSSACP //8번째 매개변수 3 : 3D Fix, 13번째 매개변수 07: 현재 연결된 위성갯수 7개, 좌표획득!!
$GNSSACP: 123602.000,240626,3730.3641N,12704.7538E,22.9,1.4,1.0,3,0.0,0.0,0.0,AANNNN,07,22.41,36.25
OK
AT$GPSCFG=3,1 //RF우선순위를 LTE로 변경, 모드 변경에 3초 소요
OK
AT#MQPUBS=1,"czme310/topic/put",0,0,"3730.3730N,12704.7397E" //위도, 경도 좌표 Publish
OK
AT$GPSCFG=3,0 //RF우선순위를 GPS로 변경, 모드 변경에 3초 소요
OK
AT$GNSSACP
$GNSSACP: 123930.000,240626,3730.3645N,12704.7478E,40.,0.9,0.8,3,0.0,0.0,0.0,AANNNN,11,5.62,9.34
OK
AT$GPSCFG=3,1 //RF우선순위를 LTE로 변경, 모드 변경에 3초 소요
OK
AT#MQPUBS=1,"czme310/topic/put",0,0,"3730.3645N,12704.7478E" //위도, 경도 좌표 Publish
OK
//MQTT 서버 DisConnect
AT#MQDISC=1
OK
//MQTT Disable
AT#MQEN=1,0
OK
//기지국 해제
AT#SGACT=1,0
OK
마지막으로 GNSSACP 프로토콜 스펙입니다.$GNSSACP: 111417.000,240626,3730.3331N,12704.7752E,43.9,1.0,0.9,3,00,0.0,0.0,AANNNN,10,10.00,7.92
1. 측정된 UTC 시간 : 111417.000 (<UTC>) (11시 14분 17.000초).
2. 측정된 날짜 : 240626 (<date>) (2024년 6월 26일, ddmmyy 형식).
3. 위도 데이터 : 3730.3331N (<latitude>) (북위 37도 30.3331분).
4. 경도 데이터 : 12704.7752E (<longitude>) (동경 127도 04.7752분).
5. 고도 : 43.9 (<altitude>) 해수면을 기준으로 한 해발 고도(미터) (43.9m).
6. 수평 위치 정밀도 저하율 : 1.0 (<hdop>) (낮을수록 정밀함).
7. 수직 위치 정밀도 저하율 : 0.9 (<vdop>).
8. 위치 고정(Fix) 상태 : 3 (<fix>) 3은 고도까지 정확하게 잡아낸 완벽한 3D Fix 상태를 의미. (0, 1은 invalid fix)
9. 진행 방향(Course over Ground)을 진북을 기준으로 나타낸 도(degrees) 값 : 00 (<cog>).
10. 지면 이동 속도 : 0.0 (<spkm>) (0.0 km/h).
11. 지면 이동 속도 노트 단위 : 0.0 (<spkn>) (0.0 knots).
12. AANNNN (<mode>): 6개의 위성 시스템(GPS, GLONASS, Galileo, BDS, QZSS, NavIC) 동작 모드를 차례대로 나타냄. A는 단독(Autonomous) 모드로 성공적으로 위치를 잡고 있음, N은 사용되지 않음(No fix)을 의미.
즉, 첫 번째와 두 번째 시스템인 GPS와 GLONASS 두 개의 위성망을 사용 중.
13. 10 (<nsat>): 현재 위치 획득에 실제로 사용 중인 위성의 총 개수
이제 AGPS를 사용해서 ColdBoot, WarmBoot에서 GNSS 위치를 잡는데 얼마나 빨라지는지 아래 간단한 테스트 코드로 확인해 보겠습니다.#include <Arduino.h>#include <ME310.h>
#define ON_OFF 2 /*Select the GPIO to control ON_OFF*/
// 모듈과 연결된 시리얼 포트 (ESP32나 Mega 등 하드웨어 시리얼 사용 시 Serial1 추천)#define MODEM_SERIAL Serial1#define DEBUG_SERIAL Serial
using namespace me310;
ME310 myME310;ME310::return_t rc; // Enum of return value methods
unsigned long startTime = 0;
int lv = 0;
// 함수 선언String sendATCommand(String command, const int timeout);String extractParameter(String payload, int index);double nmeaToDecimalDegrees(String nmeaString);
void setup() {DEBUG_SERIAL.begin(115200);MODEM_SERIAL.begin(115200);delay(100);myME310.debugMode(true);myME310.powerOn(ON_OFF);
DEBUG_SERIAL.println("=== ME310G1 AGPS & 좌표 변환 Test Started ===");
// 1. 망 접속 확인 (AT+CEREG?)DEBUG_SERIAL.println("\n1. Network Registration Check...");while (true) {String response = sendATCommand("AT+CEREG?", 2000);if (response.indexOf("0,5") != -1 || response.indexOf("0,1") != -1) {DEBUG_SERIAL.println("-> Network Registered!");break;}DEBUG_SERIAL.println("-> Not registered yet. Retrying in 2 seconds...");delay(2000);}
// 2. PDP 컨텍스트 활성화DEBUG_SERIAL.println("\n2. Activating PDP Context...");sendATCommand("AT#SGACT=1,1", 5000);
// 3. NTP 설정DEBUG_SERIAL.println("\n3. Configuring NTP...");sendATCommand("AT#NTPCFG=1,0", 2000);
// 4. NTP 동기화 (한국 시간)DEBUG_SERIAL.println("\n4. Synchronizing Time with NTP...");sendATCommand("AT#NTP=\"216.239.35.0\",123,1,5,36", 10000);
// 5. 런타임 우선순위 GNSS로 변경DEBUG_SERIAL.println("\n5. Setting GNSS Runtime Priority...");sendATCommand("AT$GPSCFG=3,0", 2000);
// 6. GNSS 엔진 가동!DEBUG_SERIAL.println("\n6. Powering up GNSS Engine...");sendATCommand("AT$GPSP=1", 2000);
startTime = millis();DEBUG_SERIAL.println("\n*** Timer Started! Waiting for GPS Fix... ***\n");}
void loop() {String response;
if (lv == 0) {// 7. 위치 정보 확인 (AT$GNSSACP 실행)response = sendATCommand("AT$GNSSACP", 1500);
if (response.indexOf("$GNSSACP:") != -1) {// "$GNSSACP: " 이후의 실제 데이터 문자열만 분리int payloadStart = response.indexOf(':') + 1;String payload = response.substring(payloadStart);payload.trim(); // 양쪽 공백 제거
// 8번째 매개변수(<fix> 상태) 추출 -> 인덱스 번호는 7 (0부터 시작)String fixStr = extractParameter(payload, 7);int fixVal = fixStr.toInt();
if (fixVal == 0 || fixVal == 1) {DEBUG_SERIAL.println("Connecting...");} else if (fixVal >= 2) {// 🌟 2D 또는 3D Fix 성공! 🌟unsigned long elapsedTime = millis() - startTime;
// 위도(3번째 매개변수, 인덱스 2)와 경도(4번째 매개변수, 인덱스 3) 추출String raw_lat = extractParameter(payload, 2);String raw_lon = extractParameter(payload, 3);
// NMEA 포맷을 Decimal Degrees(십진수) 포맷으로 변환double dd_lat = nmeaToDecimalDegrees(raw_lat);double dd_lon = nmeaToDecimalDegrees(raw_lon);
// 결과 출력DEBUG_SERIAL.print("\n====================================\n");DEBUG_SERIAL.print("🌟 AGPS 연결 성공! 🌟\n");DEBUG_SERIAL.print("소요 시간(TTFF): ");DEBUG_SERIAL.print(elapsedTime / 1000.0);DEBUG_SERIAL.println(" 초");DEBUG_SERIAL.println("전체 응답값: " + response);DEBUG_SERIAL.println("------------------------------------");DEBUG_SERIAL.println("[좌표 변환 결과]");DEBUG_SERIAL.print("원본 위도 (NMEA): ");DEBUG_SERIAL.println(raw_lat);DEBUG_SERIAL.print("변환된 위도 (DD): ");DEBUG_SERIAL.println(dd_lat, 6);DEBUG_SERIAL.print("원본 경도 (NMEA): ");DEBUG_SERIAL.println(raw_lon);DEBUG_SERIAL.print("변환된 경도 (DD): ");DEBUG_SERIAL.println(dd_lon, 6);DEBUG_SERIAL.print("====================================\n");
DEBUG_SERIAL.println("\nPowering off GNSS Engine...");sendATCommand("AT$GPSP=0", 2000);
delay(3000);
DEBUG_SERIAL.println("\nPowering on GNSS Engine...");sendATCommand("AT$GPSP=1", 2000);
startTime = millis();DEBUG_SERIAL.println("\n*** Timer ReStarted! Waiting for GPS Fix... ***\n");
lv++;}}}else {// 7. 위치 정보 확인 (AT$GNSSACP 실행)response = sendATCommand("AT$GNSSACP", 1500);
if (response.indexOf("$GNSSACP:") != -1) {// "$GNSSACP: " 이후의 실제 데이터 문자열만 분리int payloadStart = response.indexOf(':') + 1;String payload = response.substring(payloadStart);payload.trim(); // 양쪽 공백 제거
// 8번째 매개변수(<fix> 상태) 추출 -> 인덱스 번호는 7 (0부터 시작)String fixStr = extractParameter(payload, 7);int fixVal = fixStr.toInt();
if (fixVal == 0 || fixVal == 1) {DEBUG_SERIAL.println("Connecting...");} else if (fixVal >= 2) {// 🌟 2D 또는 3D Fix 성공! 🌟unsigned long elapsedTime = millis() - startTime;
// 위도(3번째 매개변수, 인덱스 2)와 경도(4번째 매개변수, 인덱스 3) 추출String raw_lat = extractParameter(payload, 2);String raw_lon = extractParameter(payload, 3);
// NMEA 포맷을 Decimal Degrees(십진수) 포맷으로 변환double dd_lat = nmeaToDecimalDegrees(raw_lat);double dd_lon = nmeaToDecimalDegrees(raw_lon);
// 최종 결과 출력DEBUG_SERIAL.print("\n====================================\n");DEBUG_SERIAL.print("🌟 AGPS 연결 성공! 🌟\n");DEBUG_SERIAL.print("소요 시간(TTFF): ");DEBUG_SERIAL.print(elapsedTime / 1000.0);DEBUG_SERIAL.println(" 초");DEBUG_SERIAL.println("전체 응답값: " + response);DEBUG_SERIAL.println("------------------------------------");DEBUG_SERIAL.println("[좌표 변환 결과]");DEBUG_SERIAL.print("원본 위도 (NMEA): ");DEBUG_SERIAL.println(raw_lat);DEBUG_SERIAL.print("변환된 위도 (DD): ");DEBUG_SERIAL.println(dd_lat, 6);DEBUG_SERIAL.print("원본 경도 (NMEA): ");DEBUG_SERIAL.println(raw_lon);DEBUG_SERIAL.print("변환된 경도 (DD): ");DEBUG_SERIAL.println(dd_lon, 6);DEBUG_SERIAL.print("====================================\n");
DEBUG_SERIAL.println("\nPowering off GNSS Engine...");sendATCommand("AT$GPSP=0", 2000);// 테스트 종료 (무한 대기)while (true) {delay(10000);}}}}delay(1000); // 1초 간격으로 반복 조회}
// ---------------------------------------------------------// [헬퍼 함수] AT 커맨드 전송 및 응답 수신// ---------------------------------------------------------String sendATCommand(String command, const int timeout) {String response = "";MODEM_SERIAL.println(command);long int time = millis();
while ((time + timeout) > millis()) {while (MODEM_SERIAL.available()) {char c = MODEM_SERIAL.read();response += c;}}return response;}
// ---------------------------------------------------------// [헬퍼 함수] 콤마(,)로 구분된 데이터에서 특정 인덱스의 값 추출// ---------------------------------------------------------String extractParameter(String payload, int index) {int start = 0;for (int i = 0; i < index; i++) {start = payload.indexOf(',', start) + 1;if (start == 0) return ""; // 콤마가 모자라면 빈 문자열 반환}int end = payload.indexOf(',', start);if (end == -1) end = payload.length(); // 마지막 파라미터인 경우
return payload.substring(start, end);}
// ---------------------------------------------------------// [헬퍼 함수] NMEA 포맷을 Decimal Degrees로 변환하는 함수// ---------------------------------------------------------double nmeaToDecimalDegrees(String nmeaString) {int dotIndex = nmeaString.indexOf('.');if (dotIndex == -1) return 0.0; // 잘못된 데이터 처리
// '분(Minute)'은 항상 소수점 앞 2자리부터 시작합니다.int minIndex = dotIndex - 2;
// '도(Degree)'와 '분(Minute)' 문자열 분리String degStr = nmeaString.substring(0, minIndex);String minStr = nmeaString.substring(minIndex);
// 숫자로 변환 (이때 뒤에 붙은 N, E 등의 문자는 자동으로 제외됨)int degrees = degStr.toInt();double minutes = minStr.toFloat();
// 공식: 도 + (분 / 60)double decimalDegrees = degrees + (minutes / 60.0);
// (Pro-Tip) 남반구(S)나 서반구(W)일 경우 음수로 변환하는 방어 로직 추가if (nmeaString.endsWith("S") || nmeaString.endsWith("W")) {decimalDegrees *= -1.0;}
return decimalDegrees;}
결과가 콜드부트 연결 시 16.5초, 웜부트 연결시 5초 정도 소요 되었습니다.
16.5초는 기록이 상당히 좋게 나왔는데 일반적으로 19초에서 30초 정도 콜드부트 GNSS 연결시간이 소요됩니다.
AGPS를 사용하지 않고 연결 시 1분에서 1분 30초 정도 걸리던 시간에서 상당히 단축되었습니다.(!!!)
콜드부트상태에서 최초 위치를 잡은 후 GNSS만 ON/OFF 하면서 사용하는데 다시 연결할 때는 2.5초에서 5초 정도로 상당히 빠른 속도로 위치를 잡습니다.AT
AT
AT
AT$GPSP=1
AT$GPSP=0
=== ME310G1 AGPS & 좌표 변환 Test Started ===
1. Network Registration Check...
-> Not registered yet. Retrying in 2 seconds...
-> Network Registered!
2. Activating PDP Context...
3. Configuring NTP...
4. Synchronizing Time with NTP...
5. Setting GNSS Runtime Priority...
6. Powering up GNSS Engine...
*** Timer Started! Waiting for GPS Fix... ***
Connecting...
Connecting...
Connecting...
Connecting...
Connecting...
Connecting...
====================================
🌟 AGPS 연결 성공! 🌟
소요 시간(TTFF): 16.50 초
전체 응답값: AT$GNSSACP
$GNSSACP: 133922.100,150726,3730.3769N,12704.7314E,-1.9,1.3,0.9,3,0.0,1.5,0.8,ANNNNN,06,35.41,41.95
OK
------------------------------------
[좌표 변환 결과]
원본 위도 (NMEA): 3730.3769N
변환된 위도 (DD): 37.506282
원본 경도 (NMEA): 12704.7314E
변환된 경도 (DD): 127.078857
====================================
Powering off GNSS Engine...
Powering on GNSS Engine...
*** Timer ReStarted! Waiting for GPS Fix... ***
Connecting...
====================================
🌟 AGPS 연결 성공! 🌟
소요 시간(TTFF): 5.00 초
전체 응답값: AT$GNSSACP
$GNSSACP: 133935.000,150726,3730.3607N,12704.7456E,11.2,1.1,0.8,3,0.0,0.0,0.0,AANNNN,09,17.55,21.68
OK
------------------------------------
[좌표 변환 결과]
원본 위도 (NMEA): 3730.3607N
변환된 위도 (DD): 37.506012
원본 경도 (NMEA): 12704.7456E
변환된 경도 (DD): 127.079093
====================================
Powering off GNSS Engine...
영상(Youtube)
https://youtu.be/FYK6WQKIjdQ위도, 경도를 구글맵에 표시한 지도는 아래와 같습니다.상당히 정확하게 위치를 잡았습니다.
LTE-CATM1 내장형 모뎀 대량 구매 상담, 외주 개발, 협업 문의, vodafone IoT유심 문의
(주)코드주
장병남 대표 010-8965-1323 rooney.jang@codezoo.co.kr코드주 LTE-CatM1 내장형 모뎀 CZ-ME310G1 / GNSS(GPS) 지원 / 외장 LTE 안테나 포함 / Zephyr 및 Arduino 지원
메카솔루션 공식 쇼핑몰
www.mechasolution.com
iot유심 : codezoo
[codezoo] IoT Global SIM, IoT Connectivity, IoT Device
smartstore.naver.com
LTE + GNSS Cabinet 안테나 : codezoo
[codezoo] IoT Global SIM, IoT Connectivity, IoT Device
smartstore.naver.com
CodeZoo LTE-CatM1 전용 아두이노 브레이크아웃 쉴드
메카솔루션 공식 쇼핑몰
mechasolution.com
'Asset tracking' 카테고리의 다른 글
CZ-ME310G1모뎀 AGPS 꼭 쓰세요~!! 두번째 이야기 (0) 2026.07.21 영등포 ➔ 마곡 ➔ 강동 ➔ 청량리, 차량 Asset Tracking Map 제작 (4) 2025.04.13 CZ-ME310G1모뎀, Thingspeak.com, Google Map으로 Asset tracking 지도 제작하기 (6) 2025.04.12