A first look at RTKLIB with dual frequency receivers

As I mentioned in my last couple of posts, I have recently been exploring the use of RTKLIB with a couple of different low-cost dual frequency receivers.  Low-cost is a relative term here.  At $600 to $1700 for the receivers, plus the cost of the antenna, these configurations are significantly more expensive than the u-blox based single frequency versions I usually work with.  Still, they are quite a bit less expensive than models from the more traditional manufacturers.

The first receiver I have is a Piksi Multi from Swift Navigation.


It is available from their website for $595 for the receiver board, or $1995 for a complete evaluation kit including two receivers, antennas, and radios.  This receiver relies on the new L2C codes for the second (L2) frequency and so does not support the traditional P2 codes.  L2C is an unencrypted code that is only available on the newer GPS satellites.  Roughly half the GPS satellites are currently broadcasting these codes but this number will increase as newer satellites are launched.  This does mean that the Multi can only make dual frequency measurements on the satellites that have L2C capability.  Also, although the receiver hardware is capable of supporting GLONASS G1/G2, BeiDou B1/B2, Galileo E1/E5b, QZSS L1/L2 and SBAS signals, these constellations are not supported in the current firmware.  This means that the current capability of this receiver is somewhat limited, but it should improve as they release new firmware and more satellites are launched.

The second receiver I have been evaluating is a more expensive option, the Precis-BX306 from Tersus which is available from their website for $1699.

BX306 (2)


This receiver does support the P2 codes on the L2 frequency and therefore is able to receive dual frequency signals from all the GPS satellites.  It also supports Glonass G1/G2 and Beidou B1/B2 in the current hardware and firmware.  Tersus also has similar receivers that are less expensive but also less capable than this one.  The Precis-BX305 fully supports GPS L1/L2 but only has support for GLONASS G1 and Beidou B1/B3.  The Precis-BX316R supports all the same constellations as the BX306 but only provides raw measurements, it has no internal RTK engine.  Both of these models sell for $999.

In the spirit of full disclosure, I should mention that Tersus gave me the BX306 receiver to evaluate and one of my consulting clients gave me permission to use their Piksi Multi receiver for this evaluation.  I appreciate both of them for their generosity.

Before digging into the details of the receivers, it’s worth first discussing what the advantages of a dual frequency receiver are over a single frequency receiver and also to what extent RTKLIB is capable of exploiting these advantages.  All of this is fairly new to me so the following analysis is based on my somewhat limited understanding.  If I get anything wrong, I am hoping one of my more experienced readers will jump in and correct me.

The most obvious advantage of the dual frequency receiver is that it provides more measurements than the single frequency receiver for the same satellite constellation.  However, if this were the only advantage, then the Piksi Multi, with GPS support only, would still be less capable than the u-blox M8T when the additional GLONASS, SBAS, and Galileo measurements are all taken into account.  Dual frequency receivers do also tend to have more high-end circuitry and tend to be paired with more expensive antennas.

The biggest advantage, though, comes from having multiple measurement of the same path through the atmosphere made with different frequencies.  Using linear combinations of these pairs of measurements in different ways we can glean information that is just not available with the single frequency measurements.  Two linear combinations that are particularly useful are the ionosphere-free combination and the wide lane combination.

The ionosphere-free combination takes advantage of the fact that the ionospheric delay is inversely proportional to the square of the frequency.  By taking the difference of the squares of the two phase measurements,  more than 99% of the ionospheric delay error can be eliminated.  The ionosphere-free combination provides the ability to deal with much longer baselines between the two receivers and also makes possible accurate PPP measurements.

The wide lane combination is simply the difference of the phase measurements made at the two frequencies and the advantage of this combination is that the effective wavelength of this measurement is a function of the difference in frequencies between the two measurements.  In the L1/L2 case, the difference in frequencies is 348 Mhz and the wavelength is 86 cms.  Resolving integer cycle ambiguities over an 86 cm cycle is significantly easier than resolving them over the much shorter L1 wavelength of 19 cm, the only option available with the single frequency receivers.  Once the wide lane ambiguities have been resolved, they can be used to assist in resolving the shorter cycle L1 and L2 ambiguities.  This can lead to much faster times to first fix with the dual frequency receivers.

