← GPS hoạt động thế nào?

Bài 9 · Nâng cao · 30 phút

Dự án cuối khoá

Biên soạn bởi Nguyễn Anh Tuấn

Ghép mọi thứ, chạy trên trình duyệt: tự định vị bằng trilateration, tính khoảng cách đường chim bay bằng công thức Haversine, và mổ xẻ một câu NMEA ($GPGGA).

Tám bài qua, mèo con đã đi từ vệ tinh phát tín hiệu tới chấm xanh trên bản đồ. Giờ là lúc tự tay làm ba thử thách nhỏ, mỗi cái dùng một mảnh đã học - không phải học thuộc, mà là chạy thật.

Nhớ Bài 4 chứ? Mỗi vệ tinh cho một khoảng cách = một vòng tròn; ba vòng giao tại đúng một điểm. Kéo thử lại, đặt mình vào vai máy thu:

Số vệ tinh:
🛰️🛰️🛰️🐱

Ba vệ tinh: ba vòng giao nhau tại đúng MỘT điểm - chính là bạn.

Kéo 🛰️ vệ tinh hoặc 🐱 máy thu. Mỗi vòng tròn = “máy thu cách vệ tinh này đúng bấy nhiêu”.

  • 1 vệ tinh = một vòng (vô số khả năng); 2 = hai điểm; 3 = một điểm.
  • Đây chính là phép toán máy thu chạy mỗi lần định vị.
  • Đời thực là 3D mặt cầu, cộng vệ tinh thứ tư cho đồng hồ.

Có hai toạ độ GPS rồi, tính khoảng cách giữa chúng thế nào? Vì Trái Đất cong, ta dùng công thức Haversine để ra đường chim bay (đường ngắn nhất trên mặt cầu, gọi là great-circle):

hav.py - khoang cach duong chim bay giua hai toa do

import math

def haversine(lat1, lon1, lat2, lon2):
    R = 6371.0  # ban kinh Trai Dat (km)
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp = math.radians(lat2 - lat1)
    dl = math.radians(lon2 - lon1)
    a = math.sin(dp/2)**2 + math.cos(p1)*math.cos(p2)*math.sin(dl/2)**2
    return 2 * R * math.asin(math.sqrt(a))

ha_noi  = (21.028, 105.834)   # Ho Hoan Kiem (xap xi)
sai_gon = (10.776, 106.701)   # Cho Ben Thanh (xap xi)
print(f"Duong chim bay Ha Noi <-> Sai Gon: {haversine(*ha_noi, *sai_gon):.0f} km")

Kết quả khi chạy

Duong chim bay Ha Noi <-> Sai Gon: 1144 km

Trung thực

1.144 km là đường chim bay. Đi xe Hà Nội - Sài Gòn dài hơn nhiều (khoảng 1.700 km) vì phải theo đường xá thực tế. Haversine cho cự ly thẳng trên mặt cầu, không phải quãng đường đi.

Máy thu GPS thật “nhả” ra những dòng chữ theo chuẩn NMEA. Câu $GPGGA gói kết quả một lần định vị. Tách nó ra để lấy vĩ độ, kinh độ, độ cao:

nmea.py - mo xe mot cau $GPGGA

cau = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47"

def ddmm_sang_do(chuoi, huong):
    diem = chuoi.find('.')
    do = int(chuoi[:diem - 2])
    phut = float(chuoi[diem - 2:])
    kq = do + phut / 60
    return -kq if huong in ('S', 'W') else kq

p = cau.split(',')
gio = p[1]
print(f"Gio (UTC) : {gio[0:2]}:{gio[2:4]}:{gio[4:6]}")
print(f"Vi do     : {ddmm_sang_do(p[2], p[3]):.4f}")
print(f"Kinh do   : {ddmm_sang_do(p[4], p[5]):.4f}")
print(f"So ve tinh: {int(p[7])}")
print(f"Do cao    : {float(p[9])} m")

Kết quả khi chạy

Gio (UTC) : 12:35:19
Vi do     : 48.1173
Kinh do   : 11.5167
So ve tinh: 8
Do cao    : 545.4 m

Trung thực

Đây là bản rút gọn để thấy ý chính. Câu NMEA thật còn nhiều loại ($GPRMC, $GPGSV…), có mã kiểm tra (checksum sau dấu *), và máy thường gửi cả chùm câu mỗi giây.

Ghép lại cả khoá, giờ bạn hiểu trọn con đường từ trời xuống màn hình điện thoại:

