Skip to the content
PCBKitNew board
4 layers40.6 × 40.6 mmRtk gps module, the printed circuit board in 3D

Cheap dual-band L1+L5 RTK GNSS module. LC29H rover, discrete 50 ohm front end, USB-C + castellated. Schematic generated from Python and verified by a 146-check gate.

Size
40.6 × 40.6 mm
Copper layers
4
Thickness
1.6 mm
Parts
67
Nets
54
Pads
215
Tracks, vias
8, 12
Pours
4
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
28 Sep 2026
Updated
6 Nov 2026

Overview

Rtk gps module is an open-source printed circuit board by Lucas-Poulos, from the Lucas-Poulos/rtk-gps-module repository on GitHub, published under the CERN-OHL-P-2.0 licence. It is a 4-layer board of 40.6 × 40.6 mm with 67 parts on 54 nets, routed with 8 tracks and 12 vias.

It is built around the LC29HDAMD, CH340N and AP2112K-3.3TRG1, with the CL21A106KAYNNNE, 0402CG101J500NT and 0402CG330J500NT among its other parts. Its parts include 24 resistors, 19 capacitors, 7 diodes, 4 connectors and 3 ICs. It belongs with the radio and wireless boards of this library.

Main components

12

README

README.md

rtk-gps-module

A cheap, solder-down RTK GNSS module that gets you centimetre-level position. Dual-band L1 + L5, castellated edges, and a USB-C port so it also works on its own with nothing but a cable.

Status: schematic complete and verified. PCB layout is the next phase.

text
    ┌──── u.FL ────┐
    │ active       │   50 Ω CPWG, 0.38 mm
    │ dual-band    ├──► ESD ─► bias tee ─► DC block ─► π ─► SAW ─┐
    │ antenna      │    0.25pF   68 nH      100 pF    0R   L1+L5 │
    └──────────────┘        ▲                                    ▼
                            │                            ┌───────────────┐
                    ANT_ON ─┴─ PMOS switch               │   LC29H (DA)  │
                                                         │  dual-band    │
    USB-C ─► ESD ─► BAT54C OR ─► AP2112K 3V3 ────────────┤  RTK rover    │
      │                ▲                                 │               │
      │             5V_IN (carrier)                      │  UART1  1PPS  │
      └─► CH340N ──────────────────────────── UART ──────┤               │
                                        1k/10k divider   └───────┬───────┘
                                                                 │
                              24 castellated pads, 1.27 mm ──────┘

What it does

Feed it RTCM3 corrections over the UART — from an NTRIP client on a phone, a Raspberry Pi or a PC — and it resolves carrier phase to 1–2 cm horizontal, versus the 2–3 m you get from ordinary GPS.

Corrections come from the host, so there is no radio on the board: nothing to license, nothing to certify, and one less thing to pay for.

ReceiverQuectel LC29H (DA), dual-band RTK rover
BandsL1 / E1 / B1 / G1 and L5 / E5a / B2a
ConstellationsGPS, GLONASS, Galileo, BeiDou, QZSS, SBAS
RTK accuracy~1–2 cm CEP, open sky
RTK fix rate1 Hz — the DA does not go faster, see below
Position rate, no RTKup to 10 Hz
Corrections inRTCM3 over UART1 — MSM4 or MSM7, plus 1005/1006
Timing out1PPS, rising-edge synchronised
Supply5 V from USB-C or 5 V from the carrier board
Logic3.3 V (plus a 1.8 V debug domain, see below)
InterfaceUSB-C (CH340N) and 24 castellated pads on 1.27 mm
Parts cost$27.10 per board at qty 1

The receiver is 88 % of the bill. Everything else together is $1.56. Nothing but the receiver is worth cost-optimising.

RTK fixes at 1 Hz, and only 1 Hz

Quectel's LC29H (BA,CA,DA,EA) DR&RTK Application Note is unambiguous:

LC29H (DA) only supports RTK (update rate: 1 Hz). LC29H (EA) only supports RTK (update rate: 1–10 Hz, 10 Hz by default).

The 10 Hz figure quoted for these modules is the ordinary position rate. With RTK engaged, the DA produces one fix per second. If you need faster, the only variant that does it is the EA, which costs roughly 25 % more than the DA and is a different board cost, not a firmware setting.

This also means the AA variant gives up nothing on rate. Its raw observations are capped at 1 Hz, which is exactly what the DA fixes at — so "the AA is slower" is not a real objection to moving the RTK engine onto the host.

Where the corrections come from

The board has no radio, so RTCM3 arrives over UART1 from whatever the host can reach. In the United States most states run a free CORS network.