Of course, these additional opportunities are only valuable if the solution algorithm takes advantage of them.  Unfortunately RTKLIB appears to be quite disappointing in this regard.  For the most part, the default configuration of RTKLIB for RTK handles the two frequency measurements independently and takes very little advantage of the linear combinations.  This makes them no more valuable than if they were two measurements from different satellites.  There is an option to enable ionosphere free combinations (pos1-ionoopt =dual-freq) in the config file which uses the ionosphere-free combinations to estimate the phase biases instead of the individual measurements.  The user manual indicates, though, that the ionosphere-free model is not applied for the RTK solution modes and I have found that setting this option when running an RTK solution breaks the ambiguity resolution.  There is also an option in the code for a wide lane ambiguity resolution but this option is not mentioned in the user manual and if set it attempts to call an external function that is not included with the RTKLIB source code.  There may be a little more support for dual frequency in the PPP solution modes.  However, the current RTKLIB version does not make any attempt at ambiguity resolution in the PPP modes.  The 2.4.2 release of RTKLIB does include what the manual describes as a beta version of ambiguity resolution but that has been removed in the 2.4.3 release.  Without ambiguity resolution, my experience with PPP solutions has been that I can get much better solutions using some of the free online PPP services that do use ambiguity resolution than I can get with RTKLIB.  I am hoping someone can prove me wrong and provide a config file that generates an RTK or PPP solution with RTKLIB that takes full advantage of the linear combinations of the dual frequency measurements but from everything I can see, there is not much code to support this capability.

Fortunately, both receivers do include the capability to calculate their own RTK solutions without RTKLIB.    So the goal in the following experiments will be to both compare the two receivers against an M8T single frequency receiver and also to compare their internal solutions to the RTKLIB solutions.  Unfortunately, neither receiver is set up to handle the post-processing of previously collected measurements and so all of the internal RTK solutions need to be done in real-time.  In my last post I described how I configured the receivers to receive real-time base station data over a cell phone link.

So, let’s start by taking a look at some actual measurement data.

Here is a set of measurement observations collected simultaneously from two receivers on a moving car.  The observations on the left are from a u-blox M8T receiver and on the right are from the Tersus receiver.  Satellites with lock to L1 only are indicated in yellow, those locked to L1 and L2 are in green.


At the start of the data set, the M8T is locked to 8 GPS, 7 Glonass, 4 Galileo satellites, and 3 SBAS, for a total of 21 measurements.  The Tersus receiver is locked to 8 GPS L1, 7 GPS L2, 6 Glonass L1 and 5 Glonass L2 for a total of 26 measurements.  The greater number of satellites should give the Tersus an advantage over the M8T even before considering the extra advantages of the L1/L2 combinations or the more expensive electronics and antenna.

Here is a similar set of data.  The M8T receiver is on the left again, this time the Swift is on the right.  Again yellow is a single frequency measurement, green is for measurements at two frequencies.


swift_obs This time there were a few less satellites in the sky.  At the start of the data set the M8T is locked to 7 GPS, 7 Glonass, 2 Galileo, and 3 SBAS for a total of 19 measurements.  The Swift receiver has 6 GPS L1, and 4 GPS L2 for a total of only 10 measurements.  Particularly for RTKLIB which does not take advantage of the extra information in the L1/L2 combinations, it will be difficult to make up for the small number of measurements.

As mentioned before, this should improve as Swift releases firmware to support GLONASS, BeiDou, Galileo, QZSS, and SBAS, and as more GPS satellites are launched with L2C capability.

In my next post I will compare solutions generated with these different measurements, both from RTKLIB and from the internal RTK engines.







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.


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.


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.


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.


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.





Newest U-blox M8N receivers not usable with RTKLIB

It looks like it is no longer possible to access the raw GPS measurements on the newest version of the u-blox M8N receiver.  Access to these raw measurements on the M8N has always been through debug messages not officially supported by u-blox.  Last year, when they migrated from the 2.01 version of firmware to the 3.01, version they scrambled the output of these messages so they were no longer readable by RTKLIB.

