The Taming of the u-blox ZED-F9P

The Taming of the u-blox ZED-F9P

posted in: Uncategorized | 31

When the UPS guy drops off some new long-anticipated electronics component at your front door, you may be hit with two competing thoughts:

  1. First-date-level excitement about the capabilities of the new component and the possibilities it will open up for your projects
  2. Final-exam-level dread of the process of figuring out how to use the thing

#2 can be especially pronounced when you’re an early adopter and the internet hasn’t yet given birth to much documentation about your newly acquired component.

Since that fateful day in early 2018 when u-blox announced the ZED-F9P L1/L2/L5 GNSS receiver, I’ve logged an embarrassing count of visits to their website anticipating every new piece of information that they would publish about the little ZED.

Eventually u-blox announced they would call the official development board the C099-F9P. As an old-school believer in the technology maxim that you wait ’till the 3rd iteration of some new product before adopting, I had hoped that u-blox would quickly release a few updates to the dev kit so that I could feel like a wise old sage buying the more refined product.

Well, Digi-Key began selling the C099-F9P dev kit and I could only wait a month or so before caving in and buying two:


The familiar thin white rectangular box with the beautiful u-blox logo stirs long dormant Christmas morning feelings


Unboxing the C099-F9P High Precision GNSS RTK Development Kit


When you unbox your C099-F9P, here’s what you’ll find:

Historically, the component prices of RTK hardware have been astronomical — even the multi-frequency GNSS antenna (hidden in the nondescript brown box in the upper left) has been a thousand dollar USD component up ’till recently.


Hooking up the components yields this:

The ZED-F9P hooked up and ready for for action. Note the GNSS antenna is sitting on the circular silver magnetic ground-plane. The metal ground plane significantly increases antenna performance by reducing signal multipath issues. Nearly any metal ground plane (i.e. the roof of your car) will do the job — in general, the bigger the plane the better.


If you go on a late-night RTK GNSS wiki binge, you’ll likely have your brain numbed as you start to uncover the considerations involved in distilling the faint chirps from several dozen non-homogeneous satellites orbiting our planet 12,000 miles away into a centimeter accurate position in your front yard 20 times per second.

Let’s be clear: this blog post will not add to that scientific body of knowledge at all — instead, I’m assuming you’re a layman from some field other than RTK GNSS and you’ve stumbled across this ground-breaking technology as it’s effectively the only game in town for repeatable absolute centimeter-level outdoor positioning.

Those wishing to understand the technology underpinning RTK GNSS more deeply will find capable mentors in Tomoji Takasu[1], Clive Turvey[2], and Tim Everett[3].



Shortcuts to High Precision GNSS with the Revolutionary ZED-F9P (or “Early Adopter Tax Evasion”)


This blog post should serve as a crash-course in getting your ZED-F9P rolling. Success on my part will be measured in helping you avoid much of the early adopter tax that I had to dutifully pay through the usual fog of frustration and confusion that eventually gave way to the thrill of using a game changing component.

At this point I’m going to suggest something that (I think) you’ll eventually thank me for: Go ahead and buy two C099-F9P dev kits so that you can stand up your own Base Station. Trust me, at some point this will almost certainly feel like the best $250 USD investment you’ve ever made.

We’re going to set up one of the C099-F9Ps as the “Base Station” (to provide “Corrections”) and the other as the “Rover”. You have the option to use some local correction source if available, or to use a subscription correction service (i.e. the dev kit comes with a free trial subscription to a remote correction service called HxGN SmartNet — I’ve not used). Your mileage may vary, but I’ve never regretted setting up my own base station and relaying the RTCM corrections on a dedicated radio link.

Let’s start with the simplest possible use-case — hard-wiring the corrections output directly from the “Base Station” board to the “Rover” board (via a male-to-male breadboard wire). Once you have the setup running with a wired RTCM connection, you’re just a pair of 3DR radios away from a long-range wireless RTK setup.


RTK success with two C099-F9P boards wired to each-other

Here are the high level items we’ll accomplish to get our self-contained RTK system running:

  1. Connect to your ZED-F9P from within u-center
  2. Update the ZED-F9P receiver firmware on both C099-F9P boards to the latest from u-blox
  3. Set up one C099-F9P board as the Base Station, one C099-F9P board as Rover, and wire RTCM output from Base Station to Rover


