Memahami NMEA 0183: Protokol di Balik Radar dan GPS Kapal (Tutorial Lengkap)

Di atas kapal modern, radar, GPS, kompas, depth sounder, dan AIS semuanya "berbicara" satu sama lain lewat satu bahasa yang sama: NMEA 0183. Tanpa protokol ini, radar tidak tahu posisi kapal sendiri, dan chart plotter tidak bisa menampilkan target AIS. Tutorial ini mengupas NMEA 0183 sampai kamu bisa membaca dan mem-parsing datanya sendiri.

1. Apa Itu NMEA 0183?

NMEA 0183 adalah standar komunikasi data elektronik marine. Cara kerjanya sederhana: perangkat mengirim kalimat teks lewat port serial (default 4800 baud, 8N1), satu kalimat per baris, diakhiri carriage-return + line-feed. Satu pengirim bisa didengar banyak penerima — misalnya satu GPS memberi data posisi ke radar, autopilot, dan chart plotter sekaligus.

Format dasarnya:

$TTSSS,data,data,data*hh

TT = talker ID (pengirim: GP = GPS, GL = GLONASS, GA = Galileo, GN = GNSS gabungan, SD = depth sounder, HC = kompas), SSS = jenis kalimat, hh = checksum 2 digit heksadesimal.

2. Kalimat yang Wajib Dikenal

GPGGA — data fix GPS:

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

Artinya: jam 12:35:19 UTC, lintang 48°07.038' N, bujur 11°31.000' E, kualitas fix 1 (GPS biasa), 8 satelit, HDOP 0.9, ketinggian 545.4 meter.

GPRMC — data minimum yang direkomendasikan:

$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

Artinya: status A (Active/valid — kalau V berarti Void/tidak valid), posisi sama seperti di atas, kecepatan 22.4 knot, haluan 084.4°, tanggal 23 Maret 1994.

Kalimat lain yang sering muncul: GPGSV (satelit yang terlihat), GPGSA (status fix & DOP), GPVTG (kecepatan & haluan gerak), SDDPT (kedalaman air), HCHDT (heading kompas), dan RATTM (target yang di-track radar: nomor target, jarak, bearing, kecepatan).

3. Cara Menghitung Checksum

Checksum = XOR semua karakter di antara $ dan *, ditulis sebagai 2 digit heksa huruf besar. Ini cara cepat memastikan kalimat tidak rusak di tengah jalan (noise di kabel serial itu nyata).

4. Kode Python: Parser NMEA Lengkap

Copy-paste kode ini — sudah termasuk validasi checksum, parsing GGA, dan konversi koordinat ke derajat desimal:

def nmea_checksum(body: str) -> str:
    c = 0
    for ch in body:
        c ^= ord(ch)
    return f"{c:02X}"

def nmea_ke_desimal(koordinat: str, arah: str) -> float:
    # format ddmm.mmmm (lintang) atau dddmm.mmmm (bujur)
    titik = koordinat.index(".")
    derajat = float(koordinat[:titik - 2])
    menit = float(koordinat[titik - 2:])
    desimal = derajat + menit / 60
    if arah in ("S", "W"):
        desimal = -desimal
    return desimal

def parse_kalimat(line: str):
    line = line.strip()
    if not line.startswith("$"):
        return None
    body, _, check = line[1:].partition("*")
    if check and nmea_checksum(body) != check.upper():
        return None  # checksum tidak cocok -> abaikan
    f = body.split(",")
    talker_type = f[0][2:]  # mis. GPGGA -> GGA
    if talker_type == "GGA":
        return {
            "tipe": "GGA",
            "waktu_utc": f[1],
            "lintang": nmea_ke_desimal(f[2], f[3]),
            "bujur": nmea_ke_desimal(f[4], f[5]),
            "kualitas_fix": f[6],
            "jumlah_satelit": f[7],
        }
    if talker_type == "RMC":
        return {
            "tipe": "RMC",
            "status": f[2],  # A = valid, V = tidak valid
            "lintang": nmea_ke_desimal(f[3], f[4]),
            "bujur": nmea_ke_desimal(f[5], f[6]),
            "kecepatan_knot": float(f[7]) if f[7] else 0.0,
            "tanggal": f[9],
        }
    return {"tipe": talker_type, "mentah": f[1:]}