Until recently though, the units they were shipping still had an older 2.01 version of ROM.  With these units it is possible to downgrade the firmware to 2.01 using the instructions on their website.  With the older firmware loaded, the receivers revert to their previous behavior and the debug messages are no longer scrambled.

Apparently their newest units are shipping with a 3.01 version of ROM and this ROM is not compatible with the older 2.01 version of firmware.  If you attempt to load the older firmware it will appear to succeed but will still be running the newer code.

You can see what version of ROM and firmware your receiver is running using the UBX-MON-VER message from the u-center console.  The example below shows the message output for one of the newer modules with the 3.01 ROM after attempting to download the older firmware.  I believe the firmware listed under “Extension(s)” is the ROM version and the firmware listed under “Software Version” is the version of firmware loaded to flash.  In this case you can see that the ROM is version 3.01 and that the flash is still running version 3.01 even though it was attempted to load the 2.01 firmware.


In an older version of the M8N module, the ROM code listed under “Extension(s)” would have been 2.01 and the firmware listed under “Software Version” could be either 2.01 or 3.01 depending on how old the module was and what firmware had been downloaded to it.

There are a few more details about the issue on the u-blox forum in this thread.  Thanks to Marco for making me aware of the issue and Clive and Helge for providing a detailed explanation of what is going on.

If you are using the u-blox M8T, and not the M8N, then you will be using the officially supported raw measurement messages and would normally not care about access to the debug messages.  The only exception I know of is that the resolution of the SNR measurements are 0.2 dB in the debug messages and 1.0 in the official messages.  I have not confirmed that the debug messages on the 3.01 M8T firmware are scrambled but it is likely that they are.

[Note 6/25/17:  A couple of readers have pointed out that this is not the whole story.  It would have been more correct to say that the newest M8N modules are not usable with the publicly available versions of u-blox firmware and RTKLIB.  It turns out that u-blox did not use a particularly sophisticated method to scramble the debug messages and there are now several modified versions of u-blox firmware and RTKLIB floating around that have been hacked to unscramble the messages.  I don’t want to get into the question of ethics or legality of using these codes but just say that I personally am less comfortable using the debug messages in the modules where u-blox has made an obvious attempt to prevent this and have avoided any use of them at least for the time being.]

New b27 release of demo5 code

I’ve just released a b27  version of the demo5 code that incorporates all the changes in the b27 release of the official code.  I’ve also included some fixes for the Galileo satellites.  The biggest fix I added was for an array overrun that was causing solutions to intermittently report zero status when Galileo satellites were enabled.  Another fix was to correctly decode the range accuracy estimates in the Galileo ephemeris data.  The code can be downloaded from the code download section of the rtkexplorer.com website.   The source code is available in my Github repository.  Please let me know if you find any issues with this code, especially if it was something that was working in the previous code.

One issue I am aware of is the time tag feature which enables simulated real-time runs in RTKNAVI appears to be broken in the new code.  There was an existing incompatibility  between time-tag files that were created in the win32 version of RTKLIB and run in the win64 version or vice-versa.   It looks like an attempt to fix this in the latest release code actually made things worse and now the time-tag files don’t work at all, at least in the win32 version.

By the way, for anyone using the free starter edition of the Embarcadero compiler, be aware that it does not support building win64 executables.  The code will build, but the option to specify win64 is not available, so the compiler will just build the win32 code.  I hadn’t realized this until I tried to build the win64 version recently.

Also, I’ve recently got a hold of two low cost dual frequency receivers, one from Swift Navigation and one from Tersus, so I am collecting and analyzing data with them now.  I should have some results and comparisons to share in my next post soon.

Update to RTKLIB config file recommendations

I’ve just updated my “RTKLIB: Customizing the input configuration file” post from a few months ago with information on all of the new config parameters I have added to the demo5 code up through B26B.  I’ve also added more notes to some of the existing features based on my more recent experiences.

RTKLIB on a drone with u-blox M8T receivers

