Dual-frequency PPK solutions with RTKLIB and the u-blox F9P

With previous generations of u-blox receivers there has been a lower priced option available without an internal RTK engine, such as the popular M8T in the generation 8 modules. This does not appear to be the case with the new dual-frequency generation 9 modules, as the F9T, without internal RTK solution, is currently priced higher than the F9P with internal solution.

As the u-blox internal RTK solution in the F9P appears to be very robust, there is probably no good reason to ever use RTKLIB for real-time solutions with the F9P. However, it often still makes sense to use RTKLIB to post-process raw data previously collected by the F9P since the F9P is not capable of post-processing solutions.

Post-processed (PPK) solutions have several advantages over real-time solutions. The rover hardware is simpler, less expensive, lighter, and lower power since post-processing does not require a real-time data link between base and rover. Post-processed solutions also tend to be more robust than real-time solutions, both because they are not subject to data dropouts in the base data link and because they allow for solution techniques that take advantage of both past and future observations, not just past observations. When the solution is not required in real-time, it often makes more sense to collect the data first and then process it later.

Collecting data and processing RTK solutions for the dual-frquency F9P with RTKLIB is not very different for doing this for the single-frequency u-blox M8T, and if you are already familiar with doing that, you will probably not have much trouble adapting to the F9P. However, since it’s been a long time since I did a post on this subject, I thought it would be worth going over again with some updated tips for the new receiver.

Step 1: Configuring the receiver:

To process an RTKLIB solution, we will need raw observation messages from both rover and base receivers and navigation data messages from one of the receivers. The receivers do not output these messages by default so we will need to configure them to do this. With the u-blox M8T it was possible to do this directly with RTKLIB using a command file but this is not an option with the F9P as RTKLIB does not currently support the new F9P configuration messages.

Instead we will download the u-blox u-center app and use this to configure the receivers, then save the results to the on-board flash. There are detailed instructions on how to do this in the F9P documentation available on the u-blox website but here’s a quick summary of the process.

  1. Plug the receiver into a Windows PC using a USB cable if the board supports USB or with an FTDI serial/USB converter if the receiver only has a UART port.
  2. Start the “u-center” app and connect to the receiver with the “Connection” command on the “Receiver” tab. If it is a USB connection, baud rate won’t matter, but if it is a UART->USB connection through FTDI, then you will have to set the correct baud rate from the “Receiver” tab. If all is well, you should see the green connection indicator flashing at the bottom of the screen
  3. From the “View” tab, open the “Messages”, Configure”, “Gen 9 Configure”, and “Packet Console” windows
  4. If using the UART port, click on “PRT (Ports)” from the “Configure” window, set the Target to “1-UART1” and “Baudrate” to the desired baud rate, and click on “Send”. I typically set this to 115200 baud. You will then need to change the baud rate in u-center to the new baud rate. If you are using the USB port directly, you can skip this step.
  5. From the “Configure” window, click on “RATE”, and set “Measurement Period” to the desired time between observation samples, then click on “Send”. I typically set this to 200 ms which gives a 5 Hz sample rate.
  6. From the “Gen 9 Configure” window, select “GNSS Configuration”, enable the desired constellations and signals, select “RAM” and “Flash” under “Layer Selection”, then click on “Send Configuration”. The F9P supports GPS L1C/A and L2C, Glonass L1 and L2, Galileo E1 and E5b, BediDou B1 and B2, and QZSS L1C/A.
  7. From the “Messages” window, right click on “NMEA” and then click on “Disable Child Messages” to disable all the NMEA messages. None of these are needed for an RTK solution but if you want any of the messages for other reasons you can then individually enable the ones you need.
  8. From the “Messages” window, double click on “UBX” then “RXM”. Right click and enable “RAWX” to enable raw observation messages and “SFRBX” to enable navigation messages. Alternatively, you can enable the RTCM3 messages from the “Gen 9 Configure” window. In this case you will want to enable the 1077,1087,1097,and 1127 messages. I have occasionally had trouble enabling the RTCM3 messages on the F9P and have had to use the “Revert to default configuration” option under the “CFG” command first to get this working.
  9. If an antenna is connected to the receiver and is not completely blocked, verify that you see RAWX and SFRBX messages appear in the “Packet” window.
  10. From the “Configure” window, select “CFG”, then “Save current configuration” then “Send” to save these settings to the flash on-board the F9P module.
  11. Repeat this procedure for the base receiver except set the “Measurement Period” under “RATE” to “1000 ms” for a 1 Hz sample rate. You will only need one set of navigation data so you can choose not to enable the SFRBX messages on the base. I tend to leave them enabled just because it makes plotting slightly easier later if each set of observations has its own navigation data.

If you have any trouble with the above summary, you might find this YouTube video from Robo Roby useful. It is intended for setting up the F9P for real-time solutions, not post-processing, but there is a lot of overlap between the two.