In Massachusetts that is MaCORS, MassDOT's 22-station SpiderNet network covering all 14 counties, free after registration at macors.massdot.state.ma.us. It serves RTCM 3.1 and RTCM 3.2 MSM4.

That is directly compatible — no translation layer. The DA accepts:

Message
1005 / 1006Stationary RTK Reference Station ARP
1074 / 1077GPS MSM4 / MSM7
1084 / 1087GLONASS MSM4 / MSM7
1094 / 1097Galileo MSM4 / MSM7
1114 / 1117QZSS MSM4 / MSM7
1124 / 1127BeiDou MSM4 / MSM7

If the network offers a VRS mount point it synthesises a virtual base at your position, so the usual "stay within ~1 km of the base" rule stops applying — the effective baseline is short wherever you are inside the network. Outside network coverage that rule returns, and the answer is your own base: LC29HBS is the base-station variant and shares this footprint, so a second board off the same fab run becomes one.

Multipath will dominate your results before the board does

RTK resolves carrier phase, and carrier phase is ruined by reflections. A signal bounced off a glass facade arrives with corrupted phase, which costs you the fix — or worse, buys a confident but wrong one.

Test open-sky first and separate the two questions: does the board work and does it work where I need it. Debugging the former in an urban canyon wastes days.

Everything else is discrete

There is no way to make an RTK receiver from discrete components — carrier phase needs a correlator ASIC. So the receiver and its SAW filter are ICs and everything around them is built from single transistors and passives rather than bought as a block:

  • Antenna bias tee — a 68 nH choke, a 100 pF block, and a PMOS/NPN pair switched by ANT_ON, with a 10 Ω resistor limiting a shorted antenna to ~330 mA.
  • 5 V ORing — one BAT54C, anodes to USB and to the carrier's 5 V, cathode to the LDO. USB and carrier power can both be present and neither back-feeds the other.
  • Backup domain — a second BAT54C ORs 3V3 with an optional external cell on VBCKP_EXT, so the ephemeris cache survives and the module hot-starts in ~1 s instead of cold-starting in ~30 s.
  • RX level shift — a 1 k / 10 k divider, because RXD1 is specified VIHmax 3.08 V and a 3.3 V host would exceed it.
  • 1PPS indicator — one MMBT3904, because 1PPS is guaranteed only 2.1 V high and would drive an LED dimly while loading the edge.

The impedance work

Fully derived rather than asserted — see docs/impedance.md. Short version:

  • The antenna line is a conductor-backed CPWG, not microstrip. Solving the conformal-mapping model for JLCPCB's 4-layer JLC04161H-3313 stackup gives 0.38 mm at 0.2 mm gap → 50.19 Ω. Treating it as microstrip would say 0.41 mm and land it near 47 Ω.
  • The SAW's ports are 50 Ω ∥ 5.1 nH, not 50 Ω, so L302/L303 are part of the impedance, not optional.
  • The ESD diode is 0.25 pF. An ordinary ESD part at 10–50 pF would shunt the antenna signal away.
  • The number lives in tools/calc_impedance.py, and make check fails if the project's RF netclass drifts away from it.

Pinout

24 castellated pads on 1.27 mm — drops onto 0.1 in perfboard.

Left edge (J501)

PadNameNotes
1GND
25V_INORed with USB VBUS
33V3LDO output
4VBCKP_EXToptional backup cell / supercap
5GND
6TXD1receiver → host, NMEA / PQTM
7RXD1host → receiver, RTCM3 in
81PPSrising edge
9RESET_Nactive low, pulled up on-board
10WAKEUPneeds ≥ 3.0 V to wake
11VDD_EXT2.8 V out, 100 mA max
12GND

Right edge (J502)

PadNameNotes
1GND
2ANT_ONantenna switch control
3I2C_SDAvia DNP link
4I2C_SCLvia DNP link
5TXD21.8 V domain, via DNP link
6RXD21.8 V domain, via DNP link
7D_SEL11.8 V domain, via DNP link
8D_SEL21.8 V domain, via DNP link
9GND
10–11—spare
12GND

Pads 5–8 on the right edge are not 3.3 V tolerant. VIHmax is 2.1 V. Each reaches the edge only through an unfitted link, so a default board cannot present them to a 3.3 V host by accident.

D_SEL1 = D_SEL2 = 0 selects UART1 and is the on-chip default via 75 kΩ pulldowns, so the fitted board needs no strapping parts at all.

Repository layout