1. Connect to your ZED-F9P from within u-center

On Windows 10 (no knowledge if this procedure works on other versions of Windows), before you plug in the C099-F9P, open up the Device Manager and expand the Ports item. Now plug in the C099-F9P and you should see 3 new ports that appear — one for the ODIN-W2 radio (COM7 in the example below), one for the ZED-F9P (COM6 below), and a USB Serial Device port that’s apparently some kind of all-in-one port where you don’t have to guess baud rates correctly. It’s much easier IMO to use this port (COM3 below).

On Windows 10, I seem to have the best success connecting to the “USB Serial Device” port that appears when you plug in the C099-F9P


From within u-center (I’m using u-center 19.04 which is the latest as of May 2019), click the down arrow next to the port icon in the upper left and you should see a port number corresponding to the USB Serial Device you noted above (COM3 for me). Select this port and we’re now connected to the dev board.



2. ZED-F9P firmware update

Updating to the latest firmware may not be required, but it’s quick and easy — so I’d say go for it.

Here’s a little video I made of updating the ZED-F9P firmware.


3. Set up one C099-F9P as the Base Station, the other C099-F9P as the Rover, and wire RTCM output from Base Station to Rover

You’ll need to know your Base Station antenna’s coordinates to complete this section. If you’re not familiar with how to get those coordinates, check out Addendum 1 below.

The configuration procedure we follow in the video below configures the receiver to output NMEA PVT (Position, Velocity, Time) to the UART2 (June 2019 update: output on UART2 has been spotty — so I’m just using UART1 for PVT output) UART1 Tx port at 5Hz (i.e. a new reading every 0.2 seconds) at 115k baud. It also configures the UART2 Rx port to receive RTCM corrections at 115k baud. These settings are convenient for the mower rover we blogged about last time. Note that you can set the output rate up to 20Hz, but you may need to bump up the baud to something higher than 115k (otherwise the line may get clogged up and the readings would be delayed). On the slow rover we’re using to cut the grass, 5Hz is plenty and the Pixhawk 4 we’re using communicates nicely at 115k baud.


If you’ve followed the steps above, then you can easily send RTCM correction data from the Base Station to the Rover by connecting the the Base Station UART1 Tx to the Rover UART2 Rx with a simple breadboard wire.

Caveat: the one-wire approach will work if you’re powering both boards with an electricity source with a common ground. If not, you can just connect the two boards’ GND sockets together (you’ll find multiple GND sockets on the dev board) with another breadboard wire.


It wasn’t obvious to me from the documentation which sockets on the C099 board map to UART1 and UART2 — perhaps all other humans were born with this knowledge. Here’s a little mapping diagram that will hopefully help future travelers:

Showing the u-center screens for the ports on the Base and Rover. Note the curious black lettering (like “J3 >1” and “J9 > 2”) — the official C099-F9P documentation adopts the names “J2”, “J3”, “J8” and “J9” for the terminal blocks — just showing what the terminal is called in the C099-F9P u-blox documentation.


You’ll note that we’ve taped off the ODIN radio antenna jack (remember that I don’t use the on-board ODIN radio). This just gives me one less thing to remember when connecting the GNSS antenna to the dev board.


ZED-F9P real world performance demonstration

Here’s a little video showing why this small RTK receiver is so significant:


Rolling our own long-range corrections link

If you’ve been using u-blox high precision gnss components since the NEO-M8P, then you may have previously used the superbly easy-to-use and capable C94-M8P development kit for that (L1-only) module[4]. The C94-M8P basically did everything right from an ease-of-use standpoint for a builder wishing to probe that gnss module’s functionality. For instance, the development kit was sold as a pair of modules (i.e. so that you weren’t tempted to skip setting up your own local base station), the radio was based on SiK telemetry achieving great range, and the procedure for setting up a base station / rover system was very simple and well documented[5].

I spent several unrecoverable hours trying to get two C099-F9Ps to communicate with each-other via the on-board ODIN-W260 radio. Efforts tried include downloading multiple versions of the s-center radio evaluation software, feverishly googling for any kind of documented success story setting up the link, setting jumpers, and flashing various firmwares and configuration settings to the dev board. I’m not sure if you’d describe my efforts as total failure or absolute failure, but I never saw any sign that I was close to actually making the communication link work.