In the descriptions below STRSVR, RTKCONV, RTKPLOT, and RTKPOST are all RTKLIB GUI apps. They can be opened individually or you can start by opening RTKLAUNCH and run the individual apps from there. I do not believe the official 2.4.2 or 2.4.3 versions of RTKLIB fully support the F9P receiver yet so I would recommend using the demo5 version of RTKLIB available here.

RTKLAUNCH used to open the different RTKLIB apps

Step 2: Collecting the data:

  1. For this exercise I will connect both base and rover directly to a Windows PC through the USB port. You can connect both receivers to one PC or each to a separate PC.
  2. Launch two instances of STRSVR, one for each receiver
  3. Set the input stream to “Serial”, click on the input “Opt” button and set the port and baud rate. Set the output stream to file and click on the output “Opt” to set the file name. Click on the “?” to get a list of keyword replacements for the file name. I like to add “_%h%M” to the end of the file name which will append the hour and minute of the data to the file name. If you are collecting long data sets you might want to set the “Swap Intv” to break up the data into manageable file sizes. Note that you will need to use the keywords in this case to avoid overwriting the same file repeatedly. Give the file name a “.ubx” extension to let RTKLIB know that it is u-blox binary data.
  4. Click “Start” to start collecting data.
STRSVR used to collect the raw data