text
design/        THE PROJECT. Open it in KiCad, edit it, save it.
  lib/         the two symbols and three footprints stock KiCad lacks
tools/         helpers that READ design/ -- none of them write to it
  check.py             ERC + netlist + sourcing + impedance
  gen_bom.py           BOM, read from the schematic
  calc_impedance.py    the 50 Ω derivation
  fetch_datasheets.py  pulls the vendor PDFs (not committed)
  bootstrap/           the generators that built v1 -- NOT authoritative
Makefile       run `make` to list every target
.githooks/     optional pre-commit hook, ERC errors only
manufacturing/ BOM.md, BOM-dnp.md, bom_jlcpcb.csv
docs/          editing.md, impedance.md, schematic.pdf
datasheets/    README + fetch script; the PDFs are not ours to redistribute
analysis/      ERC report and netlist (gitignored, regenerated on demand)

design/ is a normal KiCad project. Edit it directly. Nothing regenerates it, and nothing in tools/ writes to it.

Working on it

bash
make open       # open in KiCad -- edit and save freely
make check      # ERC + netlist + sourcing + impedance, all read-only
make bom        # rebuild manufacturing/ after a parts change
make            # list every target

Read docs/editing.md before changing the RF path or anything on the LC29H — there are four traps on this board that KiCad will not warn you about (a 3.08 V limit on RXD1, a 1.8 V pin domain, two supply pins that are outputs, and three pins that must float).

make check reads design/ and never writes to it. It exports a fresh netlist and a fresh ERC report and asserts against those:

  • ERC — must be clean and the report must be newly written. A stale report from an earlier run reads exactly like a pass, and kicad-cli writes no report at all when the schematic fails to parse. Verified by injecting a deliberate fault and confirming ERC caught it on the right sub-sheet.
  • Netclass — the exported per-net class is read back, because KiCad accepts a netclass pattern that matches nothing without complaining and a 50 Ω line silently falls back to the default track width. (This caught a real bug: /regex/ patterns are accepted by the file format and match nothing — KiCad uses wildcards, and local nets carry their sheet path.)
  • Critical nets — the RF chain, the bias tee and the RXD1 divider are asserted pin by pin, so none of them gets rerouted by accident. Rewire one on purpose and it tells you exactly what changed.
  • LC29H pin rules — grounds grounded, the three RESERVED pins still floating, VDD_EXT never tied to 3V3.
  • Sourcing — every fitted part must carry a resolved Cxxxxx.
  • Impedance — the RF netclass width must still match what tools/calc_impedance.py derives, and still land within 5 % of 50 Ω.

Building one

The BOM is in manufacturing/BOM.md, with bom_jlcpcb.csv ready for JLCPCB assembly and BOM-dnp.md listing the unfitted options.

Prices and stock were read from LCSC on 2026-09-28 and frozen for traceability — re-check before ordering. LC29H stock in particular was thin (22 pcs). LC29HBS (C21385845) is the RTK base station variant and LC29HAA (C22403415) has no RTK engine; both share the footprint, so check you are buying the one you mean.

You also need an active dual-band L1+L5 antenna with NF < 1.5 dB, gain < 17 dB, and its SAW ahead of its LNA.

Caveats

  • Not built yet. The schematic is verified; no board has been fabricated, so nothing here is confirmed against hardware.
  • The LC29H (DA) pinout is contested by its own datasheet. Figure 4 and Table 6 disagree about pins 15–19. The V1.3 revision history settles it in Table 6's favour (the changes applied only to the EA variant), and the design follows Table 6 — but those four pins reach the edge only through unfitted links, so the board is correct either way.
  • Prices are a snapshot, not a quote.

Licence

Hardware under CERN-OHL-P v2; the scripts under the same terms. Permissive — do what you like, no reciprocity required.

Parts