Fortunately, long-range radios have become very cheap in recent years, so snag a pair off eBay, Amazon or SparkFun and you’ll have a long-range RTCM corrections link between the Base Station and Rover with minimal effort.


3DR radio configuration

Mission Planner has built-in functionality to configure the radios.

2 SiK radios connected to the Mac (running Windows via VM). Note that some SiK radios don’t have micro-usb ports — you connect them to your PC’s USB via a USB-to-Serial adapter.

Here’s a close-up of the relevant screen in Mission Planner, along with the settings of the radios that I’m using for the link:


Now that the radios are communicating, it’s time to remove the RTCM wire connecting the ZED-F9Ps to each-other and instead connect them wirelessly via the radios.

C099-F9P dev boards powering 3DR radios for wireless long-range RTCM corrections.


That’s all there is to it! Note the solid yellow light on the Rover indicates it has an RTK fix — I love seeing that light.

Sincerely yours,





  1. Tomoji really is the proverbial giant on whose shoulders many stand and see far. If you’re not familiar with him (i.e. you’re new to low-cost RTK GNSS), he wrote an ENTIRE OPEN-SOURCE RTK LIBRARY (humbly and simply called RTKLIB) that’s historically significant as it enabled the first forays of hobbyists with low-cost (i.e. < 100USD) u-blox GNSS receivers (such as the NEO-M8T) into the previously exclusive world of RTK. Tomoji actively keeps a predictably low-key blog of his research notes, which is approachable to non-Japanese audiences via the Google Translate extension in your fav browser.
  2. Clive possesses a savant-level command of several technical spheres. Fortunately for us, he decided years ago to begin ascending the RTK mountain — he has pointed many aspiring GNSS journeymen toward the correct path.
  3. Tim had two important realizations in early 2016: 1. the significance of RTKLIB (i.e. the world it opened up by processing raw data output from low-cost u-blox receivers) and 2. the difficulty that non-gnss-professionals were having approaching RTKLIB. His tremendous blog has revealed the ways of Tomoji to mortal man. Additionally he has become a trusted voice (through actual field use) critiquing the various RTK GNSS offerings appearing over the past few years.
  4. To be fair to this (first) version of the C099-F9P — the C94-M8P development kit went through a few releases before arriving at the final refined product.
  5. The M8P will always occupy a special place in my heart as it signaled to thousands of makers hoping for robust afforable RTK that u-blox was getting ready to play.

Addendum 1: Finding Latitude/Longitude/Elevation for your local Base Station Antenna

The absolute accuracy of your rover’s position is directly tied to the accuracy of the longitude/latitude/elevation that you provide to your base station as it’s antenna’s location. In order to find out the longitude/latitude/elevation of your base station antenna, you’ve got several options, including:

  1. Rough guess by using a site like this:
  2. Pipe in corrections from some RTCM correction source you have access to into your Rover C099-F9P (i.e. with your Rover C099-F9P hooked up to the base station antenna) and, assuming you get an RTK Fix, note the Lat / Long / Altitude in u-center.
  3. On the ZED-F9P that’s hooked up to the base station antenna, run the u-blox Survey In procedure (the u-blox C099-F9P GitHub folder has instructions for running Survey In, but I couldn’t ever get it to seem to work).
  4. Pay a professional surveyor to survey your base station antenna location.


If options 2 through 4 in the list above don’t make immediate sense, just grab the approximate longitude / latitude / elevation via the website (or any similar website) in #1, i.e.:


So, as an example, assuming that the map location above is zoomed in on your base station antenna, you would just pull the coordinates provided:

Latitude: 31.61680344280341

Longitude: -88.00395727135766

Elevation: 66m* (I’m not sure how accurate the website’s elevation is, but you will want to remember to add the height that your antenna is above ground to this number).


Follow Roby:

Latest posts from