Drones are a popular application for RTKLIB and quite a few readers have shared their drone-collected data sets with me, usually with questions on how they can get better solutions. In many cases, the quality of this data has been fairly poor and it has been difficult to get satisfactory results. I was curious to understand why this environment tends to be so challenging since in theory a drone should have more open skies than just about any other application.

To do an experiment, I bought an inexpensive consumer drone from Amazon. I chose the X8C from Syma since it is beginner model and a little larger than some options. I figured the larger size should make it better able to carry some extra weight.

After a few practice flights to get the hang of flying it, I used some duct tape and double-sided foam adhesive to attach a u-blox antenna and 90 mm diameter ground plane to the top of the drone and a u-blox M8T receiver with my custom CHIP data logger underneath where the camera usually goes. I used the landing gear as a spool to wind the unnecessary five meters of antenna cable which was the heaviest part of the whole setup. From a weight perspective, the Emlid Reach units would have been a better choice, but I wanted to collect data from the Galileo constellation of satellites as well as GPS and GLONASS so I used my CSG receiver with the newer 3.0 firmware. I used a second CSG receiver mounted on top of my car as the base station.  Here’s a stock photo of the drone on the left and after my modifications on the right.


Although the drone was able to lift the extra weight fairly easily, it seemed to affect the stability of the flight control system and after a few minutes the prop motors would start to fight each other. At that point the drone would start to descend even at full throttle and the drone would land hard enough to usually bounce on its side or back. Still I was able to make a number of short flights which were adequate for testing purposes.

Here’s the observation data for the first set of flights, base station on the left and drone on the right. Red ticks are cycle-slips and gray ticks are half-cycle ambiguities. Ideally, the drone data would look as clean as the base but as you can see it is significantly worse and it turned out to be unusable for any sort of reliable position solution.  The regions without cycle-slips in the drone observations are the times in between flights in which the drone is sitting on the ground.


Clearly, while the drone is flying, something is interfering with the GPS receiver or antenna, most likely either EMI or mechanical vibration. I could have used a fancy test stand and RF sniffer to try and locate the source of interference but since this blog is focused on low-cost solutions I just used some duct tape, a steel bar, and the RTKLIB code instead.

I used two types of duct tape, both the polyester/fabric type that everyone calls duct tape, and also the metal foil type that is actually used to repair or install ducts. I first used the non-metal duct tape to securely attach the landing gear to the heavy steel bar. The steel bar was convenient because it was easy to attach but anything heavy enough to prevent the drone lifting off under full throttle would work fine.

I then started an instance of RTKNAVI on my laptop and connected it to the receiver on the drone.  The goal was to simulate a complete drone flight while the drone was sitting on the ground and at the same time watch the RTKNAVI observations to detect any degradation of the measurements.  I used a wireless connection but a USB cable would have worked too.

Unfortunately RTKNAVI won’t plot the observation data real-time, but by selecting the tiny “RTK Monitor” box in the bottom left corner of the main RTKNAVI screen, then choosing “Obs Data” from the menu, I was able to get a continuously updating listing of the observations.  Cycle-slips show up as non-zero values in the first column with the I heading. I chose a location outdoors with open enough skies that any degradation in the observation data would be obvious.


I first observed the cycle-slip column with the drone powered down to verify I wasn’t getting any cycle-slips on all but the lowest elevation satellites. I then continued to observe the cycle-slip column while sequencing through the steps required to fly the drone. I first powered on the drone, then powered on the transmitter, then issued the calibration/connection sequence, then turned on the throttle to low. So far, so good, no sign of cycle-slips. I then started moving the joysticks to issue steering commands which caused the motors to change speeds. All of a sudden I started getting cycle-slips, the more aggressive the steering commands, the more cycle-slips I saw. Aggressive changes in throttle also caused cycle-slips but full throttle with no adjustments or steering commands was fine.

Next I moved just the antenna, then just the receiver away from the drone while issuing steering commands. Moving the antenna away had no effect but moving the receiver away eliminated the cycle-slips.

At this point my guess was that the interference was coming from the relatively high power switching in the motor control circuits and that the antenna ground plane was shielding the antenna from this interference but nothing was shielding the receiver. To test this theory, I attached a layer of the metal duct tape to the bottom of the drone to act as a shield between the drone controller board and the receiver.  I then re-attached the receiver to the bottom of the drone and re-ran the experiment. This time there were almost no cycle-slips even with the most aggressive steering.