67
QtyValueFootprintReferences
90RResistor_SMD:R_0402_1005MetricR206, R207, R208, R209, R210, R211, R301, R305, R401
9100nFCapacitor_SMD:C_0402_1005MetricC102, C104, C106, C202, C204, C205, C305, C401, C402
610kResistor_SMD:R_0402_1005MetricR201, R204, R212, R303, R304, R501
310uFCapacitor_SMD:C_0805_2012MetricC101, C103, C201
31kResistor_SMD:R_0402_1005MetricR103, R205, R502
3Fiducial_1mm_Mask2mmFiducial:Fiducial_1mm_Mask2mmFID1, FID2, FID3
2100pFCapacitor_SMD:C_0402_1005MetricC301, C304
233pFCapacitor_SMD:C_0402_1005MetricC107, C203
25.1kResistor_SMD:R_0402_1005MetricR101, R102
25.1nHInductor_SMD:L_0402_1005MetricL302, L303
2BAT54CPackage_TO_SOT_SMD:SOT-23D102, D104
2DNPCapacitor_SMD:C_0402_1005MetricC302, C303
2MMBT3904Package_TO_SOT_SMD:SOT-23Q302, Q501
1100kResistor_SMD:R_0402_1005MetricR202
110RResistor_SMD:R_0402_1005MetricR302
122RResistor_SMD:R_0402_1005MetricR213
14.7kResistor_SMD:R_0402_1005MetricR203
14.7uFCapacitor_SMD:C_0603_1608MetricC105
168nHInductor_SMD:L_0402_1005MetricL301
1AO3401APackage_TO_SOT_SMD:SOT-23Q301
1AP2112K-3.3Package_TO_SOT_SMD:SOT-23-5U101
1B8389rtk-gps-module:SAW_RF360_SMD1411-5P_1.4x1.1mmFL301
1CH340NPackage_SO:SOIC-8_3.9x4.9mm_P1.27mmU401
1GREEN 1PPSLED_SMD:LED_0603_1608MetricD501
1LC29HDAMDrtk-gps-module:Quectel_LC29H_LCC-24_12.2x16.0mmU201
1LEFT EDGErtk-gps-module:Castellated_1x12_P1.27mmJ501
1REDLED_SMD:LED_0603_1608MetricD105
1RF1256-000Diode_SMD:D_0603_1608MetricD301
1RIGHT EDGErtk-gps-module:Castellated_1x12_P1.27mmJ502
1SD05Diode_SMD:D_SOD-323D103
1USB-C 16PConnector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12J101
1USBLC6-2SC6Package_TO_SOT_SMD:SOT-23-6D101
1u.FLConnector_Coaxial:U.FL_Hirose_U.FL-R-SMT-1_VerticalJ301

Questions

How big is the Rtk gps module PCB?

It measures 40.6 × 40.6 mm and has 4 copper layers, 1.6 mm thick.

What parts does the Rtk gps module use?

67 parts, built around the LC29HDAMD, CH340N, AP2112K-3.3TRG1 and CL21A106KAYNNNE. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Rtk gps module KiCad files?

From the Lucas-Poulos/rtk-gps-module repository on GitHub, at the commit this page was made from: the board is design/rtk-gps-module.kicad_pcb and its schematic design/01_power.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Rtk gps module design in my own project?

Its repository publishes it under the CERN-OHL-P-2.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers78.4 × 90.4 mmIphoneFM panel, the printed circuit board in 3D

    IphoneFM panel

    louisflakes/IphoneFM

    KiCad project for IphoneFM Rev A. Built step by step from ../../design/rev-a/kicad-build-procedure.md; checked with ../../tools/kicadcheck.py.

    134 parts
  • 4 layers50 × 20 mmPicoarc, the printed circuit board in 3D

    Picoarc

    naorunaoru/picoarc

    Use your HDMI ARC capable soundbar with your computer

    72 parts1
  • 4 layers80 × 105.5 mmNetdaq, the printed circuit board in 3D

    Netdaq

    Gherkin/netdaq

    913 partsCERN-OHL-P-2.0
  • 6 layers133 × 102 mmIasis, the printed circuit board in 3D

    Iasis

    hydazz/iasis

    An optional Raspberry Pi Compute Module 5 carrier for Iasis. It plugs into the main board's HubPD population and carries Ethernet, NVMe storage, an accessory USB-C port and a service USB-C port.

    723 partsApache-2.0
  • 4 layers52 × 52 mmMoto gps rev a1, the printed circuit board in 3D

    Moto gps rev a1

    mx3353672833-debug/moto-gps-waveshare

    MOTO GPS · Waveshare ESP32-S3 1.75C 圆屏导航 + iPhone App | Author: Maler X | Noncommercial, attribution required | Experimental

    112 parts529
  • 4 layers50 × 79.5 mmGD32-Devboard, the printed circuit board in 3D

    GD32-Devboard

    ConnorRigby/GD32-Devboard

    Simple GD32F405 Development board with CAN, SD Card, Lora, BLE and GPS

    106 parts
  • 12 layers68 × 40 mmTeresina Rack, the printed circuit board in 3D

    Teresina Rack

    marcoallegretti/Teresina-Rack

    The goal is an open, self-fabricatable Daisy Patch SM-compatible Eurorack submodule: the same carrier interface and libDaisy application compatibility through a small Teresina firmware variant.

    214 parts