31 Responses

  1. John Dolecki

    This is great. Im going to order my two units this week.
    Have to sell some robot parts to buy these.
    Its a never ending cycle.

  2. Clive Turvey

    If doing integration work consider the ArduSimple shield solutions. Doing some interesting experiments with those including double-stacking them to get real time orientation with dual antenna rover configurations. ie One resolving location, the second resolving a NED vector using moving-base mode.

    • Thanks Clive! ArduSimple is on a tear lately — I’m itching to pick up the new heading board once it’s out.

  3. John Dolecki

    So are you running two sets of radios? one for mission planner to the robot. and another set for the GPS corrections base to the rover?

    • Hey John that is right — that second pair of 3DR radios connects Pixhawk telemetry to Mission Planner.

      Usually, however, that radio connection to the robot is just a backup — I prefer to use the Raspberry Pi running mavproxy and sending the telemetry to my Mission Planner via UDP. So having the on-board Ubiquiti Access Point is nice in this situation.

      To be clear, here’s what that looks like: from the pictures on the previous blog post, you’ll see a USB-TTL-UART connector plugged in to Raspberry Pi’s USB. The Tx/Rx wires connect to the Pixhawk 4 Telem1 port.

      You run a command like this on the Raspberry Pi to forward the telemetry to your in-network Mission Planner: --master=/dev/ttyUSB0,921600 --out my-pc-name-or-IP:14500

      And then from Mission Planner on your PC, you just connect to UDP:14500 and you’ve got a lot faster connection (921k baud) than the 3DR radios will usually give you.

  4. Hey Roby,
    Excellent write-up. Really appreciate your blazing the trail on the ZED-F9P.
    Can I ask, how did you overlay the antenna’s path with the map of your property?

    Is this the map view in u-center? If so, did you purchase a google maps API key, or create a calibrated, static image?

    • Hi Conner,

      Thx for your kinds words! Hey that is all within u-center — I have a Google Maps API key and it was free (you do have to sign up for it though).


      • Hi Roby,
        Thanks for the info. I didn’t push too hard on through the Google API setup. I figured there were additional costs, but I’ll go back and play with it. That overlay is slick!

        For your future readers, I did succeed in getting the ODIN modules to talk to each other on the C099-F9P dev kit, and achieve a wireless RTK fix using only 2x dev kits.

        My dev kits (C099-F9P-2, purchased from Digikey) came setup for Mbed. I believe all US kits run the Mbed OS 3 application firmware from the factory. You’ll know if the kit is setup for Mbed if upon opening the port in s-center, all you see is “+++”. The ODIN-W2 modules can be setup to use the Connectivity Software / wifi using AT commands, which is what we want for RTK over wifi. After your #3 step above, I downloaded the latest version of UBlox s-center (4.8.0). You really have to carefully parse the UBlox documentation to figure out the setup. Refer to pg30 of the C099-F9P-AppBoard-ODIN-W2-CSW_UserGuide_(UBX-18055649-R04), section 7.2 ODIN-W2 Firmware Update.

        To get the Connectivity Software to run you have to first flash an updated bootloader to the ODIN module. (I was pulling my hair out at this point). But before you can flash anything, you have to restart the ODIN module into safe boot mode.
        – Hook up a jumper across the safe boot pins on the board (see pg 11, Figure 6: Switches and LEDs) and press the safe boot button to restart the board (or maybe its the normal reset button, can’t recall exactly).
        – Flashing requires you to download a separate program, stm32flash (, stm32flash v0.5) to a windows PC.
        – Download the bootloader (ODIN-W2-BOOT-v0.8.2.bin) and connectivity software (ODIN-W26X-SW-7.0.0-090.bin) files from the ODIN-W2 product page documentation tab ( – Look under the bold heading “Firmware Update” and download the “u-blox Connectivity Software 7.0.0 for ODIN-W2” zip file. It includes the bootloader and software file. Place stm32flash and the two files in the same folder for ease of access.
        – Connect one dev kit to your computer via the including usb cable. Following pg30 of the user guide, open Power Shell / Command Prompt in Windows, navigate to your chosen folder, and run stm32flash.
        – To flash the new bootloader, type (replacing port number with the ODIN-W2 dedicated port number):
        stm32flash.exe -b 115200 -w ODIN-W2-BOOT-v0.8.2.bin -S 0x8000000 COM
        – To flash the new firmware, type (replacing port number with the ODIN-W2 dedicated port number):
        stm32flash.exe -b 115200 -w ODIN-W26X-SW-7.0.0-090.bin -S 0x8010000 COM
        – If it gives you errors, make sure your Baud rate, port number, and file name are exactly correct.
        – At this point, remove the safe boot jumper and restart the board in normal mode.
        – Open s-center (ODIN will use 115200 baud rate at this point). Open port.
        – Turn off flow control by pressing the button labeled “EVK-ODIN-W2 via ST-LINK” (I believe this is required to see the AT commands, could be wrong)
        – Execute these 3 AT commands:
        • AT+UMRS=460800,2,8,1,1,0
        • AT&W
        • AT+CPWROFF
        – Close port and reopen using 460800 baud rate.
        – Hit the AT mode button and you should start to see AT commands per pg 31.
        – Repeat the above steps for the 2nd dev kit.
        – Now that you have the ODIN running the connectivity software, you can download the rover/base config files (located on the github) to the ODIN module

        The last thing you have to do is hook up a jumper across the “3OE” pins, per pg 17, to connect the ODIN-W2 and ZED-F9P serial ports, and allow RTK corrections communication between rover and base.

        Hope this helps someone else out there struggling!


        • Conner — this is wonderful — thanks for taking the time to log the success path for getting the ODIN-W2 radio communication working.

          I’m interested to learn the range of those radios.


  5. Martin Mercurio

    Hi! I would like to ask about the patch antenna used. Is there any documentation or idea where the phase center of L1 and L2 signals? Additionally, are there any options or accessories that I can put the patch antenna to the tripod (usually used in surveying or RTK) so it will be placed vertically above the point/station? thanks!

    • Hi Martin,

      Here is a screengrab from the official ANN-MB documentation detailing the antenna phase centers:

      ANN-MB L1/L2 Phase Center

      Re: Mounting the antenna on a tripod — curiously, note that the ANN-MB antenna pictures on the official u-blox page have a through-hole flanking either side of the antenna, but the ANN-MB antenna I received doesn’t have that.

      Hope that helps,


    • Martin Mercurio

      Thanks for the response. Another question is, can I use a smartphone instead of a laptop to control the device? If any, is there any application that could control the device? Thanks Roby


      • Hi Martin — Can you give a little more color on what you’re trying to achieve?

      • The C099 Dev Board contains the ZED-F9P and an ODIN-W2 module (Wifi+BT). You can pair an Android smartphone to the using bluetooth and stream RTCM data to it using an app like NTRIP Client (by Lefebure). You will need to “point” the app to your RTCM correction server with your login details.

        But having a second C099 board (base station) creating RTCM correction data(as in this post) opens up many more possibilities and puts you in control.

    • Martin Mercurio

      Hi Roby, I tried logging data using DF receiver (zed-f9p) and then recorded its log data using ucenter. However, when I tried to plot the .ubx file using RTKPLOT, it says that “no solution”. As I tried to convert the .ubx file to RINEX format, nothing happens. Is there missing points or configurations I did before recording? Thanks
      (you can also email me)

  6. Jason lee

    Good to see your rtk tutorial.
    Would you let me know if this is possible.
    As your tutorial, with two C099-F9P board, getting cm level accuracy rtk
    signal and send it to smartphone map app via bluetooth or usb connecting.
    Because I want to record the gps track with smartphone app when I’m doing outdoor activity.
    Have a good day. 🙂

  7. Hi Roby,

    Great tutorial! I just got my hands on a SimpleRTKB + SimpleRTKBLite with hopes of putting them into a moving-base configuration (total rookie here). Have you come across any resources on how that may be accomplished? Further how might I send position + heading information obtained to an arduino board?

    Thanks for the help!
    Jason M

    • Hi Jason,

      Thanks for stopping by — I haven’t used the ZED-F9P for heading — I’ll often still use an old (and discontinued) HMC5883 here at the shop. I did see that u-blox dropped a new pdf last week regarding using the ZED in moving-base — here’s a link to the info page (scroll down to Application Note –> ZED-F9P moving base applications) where you can download it if you haven’t see this yet. It’s pretty standard to use I²C for compass communication — but depending on your needs you may choose something else.

      Hope to hear you have much success with the SimpleRTKB board!


  8. Hi Roby,
    Thanks for sharing, this has been very helpful! I am trying to do a similar setup. I have been searching all over trying to gather all the info for this on the internet. I have 2 of the Ardusimple SimpleRTK2B with XBee LR radios for correction. My Pixhawk 4 and other goodies have just shipped! I would like to collaborate more on this. For now I’ll just try to catch up.
    I noticed you are sending NMEA to Pixhawk. The sparkfun website says the resolution for NMEA string does not fully utilize the precision these guys are capable of. It says the 5th digit is about 1.5cm. Did you keep this setting? Can Pixhawk 4 take the higher resolution UBX strings or can you increase the resolution of the NMEA strings?

    • Hi Mike,

      For the Pixhawk 4, I’ve only run ArduPilot accepting NMEA and its works fine (you’re not going to want that baud rate any lower than 115k though — maybe higher if you’re going over 5Hz PVT with the ZED). By now ArduPilot may have ZED-F9P UBX working on the u-blox driver, but since NMEA works fine I just haven’t checked. Also, that 1.5 cm figure you saw for NMEA precision sounds about right. I remember a few years back there may have been a little funniness within the ArduPilot code about cm-level waypoints, but for a good while now it’s seemed quite solid to me. Now if you’re wanting to get down to millimeter accuracy, you’re playing a game with which I’m not familiar.

      Look forward to hearing about your build!


  9. Morten Westeraa

    Hi Roby
    Thank you so much for your tutorial. I’m so glad I found your blog. I live in the northern part of Denmark, where I try to get knowledge about the gnss/rtk technology. Im running a similar setup with two Sparkfun RTK2 kits. I was able to reproduce your setup and read the rtcm signal from the base, however I had problems reproducing it later in the day, when I tried to use I2C. As for now it works when I send the signal from base Uart1-tx to rover UART2-rx (460800 Baud). But If I use base UART2-tx to rover UART2-rx, the signal disaperes after approx. 1 minute. Somewhere in your videos you mentioned that you had done some tweaking on these matters, is it possible that you could share your experience?

    As a side note I should mention that my antennas at the moment are poorly located very close to my house (Should have bought longer SMA cables😊) , but I dont see why that should produce any difference between the UART ports.

    Thank you in advance and have a nice day.

    Morten Westeraa

    • Hi Morten!

      Warm greetings to you across the pond in northern Denmark.

      Glad to see you figured out the issue shortly after posting this (i.e. starting with the base config files from GitHub). For some reason, on the rovers I’ve ended up going with sending in RTCM on UART2 Rx and outputting PVT on UART1 Tx — I was having trouble, for instance, getting PVT to output on UART2 Tx but that may have been something I was doing wrong — in other words, I stumbled into that UART1 PVT Tx / UART 2 RTCM Rx configuration and it worked so we just stuck with it :).

      If you’re building a rover, hope to see some pictures of it running around your beautiful country before long!

      Take care,


  10. Morten Westeraa

    I forgot to mention that I use the hardwire connection as for now, sorry😊

  11. Morten Westeraa

    I found out why it would not accept correction signals from base UART2 tx. They were not set up in the base config file from Github. After changing this file I now send RTCM from base UART2 tx to rover UART2 rx, at 460800. The update rate is 10 Hz.

  12. Hi, I can successfully configure a moving base setup at 5Hz but if I also try to send RTCM corrections to the reference module from the local CORS site in order to get both an RTK position as well as heading, then the corrections from the reference receiver to the attitude receiver periodically stop causing frequent ‘zero heading’ output from the heading field of the RELPOSNED message from the attitude receiver (along with a corresponding accuracy of 180 deg). Corrections between the reference receiver and the attitude receiver are on uart2 at 460800 baud. Corrections from the CORS station and the reference station are on uart1 at 115200 baud. All unused messages are disabled on all ports. Is this setup supported by the F9P? I have made changes to Ardurover to accommodate this setup and can successfully use the heading in EKF3 and obtain accurate headings without using any compass but the frequent dropouts causes issues…

    • Hi Jimovonz,

      Apologies but I haven’t used moving-base on the ZED-F9P.

      I’m hoping that a near-future iteration of the ZED will natively support 2+ antennas on 1 board (thus enabling absolute pose data) — considering that u-blox has already superseded the F9P with the ZED-F9K (with IMU onboard to fill in temporary GPS “gaps”), it seems reasonable to conclude that u-blox is planning on quickly pushing through the feature-enhancement roadmap that the big expensive old-school GNSS companies did with their multi-thousand $$$ USD receivers.

      If you do figure out the quirk you’re seeing, I hope you’ll consider reporting your findings.

      Take care,


Leave a Reply