Từ chòm vệ tinh trên trời tới chấm xanh trong tay - mèo con đã đi hết một vòng.
  • Vệ tinh ở MEO phát thời gian (đồng hồ nguyên tử) + vị trí (ephemeris).
  • Máy thu đổi thời gian bay thành khoảng cách (pseudorange).
  • Trilateration giao nhiều khoảng cách ra vị trí; vệ tinh thứ 4 trị đồng hồ.
  • Sai số được hiểu và hiệu chỉnh; mất sóng thì WiFi/Bluetooth/4G và cảm biến gánh.

Chúc mừng mèo con! 🐱🛰️

Bạn không còn xem GPS như phép màu nữa - bạn hiểu nó vận hành thế nào, và biết vì sao đôi khi nó sai. Giữ sự tò mò đó: ghé các khoá khác để tiếp tục bóc tách công nghệ quanh mình.

Câu hỏi thường gặp

Haversine cho “đường chim bay” - đường ngắn nhất trên mặt cầu. Google Maps tính đường đi THỰC theo đường xá, luôn dài hơn vì phải vòng theo đường có sẵn.

Vì Trái Đất cong. Ở khoảng cách ngắn (vài km) tính trên mặt phẳng cũng tạm, nhưng đi xa (hàng trăm, hàng nghìn km) mà coi Trái Đất phẳng thì sai số lớn dần.

Là chuẩn các câu chữ (text) mà máy thu GPS xuất ra. $GPGGA là một loại (chứa vị trí và độ cao); còn $GPRMC, $GPGSV… chứa thông tin khác như tốc độ, danh sách vệ tinh.

Là “checksum” - một mã kiểm tra ngắn để máy biết câu có bị lỗi khi truyền không. Nếu tính lại không khớp, câu đó bị bỏ.

Đó là định dạng độ-phút (ddmm.mmmm): 48 độ và 07.038 phút, KHÔNG phải 4807 độ. Đổi sang độ thập phân: 48 + 7.038/60 ≈ 48,1173 độ.

Trên web có Geolocation API của trình duyệt; trên app có API của hệ điều hành. Cách gọi chúng thuộc về các khoá lập trình - còn khoá này cho bạn hiểu CÁI GÌ chạy bên dưới những API đó.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Công thức Haversine tính kiểu khoảng cách nào giữa hai toạ độ GPS?

  1. 1

    Tự định vị bằng trilateration

    Dùng mô phỏng ở Thử thách 1: đặt 3 vệ tinh và 1 máy thu, kéo thử, xác nhận ba vòng tròn luôn giao đúng một điểm.

    Hoàn thành khi: Với 3 vệ tinh, giao điểm chốt đúng vị trí máy thu; bớt còn 2 vệ tinh thì xuất hiện “điểm ma”.

  2. 2

    Đường chim bay vs đường đi

    Chạy hav.py ở Thử thách 2. Đường chim bay Hà Nội - Sài Gòn ra bao nhiêu? Vì sao đường đi xe (~1.700 km) lại dài hơn?

    Hoàn thành khi: Khoảng 1.144 km (đường chim bay). Đường xe dài hơn vì phải đi vòng theo đường xá thực tế, không bay thẳng được.

  3. 3

    Đổi toạ độ

    Trong hav.py, đổi một điểm thành nơi mèo con đang ở (tra toạ độ trên bản đồ), chạy lại và đọc kết quả.

    Hoàn thành khi: Ra một con số km hợp lý cho cặp toạ độ mới; luôn nhớ đó là đường chim bay, ngắn hơn đường đi thực.

  4. 4

    Mổ xẻ câu NMEA

    Chạy nmea.py ở Thử thách 3. Vĩ độ, kinh độ và độ cao máy thu báo là bao nhiêu?

    Hoàn thành khi: Vĩ độ 48,1173; kinh độ 11,5167; độ cao 545,4 m (và 8 vệ tinh, lúc 12:35:19 UTC).

  5. 5

    Đổi độ-phút bằng tay

    Không dùng code, tự đổi “4807.038 N” sang độ thập phân.

    Hoàn thành khi: 48 + 7,038 ÷ 60 = 48,1173 độ Bắc.

  6. 6

    Hành trình của mèo con

    Bằng lời của mèo con, kể lại mạch chính cả khoá trong 2 - 3 câu: từ tín hiệu vệ tinh tới chấm xanh trên bản đồ.

    Hoàn thành khi: Nhắc được mạch: vệ tinh phát thời gian + vị trí → đo khoảng cách → trilateration ra vị trí → sai số & hiệu chỉnh → định vị lai khi mất sóng.