Step 3: Convert the observation data to rinex format:

  1. Start the RTKCONV app
  2. Click on the “…” button to the right of the “RTCM, RCV RAW or RINEX OBS” field and select the observation file created in the previous step.
  3. If the file extension is not “.ubx” set the “Format” to “u-blox”, otherwise leave as “Auto”
  4. Click on the “Options” button and select “L1”, “L2/E5b”, and all GNSS constellations collected (usually “GPS”,”GLO”,”GAL”, and possibly “BDS” (Bediou) depending on your location. Then close the options menu.
  5. Click on “Convert” to convert from binary to rinex format.
RTKCONV used to convert the raw data from binary format to rinex text format

Step 4: Review the observation data:

  1. Before processing the solution, it is a good idea to look at the data first and make sure it is complete, of reasonable quality, and at the right sample rate.
  2. From the RTKCONV main window, click on “Plot” to plot the observations you just converted.
  3. Verify there are observations from all constellations. Green indicates dual frequency measurements, yellow is single frequency. The GPS observations will be a mix of single and dual frequency since only about half of the satellites currently support L2C used by the F9P, but the other constellations should be nearly all dual frequency.
  4. Red ticks indicate cycle slips. Too many of these will make it difficult to get a decent solution. Gaps in the data usually indicate the receiver lost lock and these are not good unless they are in the low elevation satellites.
  5. If all the satellites are in gray, this usually indicates you are missing the navigation data. The previous step should have generated a “.nav” file as well as a “.obs” file. If just a few satellites are in gray, this normally indicates that they are below the elevation threshold which can be adjusted in the options menu selected in the top right corner with the star-like icon.
  6. Check both rover and base observations.
  7. In some cases you may only have one set of navigation data and so not have a matching “.nav” file for one of your observation files. In that case you can manually specify the navigation data with the “Open Nav Data…” option in the “File” tab.
Plot of raw observations

Step 5: Generate the position solution

  1. Open RTKPOST
  2. From the “…” buttons on the right hand side of the GUI, select the rover observation file, the base observation file, and the navigation file as shown in the example below.
  3. Click on the “Options” button and then the “Load” button. Select the “demo5_m8t_5hz.conf” file from the same folder as the demo5 RTKLIB executables, and then click on “Open”
  4. From the “Setting1” tab in the “Options” menu, enable “Galileo” and if applicable “Bediou”. “GPS” and “GLO” should already be enabled.
  5. From the “Setting2” tab in the “Options” menu, set “Integer Ambiguity Res (GLO)” to “On”. We are able to use the “On” setting in this case because the receivers are identical and so the Glonass hardware biases cancel. If you are not using an F9P receiver for base, then leave this field set to “Fix-and-Hold” which will automatically calibrate out the biases.
  6. From the “Setting1” tab in the “Options” menu, change the “Frequencies” from “L1” to “L1+L2”. This is the only change you should need to make to switch from processing single-frequency data to dual-frequency data for the F9P. The Galileo second frequency for the F9P is actually E5b not L2 but to simplify and improve the processing speed, I have modified the demo5 code to include “E5b” processing as Galileo’s second frequency. This won’t be the case for the 2.4.2 or 2.4.3 code. I don’t believe it’s currently possible to include the E5b data with these versions of RTKLIB but if I’m wrong please let me know
  7. Click on “OK” to close the Options menu.
  8. Click on “Execute” to run the solution. The bar at the bottom of the GUI will show the solution status as it runs and will report any errors. You should see a mix of Q=1 and Q=2 as the solution runs. If you see only Q=0, something is wrong. In this case, open the “Options” window, select the “Output” tab and set “Output Debug Trace” to “Level3”, exit the Options menu, and rerun the solution. Then open the “.trace” file in the solution folder for additional information on what went wrong.
  9. Click on “Plot” to plot the solution with RTKPLOT
RTKPOST used to generate a PPK solution
Plot RTKPOST generated PPK solution

This was just meant to be a quick summary of the process. For more details please see the references below.

References:

  1. u-center User Guide
  2. u-blox F9P Interface Description
  3. RTKLIB manual
  4. Updated guide to the RTKLIB configuration file

Real-time solutions with RTKLIB and NTRIP using a cell phone as data link

As I mentioned in an earlier post, I’ve recently acquired access to some low cost dual frequency receivers, specifically a Tersus Precis BX306 and a pair of Swift Piksi Multis.  I have been playing with them over the past few weeks and plan to share my experiences with them over a series of posts.

Both receivers provide internal RTK solutions as well as raw measurements that can be processed with RTKLIB.  I’m interested in how the RTKLIB solutions compare to the internal solutions as well as how both of these compare to solutions derived from single frequency data collected simultaneously with the dual frequency data.

The first issue I ran into with this experiment, however, is that both receivers will only provide an RTK solution for real-time data, neither have the capability to post-process previously collected data.  This meant that I needed a way to provide a real-time stream of dual frequency base station data to the receivers.  I wanted to be able to  do this while driving a car around the local area so I needed more range than a low cost set of radios would give.

Fortunately, I have fairly good cell phone coverage in this area so I was able to rely on my cell phone for the data link.  In this post I will explain how I did that, both for an external CORS reference station and for my own base station.  In both cases I used  NTRIP server/caster/clients to do this.  NTRIP is a protocol for streaming of DGPS or RTK correction data via the internet using TCP/IP.  The NTRIP server sends out the data to an NTRIP caster and the NTRIP client receives it. For more details, there is a good description here.

Using this setup I was able to run real-time solutions with RTKLIB as well as with the intenal RTK engines in the Swift and Tersus receivers.  Here’s a diagram from the RTKLIB manual showing the setup I used for running a real-time RTKLIB solution using RTKNAVI.  When I ran a Swift or Tersus solution, the configuration was similar, but the NTRIP caster streamed the base station data to STRSVR instead of RTKNAVI, and STRSVR then streamed it to the receiver where it was combined with the raw receiver observations to create an internal RTK solution.  Also missing in this diagram is the cell phone which should be in between the internet and the rover PC.

ntrip.rtklib

The amount of free base station reference data that is available online on a real-time basis is a fair bit more limited that what is available after the fact for post-processing.  Fortunately I was able to find a CORS reference station about 17 km away that is available real-time through the UNAVCO NTRIP caster.  The service is free if the data is used for educational purposes and appropriately attributed.   Most of their stations are on the west coast of the U.S. but they do have some scattered across the rest of the country as you can see in this map from their site.  There are other networks available in other parts of the world that can be found by searching online.

unavco_map

To access the UNAVCO data I had to request access through email but the process was very simple and within a couple hours of my request I was all setup with an account and password.

Once I had my account set up, I used RTKLIB on my laptop computer to collect the data from the internet and stream it to the rover receiver over a serial port.  If I were doing this experiment within range of a wireless router then I could leave the computer connected to the wireless.  In this case though, I wanted to roam outside the range of my home wireless.  To do this, I enabled a hot spot on my cell phone and logged into that with my computer.

I was able to access the raw observation data stream from the UNAVCO NTRIP caster directly using the NTRIP client option in RTKLIB.  If I had wanted to generate a real-time RTKLIB solution, I would have configured the input streams of RTKNAVI but in this case I want to stream the raw data directly to the receiver so it can use the observation data for it’s internal solution.  I did this using the STRSVR app in RTKLIB.  I specifed the “NTRIP Client” option as input type and then entered the information from my UNAVCO account into the “Ntrip Client Options” as shown below.

ntrip_client

In this case I wanted the data from station P041 in RTCM3 format so I had to specify the Mountpoint as “P041_RTCM3”.  For other networks, the mountpoint details may be a little different.  Most NTRIP casters use Port 2101, and that was the case for this one.  For the STRSVR output type, I specified “Serial” and then configured the serial port options for whichever rover receiver I was using.  Before doing the configuration, I had connected the receiver to the laptop using a USB cable.

I then had to configure the receiver to tell it to get its base station data from the COM port and specify that it is in RTCM3 format.  The details for doing this on the two receivers are a little different but fairly straightforward in both cases.  You may also need to specify the exact base station location manually or the receiver may be able to get it from the data stream depending on the receiver and NTRIP stream details.

And that’s it.  With this configuration, either receiver was able to fairly quickly lock to a fixed RTK solution and continue to receive base data as long as I stayed in range of cell reception.  Any lag in the base station observations appeared to be less than a second.

That worked great for using an existing external reference as base station.  However, I also wanted to run another real-time experiment where I used one Swift receiver as base and the other as rover.   To do this, I needed to set up an NTRIP server to stream the data to  a caster on the internet as well as an NTRIP client to receive it.

I started by connecting the second Swift receiver to an old laptop with a USB cable and then downloading RTKLIB, the Swift console app,  and the right USB drivers.  The base station antenna is on top of my roof and the laptop is in the house so I was able to connect the laptop to the internet using my home wireless.

For the NTRIP caster, I found it convenient to use RTK2GO which is a community caster available for anyone to use at no cost.  To send the data to the caster, I used the “NTRIP Server” as the STRSVR output type and configured it as shown below.

strsvr_server

Again, the port is 2101.  You can choose any name for the mountpoint.  If that name is already in use, then rtk2go will assign a suffix to it, so it is best to choose a name that is unlikely to already be in use.  The password at the current time is BETATEST but that may change from time to time so it’s worth verifying it is still correct.

For the STRSVR input, I selected “Serial” and specified the correct COM port for the base station receiver.  In this case the raw observations are in Swift binary format which RTKLIB does not support so it sends them unaltered.  If they were in a format that RTKLIB did support, then they could be converted to RTCM3 to reduce bandwidth and make them more easily usable by someone else not using a Swift receiver as rover.  You can specify the conversion to RTCM3 using the “Conv” menu on the STRSVR output.

Start STRSVR and your base station observations are now accessible to anyone in the world through RTK2GO.com!

On the rover side, the NTRIP client is set up as I previously described using STRSVR except you want to use the same caster/mountpint/password as you just did on the base station.  In this case the user-id is left blank.  Again, set the STRSVR output to “Serial” to send it to the receiver.   Then set up the receiver to get it’s base station data from the serial port and, in this case, specify that it is in the Swift Binary Protocol (sbp).  Start the receiver and it should fairly quickly get a fix.  If you are seeing baseline data but not a solution, then most likely you have not specified the base station location to the rover.

I was now able to drive around almost anywhere and get continuous real-time RTK solutions using either my own base station or the CORS reference station as base.  In the next post I will discuss some of the data I collected and analyzed.

 

 

 

 

A fix for the RTCM time tag issue

In my last post I described a problem with a loss of some of the raw measurement information caused by the lack of resolution in the time tags in the RTCM format.  Since the RTCM format is typically used to reduce bandwidth requirements in real-time applications, it is causing real-time solutions to fail when post-processing the same raw data without the translation to RTCM gives good results.  In this post I will describe a fix for this problem.

First of all I want to thank Felipe Nievinski, Igor Vereninov from Emlid, and Anthony Woolridge for their comments to the last post that pointed me to the solution.  They make this a collaborative effort between the U.S., Brazil, Russia, and the U.K!  It still amazes me how enabling the internet can be!

I’ll start by showing again this example of a RINEX output from an M8T receiver with the official raw measurement output (RXM_RAWX) and the debug raw measurement output (TRK_MEAS) enabled simultaneously.  I think  this provides a good insight to what is going on.  The TRK_MEAS  message is the top 5 lines and the RXM_RAWX message is the bottom 5 lines for a single epoch.  The first line in each message is the time stamp and the following lines are the measurements for each satellite.  In the satellite measurements, the second column contains the pseduorange value.

trkmeas1

The time stamp specifies the receiver time of the received signals and the sixth column is the number of seconds.  For the TRK_MEAS message these values are always aligned to round numbers based on alignment to the sample rate.  For example in this case the measurement rate was 5 Hz and all the time stamps occur on multiples of 0.2.  This is because they are based on the raw receiver clock without any corrections.

The time stamps from the RXM_RAWX messages however often differ from the round numbers by small arbitrary amounts.  This is because the receiver has estimated the error in its own clock and adjusted the measurements to remove this error.  In this case the estimate of clock error is 0.001 seconds and so the time stamp is adjusted by this value (18.8000000 to 18.7990000).

To keep the time stamps consistent with the other parts of the measurement, the clock error also needs to be removed from the psuedorange and carrier phase values since they are based on the difference in time between satellite transmission and receiver reception and will include any errors in the receiver clock.  We see from the above observations that the pseudorange measurement for satellite G24 has been adjusted from 22675327.198 to 22375547.970, a difference of 299779.228 meters.   The speed of light is 299792458 meters per second so the clock error of 0.001 seconds is equivalent to 299792.458 meters,  a value very close to the amount that the pseudorange was adjusted by.

A similar adjustment needs to be made to the carrier phase measurement as well but it is not as easy to see in this example because the carrier phase measurements are relative rather than absolute and the two messages in this case use different references.  The carrier phase measurements are in cycles, not meters, so the frequency of the carrier phase needs to be included in the translation from clock error to carrier phase cycles but is otherwise the same as the pseudorange adjustment.  In equation form, the adjustments are:

P = P -toff*c
L =L – toff*freq

where P=pseudorange, L=carrier phase, c= speed of light, and freq=carrier frequency

So, basically, the receiver is trying to help us out by removing its best estimate of the clock error from the measurements.  This is unnecessary since RTKLIB is quite good at estimating this clock error on its own, but by itself this adjustment does not cause a problem.

It is when the adjusted measurement is translated to RTCM that we get in trouble.  The resolution of the time stamps in the RTCM format is 0.001 seconds.  In this particular example it would not be an issue because the error is exactly 0.001 seconds or one count of the RTCM format.  Most of the time, however, this error is not an exact multiple of 1 millisec.

For example, here is a time stamp for the data set described in the previous posts.

> 2017  1 17 20 31 48.9995584  0  9

And here is the same time stamp after being translated to RTCM and then to RINEX

> 2017  1 17 20 31 49.0000000  0  9

As you can see, the clock adjustment was less than half a millisec so was completely lost in the roundoff to the RTCM format.  However, the adjustments the receiver made to the pseudorange and carrier phase are still present in those measurements.  We now have a problem because the clock correction is in part of the measurement and not the other pieces.  RTKLIB can not correct for this lack of consistency within the measurement.

So, how do we avoid this problem?  Fortunately, RTKLIB has an option to adjust the time stamps to round values using the same equations described above to adjust time stamp, pseudorange, and carrier phase to maintain consistency within the measurement.   I imagine it was put in specifically to solve this problem. We can invoke this option by adding “-TADJ=0.001” in the “Options” box in the “Conversion Options” menu in STRSVR or using the “-opt” option in the command line with STR2STR.  Note that this option needs to be set in the conversion from raw binary format to RTCM format, not the conversion from RTCM to RINEX.  It is possible to set this option when converting from RTCM to RINEX but this won’t help because the damage has already been done in the earlier conversion.

Unfortunately, there is a bug in the implementation of this option in RTKLIB, at least for the u-blox receivers, so by itself, this is not enough.  The problem is that invalid carrier phase measurements are flagged in RTKLIB by setting the carrier phase value to zero.  The time stamp adjustment feature adjusts these zero values slightly so they are no longer recognized as invalid.  They end up getting included in the output as valid measurements and corrupt the solution.

Fortunately, the fix for this bug is very simple.  Here is the code in the decode_rxmrawx() function in ublox.c that makes the adjustment:

/* offset by time tag adjustment */
if (toff!=0.0) {
fcn=(int)U1(p+23)-7;
freq=sys==SYS_CMP?FREQ1_CMP:
(sys==SYS_GLO?FREQ1_GLO+DFRQ1_GLO*fcn:FREQ1);
raw->obs.data[n].P[0]-=toff*CLIGHT;
raw->obs.data[n].L[0]-=toff*freq;
}

If we add a check to the first line of code to skip the adjustment if the carrier phase is zero, then all is fine.

if (toff!=0.0&&cp1!=0) {

Below is the original solution after RTCM conversion on the left and with time tag adjustment and the bug fix on the right.  If you compare the solution on the right to the solution with no  RTCM correction in the previous post you will see they are nearly identical.

timetag

I am still wary of using RTCM because of its other limitations described in the last  post, particularly the loss of the half cycle invalid flag and the doppler information, but I believe this fix eliminates the most serious issue that comes from using RTCM.

I will release a new version of the demo5 code with this fix sometime in the next few days.  It will take a little while because I also want to include some other features that have been waiting in the pipeline.  If you want to try the fix right away, you just need to  modify the one line of code described above and rebuild.

Update 2/2/17:    I have taken Anthony Woolridge’s suggestion and modified the RTCM conversion code to automatically adjust the pseudorange and carrier phase measurements to compensate for any round off done to the time tag.  This means it is not necessary to set the time-tag adjust receiver option.  This change is currently checked into my Github page and I hope to post new executables in the next couple of days.

Exploring differences between real-time and post-processed solutions.

I’ve had a few questions recently about differences showing up when the same set of raw data measurements are processed real-time and when they are post-processed.  Since I haven’t done a lot of real-time work I didn’t have a good answer to these questions, but it seemed like an interesting problem so I thought I would dig into a little bit.

In many cases, these differences can be traced to a poorly performing data link between base and rover that loses, delays or corrupts the base measurement data.  These problems are usually diagnosed fairly easily by looking at the “age of differential”  between base and rover or by seeing missing data in plots of the base observations.  My interest is not in these cases but rather where the data link is performing well and there is still a difference between the real-time and post-process solutions.

To troubleshoot real-time solutions is a little trickier than post-processing solutions because you may need a way to re-run the data through the real-time RTKLIB app (either RTKRCV or RTKNAVI) to recreate the problem.  The standard *.ubx log files do not contain enough information to do this since they contain only a time stamp for when the measurement was made and not when it was actually available to the solution.  There will usually be some delay between the two because of latencies in the data link between rover and base.  The post-processing solutions ignore this delay and simply align the two measurements assuming zero delay but we need to know what these delays are to recreate the real-time solution.

The real-time solution apps have an option in the input stream setup to read from a file instead of a real-time stream.  This allows you to re-run previously recorded log files but when doing this they require a *.ubx.tag file in addition to the *.ubx file to provide the latency information.   These *.ubx.tag files are generated automatically when you log real-time data if you select the appropriate option before you collect the data.  For RTKRCV, this is a “::T” appended on to the end of the log file name.  For RTKNAVI, it is checking the “Time Tag” box in the log stream options.  I recommend always enabling these options when you are running real-time solutions because the extra files are not very large and you never know when you are going to get something unusual in the data that you would like to investigate later.

Since none of the data sets I had been sent to look at contained tag files, my first step was to try and collect some data that looked good in post-processing but not in real-time with time tags enabled.  I chose to use my Emlid Reach receivers to do this, in part because it is easy to do real-time solutions with the onboard wireless, and in part because I wanted to try out their recently released 2.1.6 version of the RTKLIB code.  This version is a very close cousin to my demo5 code and contains all of its features (although many of them are not currently accessible through the Reachview GUI).

I first added or modified a couple of lines of code in the Reach startup files to save time tag versions of both the base and rover data on the rover, and the base data on the base.  I’ve added some notes at the bottom of this post on how I did it but I don’t necessarily recommend doing it yourself unless you are fairly comfortable with linux because it can be a little tricky to recover without reflashing the unit if you make a mistake.  I wanted to be able to collect data on the Reach units using the command line based RTKRCV app but use the GUI based RTKNAVI on my laptop to re-create the realtime run.  This is because RTKNAVI has a much nicer  interface with a lot more information available.  However, this meant that I needed to fix an incompatibility in the RTKLIB code between the time stamp formats of RTKRCV and RTKNAVI as described in the RTKLIB Github issue #99.  Using the fix recommended in the issue description,  I rebuilt the code on the Reach unit to create a new str2str executable with this fix incorporated.

With these changes, I can collect measurement data that gives me the option to run post-process solutions or re-created real-time solutions.  In addition, these can be run either with measurements made before or after the data link and raw binary to RTCM conversion.  This gives me quite a bit of capability  to investigate where a potential problem might be occurring.

To test this setup, I first collected some static data with both base and rover exposed to open skies.  I got all three sets of data and tag files and using these I was able to re-run the data using RTKNAVI.  Both real-time and post-processed solutions got a fix fairly quickly and the two solutions were very similar.  So, nothing interesting to look at in this example.

Next I placed both base and rover on my back patio, just a few meters away from the house and partially blocked by a large tree, knowing that this would be a more stressful measurement environment.  I may have just got lucky, but the very first data set I collected gave me multiple fixes in post-processing but none in real-time as shown below (post-process on the left, real-time on the right).  The two loss of fixes are caused by me restarting the data collection on the Reach rover.  In this case I ran the post-processing solution using the base data collected on the base in raw binary format (*.ubx), not the data after it had been converted to RTCM and transmitted to the rover (*.rtcm)  since this is the way post-processing is usually done.

real_post

Next I ran a second post-processing solution, this time using the raw measurement file saved in RTCM format on the rover.  This time there was no fix and the solution looked nearly identical to the real-time solution plotted above.   So somewhere between when these two data files were saved, the problem is occurring.  Note that in this case I was able to do all this without the time tag files or re recreating a real-time run but I imagine this capability will be helpful in future analysis.

I had monitored the age of differential while collecting the data and after collecting the data I plotted the base observations to verify there was no missing data.  This suggests that the data link was working fine.  So my next guess was that the conversion from raw binary measurements to RTCM format might be the cause of the problem.  In real-time solutions, the base data is typically translated to RTCM before transmitting over the data link to the rover to compress the data and reduce bandwidth requirements on the data link, and this is the default configuration of the Reach units.   The amount of compression will vary depending on the details of the data but in this case the RTCM file (*.rtcm) was about one third as large as the raw binary file (*.ubx).  Some of this is lossless compression but not all of it so there is potential for degrading the solution with this translation.

The next step was to isolate the effects of the RTCM translation from any effects from the data link latency.  I did this by using the STRSVR app to translate the raw binary base data saved on the base station to RTCM format.  I configured the conversion options to use the same RTCM messages as used by Reach.  ran this data through a post-process solution.  Sure enough, just converting the undelayed raw binary data to RTCM was enough to break the solution.  That means, at least for this case, we can ignore any effect of the data link delays and focus on the RTCM conversion.

Note that the post-processing apps require all the measurement input files to be in RINEX format.  This means that both the raw binary files and the RTCM files are converted to RINEX first using RTKCONV first as part of the post-processing procedure.  One thing to be aware of when using RTKCONV to convert from RTCM to RINEX is the signal mask input options.  The default signal mask has all observation types selected and if left this way it will cause the file header to be incorrect.  If you do not de-select all the extra observation types you will see this in your observation file header

obstype

The number of observations is 8 instead of 4 and there are extra observation types listed.  This will confuse RTKLIB and it will not interpret the rest of the file properly. Specifically it will not pick up any of the GLONASS observations.  It won’t flag an error but it will cause all the GLONASS measurements to be left out of your solution.  The signal mask button is on the options page as shown below.  You want to un-check all options except “1C”.

sigmask1

This post is already getting fairly long so I will put off to the next post the rest of the story including discussion about what is actually lost in the translation to RTCM and why it caused this particular example to fail.  In general, though, it is important to understand there are real losses in this translation and that they may affect the quality of your solution.  If you have the bandwidth to transfer the raw binary format instead of the RTCM format I would recommend you consider doing that.  If you don’t have the bandwidth, I would suggest you consider the trade-offs from reducing the base sample rate enough so that you are able to transfer the measurements in raw format.  As I mentioned above, in this example the raw binary file was about three times as large as the RTCM file.

 

 

Notes on how I set up the Reach to collect extra data.  There may be a more elegant way to do this but I just wanted a quick hack.  Please be careful if you try to do this yourself and be sure to back up any files before modifying them:

RTKLIB has a “::T” option to record the time-tags but I don’t believe Reach supports this option.  I got around this by adding extra instances of str2str initiated from a function call I added to the “reach_setup” script in the /usr/bin folder.  This, and all the instructions below assume you are running the 2.1.6 version of Reach code.

 I added the call right before the call to “reachview” in the “reach_setup” script as shown in blue below.  I did this on the rover receiver assuming it is getting the base measurements through a data link.
ncat -k -l 2000 < /dev/ttyMFD1 > /dev/ttyMFD1 &
 
#start logging data files with time stamps
reach_time_logs
 
# Run ReachView
led set_color green
 

I created the “reach_time_logs” script in the /usr/bin folder and put in the following lines of code

#!/bin/bash
 
# Log u-blox data to file with time stamp logs
# find unused file name
path=”/home/root/logs/”
i=0
fname=$path”rover”$i”.ubx”
while [ -f $fname ]; do
    let “i=i+1”
    fname=$path”rover”$i”.ubx”
done
 
fnameR=$path”rover”$i”.ubx”
fnameB=$path”base”$i”.rtcm”
 
# start data collection from rover
/usr/bin/RTKLIB/app/str2str/gcc/str2str_tag  -in tcpcli://localhost:2000 -out $fnameR::T &
 
# start data collection from base
/usr/bin/RTKLIB/app/str2str/gcc/str2str_tag  -in tcpcli://192.168.43.186:9000 -out $fnameB::T &
 

This finds an unused filename and saves the measurements and the tags for both the rover and base data.  You will need to modify the specified input stream for the base data to match what you are using.  You can look at the inpstr2-type and path in the /usr/bin/RTKLIB/app/rtkrcv/rtk.conf file for the exact format.  You might be able to use the RTKLIB wildcards instead to create the file name but I just copied this code from my PiZero logger which doesn’t update the clock.  I don’t know if on the Reach the clock has been updated yet at this point in the start-up.

I also had to modify the str2str app to make the time-tags compatible with RTKNAVI.  I used the bug fix recommended in Github issue #99.  I recommend debugging by re-running the data through RTKNAVI (on a Windows machine) rather than RTKRCV because it has a much nicer interface with much more info available.  If you decide you want to re-run the data through RTKRCV you will either need to rebuild it with the bug fix or collect the data with the unmodified str2str.  I think it’s unlikely that you will see different solutions between RTKRCV and RTKNAVI assuming they are both configured the same.
 
Rename the modified str2str executable to str2str_tag and leave it in the /usr/bin/RTKLIB/app/str2str/gcc folder .  Use the chmod +x command to make this file and the “reach_time_logs” file both executable.
I also modified the base receiver and saved the base data in ubx format before it was converted to rtcm so I could compare before and after to see if the conversion or data link might be causing problems.  You can use the same modifications described above, except delete the last two lines in the “reach_time_logs” script.
With these changes in place, the units will automatically save time-tagged data to a new file every time they are turned on.
After collecting data, the data files will be in the /home/root/logs folder.  The file names will be basexx.rtcm, basexx.rtcm.tag, roverxx.ubx, and roverxx.ubx.tag where “xx” will increment every time you run until you delete the old files.  To run them through RTKNAVI, just specify files in the input stream and check the time tag box.
 
You then have the options of running post-process or simulated real-time with measurements either before or after the data link/RTCM conversion.  This should give you a fair bit of insight into where the problem is occurring.
 
 I had a bit of trouble with files I edited getting corrupted after  a power cycle (maybe because I was using WinSCP through the wireless) so I suggest using the “reboot” or “shutdown” commands to avoid problems.  Also be sure to make copies of the files before you edit them.  At one point I corrupted the “reach_setup” script and then could only access the Reach by using the instructions in the Software Development section of the QuickStart guide.  Another time the /etc/reachview/stable_config.json disappeared and I had to restore it.

Collecting raw Ublox data with RTKLIB

At this point, we have verified that the GPS hardware and the link to the PC are working properly, and are ready to start using RTKLIB to collect the raw GPS data.

Start by downloading RTKLIB from Github.  Choose either the main branch (2.4.2.11) which is the stable branch or 2.4.3 which is a beta branch (currently at revision b8).

[Update 8/22/18:  Your other choice is my demo5 version of the code which has been optimized for low-cost receivers, especially the u-blox receivers.  This is the code I would recommend now.  The source code is available here and Windows executables are available here]

Recent check-ins have all been made on the beta branch, but most or all of the recent work appears to be unrelated to Ublox receivers or the  kinematic mode normally used for low cost receivers, so the functionality of the code should be nearly identical regardless of which branch you choose.  I am using 2.4.3 because I think it may be easier to merge in any future changes.  The repository includes all the executables, so there is no need to build any code before running it.

There are actually two sets of executables built from the same codebase, a GUI set, and a CUI set.  I am using a combination of the two.  For collecting the raw data, and plotting the results, I use the GUI versions (STRSVR and RTKPLOT) for convenience.  For converting the raw data to RTCM and processing the data, I use the CUI versions (CONVBIN and RTKPOST).  This is for two reasons.  First, because making any changes to the GUI versions requires  an Embarcadero/Borland VCL compiler to re-build the code and this compiler is not available for free.  The CUI versions can be rebuilt with the Microsoft Visual C++ compiler, which is free and one I am also much more familiar with.  The second reason I use the CUIs is because I have found it easier to keep track of all the input and output files for each run when using the CUIs.  I use simple Matlab wrappers to call the CUIs which save all the configuration, input, and output information to a separate folder.  Python wrappers would probably work just as well and it is available for free, but I already have Matlab and again am more familiar with it.

Once RTKLIB is downloaded, and the GPS receiver is connected to your PC via USB, start the STRSVR program (strsvr.exe).  It can be found in the rtklib\bin folder.  Set the Input Stream to “Serial” and use the “Opt” button to set the port and baudrate to match your GPS receiver.  If you’ve been communicating to the receiver with U-center or any other application, make sure you have disconnected them from the com ports to avoid any conflicts.

Next we need to configure the receiver to output the raw GPS signals, pseudorange, carrier phase, doppler, and SNR.   For the Neo-M8N receiver this requires us to use the normally undocumented commands TRK-MEAS and TRK-SFRBX.  First select the “Cmd” button for the input stream and copy the following commands into the “Commands at startup” window.

!UBX CFG-GNSS 0 32 32 1 0 10 32 0 1
!UBX CFG-GNSS 0 32 32 1 6 8 16 0 1
!UBX CFG-MSG 3 15 0 1 0 1 0 0
!UBX CFG-MSG 3 16 0 1 0 1 0 0
!UBX CFG-MSG 1 32 0 1 0 1 0 0

Make sure the “Commands at startup” box is selected, then click the “Save” button to save.  STRSVR will send these commands to the receiver at startup.  The third and fourth commands in this list enable the TRK-MEAS and TRK-SFRBX commands to the USB and UART ports.  See pages 9-13 of this document for an explanation of exactly what these numbers do.  The first and second commands are documented commands to configure how many channels the receiver should allocate to GPS and GLONASS.  Details are explained in the M8 Receiver Description under the CFG-GNSS command.  We could have configured these with the Ublox eval software in the last post, but I thought it was easier to do it all in one place, and also more consistent with other references.

strsvr

Next, set Output (1) to “File” and use the “Opt” button to select a file name to save the data to.  I use a “.ubx” extension for this raw binary data.  Finally, click on “Start” to start collecting receiver data.  If everything is working properly, it should look something like this:

strsvr_run

In the next post we will use RTKLIB to convert this Ublox proprietary binary data to a more friendly text version.