# --- contoh pakai ---
for kalimat in [
    "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47",
    "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
]:
    print(parse_kalimat(kalimat))

Output yang diharapkan:

{'tipe': 'GGA', 'waktu_utc': '123519', 'lintang': 48.1173, 'bujur': 11.516666666666667, 'kualitas_fix': '1', 'jumlah_satelit': '08'}
{'tipe': 'RMC', 'status': 'A', 'lintang': 48.1173, 'bujur': 11.516666666666667, 'kecepatan_knot': 22.4, 'tanggal': '230394'}

5. Membaca dari Perangkat Asli via Serial

GPS marine atau multiplexer NMEA biasanya muncul sebagai port USB-serial di laptop. Install dulu pip install pyserial, lalu:

import serial

ser = serial.Serial("/dev/ttyUSB0", baudrate=4800, timeout=1)
while True:
    raw = ser.readline().decode("ascii", errors="ignore").strip()
    if raw.startswith("$"):
        hasil = parse_kalimat(raw)  # fungsi dari section 4
        if hasil:
            print(hasil)

Di Windows ganti /dev/ttyUSB0 dengan COM3 (cek di Device Manager). Kalau tidak ada data masuk, baca section troubleshooting di bawah.

6. Menyambungkan ke OpenCPN

OpenCPN bisa langsung menerima aliran NMEA 0183 — posisi kapal di chart akan bergerak mengikuti data aslimu:

1. Buka OpenCPN -> Options (ikon kunci inggris) -> Connections
2. Add Connection -> pilih Serial, isi port (mis. /dev/ttyUSB0)
   dan baudrate 4800 (atau Network untuk TCP/UDP dari multiplexer)
3. Centang "Receive", Apply -> OK
4. Ikon kapal di chart mulai bergerak; cek di NMEA Debug Window
   (ikon kunci inggris -> Connections -> Show NMEA Debug)

Kalau kamu build OpenCPN Android dari fork (pernah dibahas di blog ini), alurnya sama — bedanya input NMEA masuk lewat GPS internal HP atau koneksi network.

7. NMEA 2000 Sekilas

Jangan tertukar: NMEA 2000 adalah standar yang berbeda — berbasis CAN bus (seperti di mobil), 250 kbps, data biner dalam paket bernama PGN, dan satu kabel backbone untuk semua perangkat. NMEA 0183 yang dibahas di sini tetap yang paling mudah untuk dioprek karena berupa teks biasa. Untuk menghubungkan keduanya butuh gateway/converter NMEA 2000 → 0183.

8. Troubleshooting

Tidak ada data masuk: baudrate salah adalah penyebab nomor satu. Coba 4800 dulu, lalu 38400 (standar AIS), lalu 9600. Pastikan juga TX perangkat ke RX laptop dan sebaliknya — kabel kebalik = sunyi total.

Checksum selalu gagal: biasanya noise di kabel atau level tegangan tidak cocok (RS-422 vs RS-232 vs TTL). Coba kabel lebih pendek dan pastikan ground tersambung.

Talker ID bukan GP: normal. Perangkat modern mengirim $GNGGA (GNSS gabungan) atau $GLGSV. Parser di atas memakai f[0][2:] sehingga apapun talker-nya tetap dikenali.

Status RMC = V: receiver belum dapat fix (mis. di dalam ruangan). Bawa antena ke tempat terbuka dan tunggu beberapa menit.

Kesimpulan

NMEA 0183 terlihat kuno, tapi justru itu kekuatannya: teks biasa, mudah dibaca, mudah di-debug, dan didukung hampir semua perangkat marine. Dengan parser di atas kamu sudah bisa membaca posisi, kecepatan, dan status GPS dari perangkat apapun — fondasi untuk proyek lanjutan seperti logger pelayaran, dashboard Raspberry Pi di kapal, atau integrasi dengan OpenCPN.

Komentar

Postingan populer dari blog ini