I then removed the steel bar and ran a second set of short flights with the layer of metal tape still in place. I was a little concerned that the new shield would interfere with commands sent from the transmitter to the drone so I first tested everything while still on the ground and then kept the drone fairly close during the flight. Fortunately I didn’t see any sign of commands not getting through.

The drone data looked much cleaner in this flight!  Unfortunately, this time the base data was no good with many simultaneous cycle-slips throughout the observation data. At this point I realized that I had placed the base station receiver directly on the top of the car when collecting the data which was very hot at the time. Usually I keep the receiver in the car to avoid this and only place the antenna on the roof. I have seen this kind of severe temperature effects cause simultaneous cycle-slips before but never to this extent. Again the data was completely unusable.

So, back out there again for a third round of flights. This time, everything looked much better. I still saw a few cycle-slips, especially when first applying the throttle at take-off, so my shielding was not perfect but a dramatic improvement over the first flight. The plots below show the results. The top two plots are position solutions for the z-axis. The top plot is with continuous ambiguity resolution and the middle plot is with fix-and-hold enabled. The bottom plot is the drone observation data.


I made three adjustments to the input configuration file from what I would normally use for my car based measurements.  First of all, since the drones have very open skies, I adjusted the minimum elevation angles from 15 degrees to 10 degrees.   Then, after plotting and observing the accelerations from an initial solution, I increased the vertical acceleration dynamics estimate (stats-prnaccelv) from 0.25 to 1.0.  Finally, because I was seeing slightly higher position variances in the initial solution than I usually do, I adjusted the position variance AR threshold (pos2-arthres1) from 0.004 to 0.1  Both of these last two changes would make sense if the level of vibration were higher in the drone than I am used to seeing, which is quite likely.

Each time the drone landed/crashed due to the unstable flight control system it would bounce to the side or upside-down and that is what is causing the cycle-slips and switch from fix to float at the end of each flight. As you can see though in every case I quickly get another fix after I put the drone upright again. The fixes are solid enough to hold through the entire flight even in continuous mode for all but one of the flights. With fix-and-hold enabled all flights maintained 100% fix rate. The data is as good as or better than similar experiments where I have mounted the rover on top of a car.

This is not surprising since the skies are more open in this experiment. Having over twenty satellites available for ambiguity resolution also helped. I used all the satellites (GPS/GLONASS/Galileo/SBAS) for ambiguity resolution and took advantage of the new feature in the demo5 b26 code that cycles through all the satellites and will throw a single one out if it is preventing a fix. This will automatically occur anytime the number of satellites available for ambiguity resolution is greater than the config parameter “pos2-mindropsats” which defaults to twenty.

I have added the raw data and the configuration file to the  sample data set section at rtkexplorer.com

I imagine different drones will have different issues and not all will be as easy to fix as this one, but the method described here or something similar should be helpful any time drone data is not looking as clean as the base station data.

The fix I chose was very easy to implement but a better fix would probably have been to wrap just the receiver in a shield rather than placing a shield between the control board and the receiver. This would protect the receiver better and avoid affecting commands sent from the transmitter.  In fact, based on these results, I suspect shielding the GPS receiver on a drone is always a good idea.

Zero baseline experiment

I’ve been busy with some consulting projects recently so it’s been a while since my last post but I’m finally caught up and had some time to write something.  I thought I would describe an experiment I did to both try out the “fixed” mode in RTKLIB and also provide some insight into the composition of the errors in the pseudorange and carrier phase measurements in the u-blox M8T receiver.

The “fixed” mode is an alternative to “static” or “kinematic” in which the exact rover location is specified as well as the base position and remains fixed.  The residual errors are then calculated  from the actual position rather than the measured position.  I describe it in a little more detail in this post.  It is intended to be used as a tool to characterize and analyze the residual errors in the pseudorange and carrier phase measurements.

The basic idea in this experiment was to connect two M8T receivers to a single antenna and then compare residuals between the two receivers.  I first looked at the solution using one receiver as base and the other as rover (the zero baseline case) and then compared solutions between each receiver and a local CORS reference station about 8 km away.

The M8T is typically setup to use an active antenna for which it provides power on the antenna input.  I was concerned about connecting the two antenna power feeds together, so to avoid this, I added a 47 pf capacitor in series in one of the antenna feeds to act as a DC block.  In the photo below, the capacitor is inside the metal tape wrapped around a male to male SMA adapter.  I cut the adapter in half, soldered the capacitor to each end, then wrapped it in metal tape as a shield.


The receivers are from CSG and each one is connected to a Next Thing CHIP single board computer, which logs the data and transmits it over wireless to my laptop.  They are very similar to the Raspberry Pi data loggers I described in a previous post, but the on-board wireless makes them more convenient to use.  At $9 each, they are also quite affordable, especially since they do not need micro SD cards like the Raspberry Pi Zeros.  They also have a built-in LiPo battery connector which can be convenient for providing power., although they can also be powered over the USB connectors.  They are also linux based, so setting them up is very similar to the instructions in my Raspberry Pi post.

I first looked at the zero baseline case where I used one receiver as base and the other as rover.  In this case the two receivers are seeing exactly the same signal from the single antenna.  Any error contributions from the satellites, atmosphere, or antenna should cancel and the only contributor to the residual errors should be from the receivers.

I collected about an hour of measurement data from my back patio.  It is next to the house and nearby trees so as usual, the data quality is only mediocre and will include both some multipath and signal attenuation.  I prefer to look at less than perfect data because that is where the challenges are, not in the perfect data sets collected in wide-open skies.

Here are the residuals for a high elevation, high signal strength GPS satellite.  Standard deviations are 0.24 meters for the pseudorange and 0.0008 meters for the carrier phase.


For a lower elevation GPS satellite with low and varying signal strength, the standard deviations increased to 0.46 meters for the pseudorange and 0.0017 meters for the carrier phase.  Notice how the residuals increase as the signal strength decreases as you would expect.



The GLONASS satellites had noticeably higher residuals.  Here is an example of a satellite with high elevation and reasonable signal strength.  The standard deviations were 1.02 meters for pseudorange and 0.0039 meters for carrier phase, more than twice the GPS residuals.


I’m not quite sure how relevant it is, but the ratio between the pseudorange residuals and carrier phase residuals in each case is roughly 300, the same value I have found works best for “eratio1”, the config file input parameter that specifies the ratio between the two.

RTKLIB also estimates the standard devations of the GLONASS satellites measurements at 1.5 times the standard deviations of the GPS satellites which is less than the difference I see in the example above.

However, my numbers are for only the receiver components of the measurement errors, I’m not sure exactly which components the RTKLIB config parameters are intended to include.

For the second experiment, I calculated solutions for both receivers relative to a CORS reference station about 8 km away.  In this case, I was curious to see how close the two solutions are as they will have common satellite, atmospheric, and antenna errors but will differ in their receiver errors.  The plot below shows the residuals for a GPS satellite from each solution plotted on top of each other.  As you can see the errors are quite a bit larger than before and the correlation between the two receivers is very high.  Based on the frequency of the errors, I suspect they are dominated by multipath which will vary roughly sinusoidally as the direct path and reflected path go in and out of phase with each other.

I found it quite impressive to see how repeatable the errors are between the two solutions.  It indicates, at least at this distance, that the errors from the receiver are small compared to the other errors in the system.zeroBL4

Again, the GLONASS results were not as good as the GPS results and include a DC shift in the carrier phase that I’m not sure exactly what the cause is.


I haven’t spent a lot of time trying to figure out how to best use the information in these plots but in particular I found the similarity between the two receiver solutions in the longer baseline experiment quite encouraging.  If the errors are dominated by multipath as I expect, then the baseline length isn’t that relevant and I would expect to see similar results with shorter baselines.  If that’s true, then it may be possible to derive information about the receiver’s environment from the multipath data.  People do this with more expensive dual frequency receivers to monitor things like tides and ground moisture content.  It would be interesting to see if it can be done with these low cost receivers.  Or maybe it already has been done …