Moving-base solutions (part 2)

In my last post I discussed solving for moving-base data sets using the ordinary fixed-base solution modes and promised to dis a fairly challenging data set to demonstrate with.  In case that was interfering with the solucuss solutions using the RTKLIB “movingbase” method in my next post.

Let me start by saying I had hoped to have had more success with this method by the time I got to writing this post but that has not been the case.  I have tried both the most recent demo5 code and the 2.4.3 release code and neither gives me clean reliable solutions if I turn on the “movingbase” option.

In the previous post I had pickedtion, I first switched to a cleaner data set for this experiment.  This is a data set taken with two Emlid Reach M8T receivers, one mounted on each end of a kayak while out in the ocean near Sussex England and was sent to me by Matt. Here is the solution using the same input configuration file I used in my previous post, with “movingbase” turned off.

kayak1

The distance between the receivers in this case is larger and the deviations from a circle are very small.  This result should provide very accurate heading measurements.  The two visible deviations from the circle in the plot above are caused by rolling the kayak over an embankment at at launch and retrieval.  These large z-axis movements violate the assumption that movements are all in the x-y direction and cause the solution to leave the circle onto a sphere but are not actual errors.

Here’s a solution using the latest 2.4.3 code with “movingbase” enabled.

kayak2

It may be that I am doing something silly but I did spend a fair bit of time trying to get a decent solution without success.  If anybody more familiar with “movingbase”solutions would like to take a shot at it, I’ve uploaded this data set to here on the rtkexplorer.com website.  Please let me know if you are able to get a decent “movingbase” solution with this data.

I went back to the more challenging original data set from last post since I actually had slightly more success with that one, although still quite limited.

In my first attempt with “movingbase” enabled, I ran into the same problem as last post where the missing measurements in the base data caused large spikes in the solution.  This was true even with the max age of differential set to less than one sample time, which is what fixed the problem previously.  Looking at the code, this is because the “maxage” input parameter is ignored when “movingbase” is set and a hard-coded value is used instead (more about this below).   I modified the code so that it did check the “maxage” limit for “movingbase” and then got the following solution.

movebase6

The spikes are much smaller now that the missing samples are removed but they are still occurring, this time when both measurements are present.  The spikes are large enough to make this solution useless.  At this point I have given up trying to get useful results with the “movingbase” solution but again would be very interested if someone else can show good results for this data as well.  The raw data is located at the same link as the previous data set.

I am not completely surprised that the “movingbase” solutions are not working well, since the only other case I’m aware of that RTKLIB allows the base to move also has caused me problems.  That occurs when running real-time solutions and setting the base location to “Average of Single Positions” and then setting the number of averages greater than one.   Whenever I have done this, the solution takes a long time to converge.  I get much faster first fixes if I set the number of averages to one which then prevents the base location moving after the first measurement.

Since I did spend some time going through the code to understand how the “movingbase” solution is supposed to work, I thought I would share that here.  Setting the solution mode to “movingbase” sets the opt->mode variable in the code to “PMODE_MOVEB” so I started by searching the code base for this.  There is also a section in the RTKLIB manual in Appendix E that describes the moving-base model.  Here’s a quick summary for the significant differences I found that occur when in “movingbase” mode

  1. Adjust base position every epoch: Based on single point position result.
  2.  Synchronize rover/base measurements:  The measurement times between the two receivers may vary slightly (usually less than 2 msec).  This can degrade accuracy in the case of very fast-moving rovers.  To prevent this, the base measurements are adjusted for their time difference.  Uses a hard-coded value (1.01 sec) for max age of differential instead of the “maxage”input config parameter.
  3. Constrain baseline: Add a pseudo-measurement to the kalman filter measurement update based on the error from the baseline length specified in “pos2-baselen” and “pos2-basesig” input parameters. (Only applied if pos2-baselen>0)
  4. Increase kalman filter update iterations:  Add two iterations to the number of iterations specified by the “pos2-niter” input parameter.  This should improve the response in the case of large non-linearities introduced by short baselines or rotational accelerations.

So, based on these results, my recommendation for processing moving-base data is to use the ordinary fixed-base solution parameters I described in my previous post.  This will usually give good results but be aware that there will be limitations in the cases where the rover moves a very long distance away from it’s starting point or if is moving fast relative to any sampling time deviations between the two rovers.

 

 

Exploring moving-base solutions

Recently, I’ve had several questions about moving-base solutions so that will be the topic for this post.

As you might guess from the name, a moving-base solution differs from the more common fixed-based solutions in that the base station is allowed to move in addition to the rover.   Although it could be used to track the distance between two moving rovers it is more commonly used in a configuration with two receivers attached to a single rover and used to determine heading. Since the receivers remain at a fixed distance from each other, the solution in this case becomes a circle with a radius equal to the distance between the receivers.  The location on this circle corresponds to the rover’s heading which is easily calculated using a four quadrant arctan of the x and y components of the position.  I also used moving base solutions in several of my earliest posts because the circular nature of the solution makes it easier to verify the solution and to measure errors.  Since all solution points should be on the circle, any deviation from the circle can be assumed to be error.

To be more exact, everywhere I mention “circle” above I really should say “sphere” instead since the solution has three dimensions, but if the rover is ground-based, the movements in the z-axis will be relatively small and for simplicity we can assume it is a circle.

In fixed-base solutions, the measurement rate of the base station is often lower than the rover both because it’s location is not changing and also because the base data often has to be transmitted over a data link which may be bandwidth limited.  In a moving-base solution, since both receivers are moving, and there is usually no need for a data link since they are both attached to the same rover, it makes sense to use the same data rate for both receivers.

For this exercise, I chose to use a data set I discussed previously in my “M8N vs M8T” series of posts.  It consists of two receivers, an M8N and an M8T, on top of a moving car and another M8T receiver used as a fixed base station.  The car drives on roads with a fairly open sky view for up to a couple kilometers away from the base station.  The base station is located next to some sheds and a tree, so is not ideal, but still has fairly open skies.  All three receivers  ran at 5 Hz sampling rate and both moving receivers have some missing samples.  I’m not sure exactly why this is, it may be because I used a single laptop to collect both data streams.  Regardless of where they come from, I have found occasional missing samples are fairly common whenever I collect data at higher sample rates and believe the solution should be robust enough to handle them.  The rover M8T data also has a simultaneous cycle-slip type receiver glitch near the beginning of the data as described in my last post.  Overall, I would consider this a moderately challenging data set but those are often the best kind for testing the limits of RTKLIB.

union1

Having data from three receivers gives us the luxury of being able to calculate three different solutions (base->rover1, base->rover2, and rover1->rover2) and then compare results between them.  Since the first two solutions are fixed-base and the third is a moving-base, it also allows us to validate the moving-base solution using a combination of the two fixed-base solutions.

To start with, let’s calculate solutions for the distance between each moving receiver relative to the fixed base station using the demo5 code and my standard config files for the M8N and M8T receivers.  The only difference between the two config files is that the GLONASS ambiguity resolution (gloarmode) is set to “fix-and-hold” for the M8N config file and to “on” for the M8T config file for reasons explained in previous posts.   I’ve also done the conversion from raw data to RINEX observation files with the TRK_MEAS and STD_SLIP receiver options set to 2 and 4 respectively, again for reasons previously explained.  I set the solution mode to “static-start” since I knew the data set started with the rover stationary for long enough to get a first fix but I also could have used “kinematic” mode.

Subtracting the two fixed-base solutions gives us the distance between the two rover receivers which should be equal to a moving-base solution calculated directly between the two rovers.  The only difference is that the errors will be larger in the difference of two solutions than they will be in the direct solution because the errors in the combined solutions will accumulate.

Here are the positions and ground track for the difference between the two solutions, using the “1-2” plotting option in RTKPLOT.  As expected we get a circle for the ground track.  From the radius of the circle we can tell that the two rovers were about 15 cm apart.  Usually you would put the two receivers as far apart as possible, since the errors in the heading will decrease as the distance between the rovers increases but in this case I hadn’t intended to use the results this way so had placed the rovers closer together.  Still, it might be representative of a configuration on a small drone or other small rover.

movebase5

Next let’s try to calculate the solution directly between the two moving receivers.  RTKLIB does have a special “moving-base” mode but we won’t use this yet.  The “kinematic” solution calculates the distance between the two rovers regardless of the location of the base, so for now we can ignore the fact that the base is moving.  This will breakdown eventually if the rover gets too far from the base but since in this data set the rover is only a couple kilometers from the base at its farthest point we should be OK.

The only change I made to the config file from the previous M8N run for this run was to reduce the acceleration input parameters “stats-prnaccelh” and “stats-prnaccelv” which are used to describe the acceleration characteristics of the rover in the horizontal and vertical directions relative to the base.  In the fixed-base solution, these need to include both the linear accelerations and rotational accelerations since the rover is moving and the base is fixed, but in the moving-base solution, since we care only about differential acceleration between the receivers, we can ignore the linear accelerations and include only the rotational accelerations.  I just used a rough guess and reduced the numbers from (1,0.25) to (0.25,0.1) but I could have found more exact numbers by looking at the acceleration plot of an initial run of the solution.

Here’s the solution using this configuration.  It looks reasonable except for the occasional large spikes.

movebase2

After a little debugging, I found that the spikes were occurring wherever there was a missing sample in the base data.  When this occurs, RTKLIB just uses the previous base sample.  This works fine when the base is not moving, but in this case that’s no longer true, and the previous base measurements are not good estimates of the current position.  We can tell RTKLIB to skip these measurements by setting the maximum age of differential to something less than one sample time.  This is done with the “pos2-maxage” input parameter.  I set it to 0.1 which is half of one sample time.

With this change, I got the following solution for the position.  Much better!

movebase3

The ground track for this solution is shown below on the right, on the left is the previous ground track derived by subtracting the two fixed-base solutions.  As expected, the solutions look very similar except the moving-base solution has smaller errors which appear as deviations from a perfect circle.

movebase1

To further validate this solution we can compare the heading calculated from the moving-base position with the heading determined from the velocity vector of the fixed-base solution.  This wouldn’t work if the rover were a boat, drone, or person, but in the case of a car there are no external lateral drifts and the car will move in the direction it is pointed (unless it’s in reverse of course).   This won’t work if the velocity is zero or near zero but for reasonably high velocities we should get a good match.  The top plot below shows the difference between the two.  The blue line is for all velocities and the red is for when the velocity drops below 5 m/s.  The bottom plot shows the distance from the base to the rover.

movebase4

As expected, the errors are large when the velocities are low but we get a good match otherwise.  There also appears to be no correlation between the errors and the base to rover distance which suggests we are well below the maximum base to rover distance before we start to see issues with our assumption that the base did not move.

Overall, this solution looks excellent, with 100% fix and based on deviations from the circle, very small errors.  In fact, I recommend this configuration over the RTKLIB “moving-base” solution if you are able to live within the maximum baseline constraints.  I don’t know how large that is, but it looks like it may be significantly larger than 2 kilometers which is probably large enough for most applications.

In the next post I will explore what happens when the RTKLIB solution mode is set to “movingbase” in more detail but for now let me bring up just one of its effects since it is something we can also do here without invoking “movingbase” mode and it may have some benefit.

RTKLIB uses an extended kalman filter which is designed to handle non-linearities in the system by linearizing around the current operating point.  This generally works quite well but as the system becomes more non-linear, the errors introduced by this approximation grow larger.  One way to deal with this is to run multiple iterations of the kalman filter every measurement sample to converge on the correct answer.  As we get closer to the correct answer, we will operate closer to the point around which the system has been linearized and the errors will be smaller.  There is an input parameter in RTKLIB called “pos2-niter” that specifies the number of filter iterations for each sample.  The default value is one but when “posmode” is set to “movingbase” two iterations are automatically added to whatever this value is set to.  In the default case, we would get three iterations every sample instead of one.  Since the kalman filter assumes all velocities are linear and in the moving-base case we have been looking at, they are all rotational and non-linear, it might make sense to do this.  In my example, the sample rate is quite high relative to the rate of rotation and I found it did not help, but in other cases where the rate of rotation is higher relative to the sample rate, it might be a good idea.

So, let me finish by summarizing the changes I recommend for moving-base solutions.

  1.  Set measurement sample rate for both rover and base to the same value
  2. Leave “pos1-posmode” set to “kinematic” or “static-start”
  3. Set “pos2-maxage” to half the sample time (e.g 0.1 for 5 samples/sec)
  4. Reduce “stats-prnaccelh” and “stats-prnaccelv” to reflect differential accelearation
  5. Experiment with increasing “pos2-niter” from 1 to 3

These recommendations are based on my fairly limited experience with moving-base solutions so if anybody else has other recommendations, please respond in the Comments section.

I have added the data set I used here to the data sets available for download on rtkexplorer.com for anyone who would like to experiment further with this data.

In the next post, I will talk more about what happens when “pos1-posmode” is set to “movingbase”.

 

 

Receiver warm-up glitches

I’ve described before the occasional glitches that both the M8N and M8T seem to be susceptible too in their first few minutes of operation, but my previous description was buried in one of my more technical posts and maybe not seen by people more interested in just the practical side of using RTKLIB, so I thought it was worth bringing them up again.

Here is an example of one of these glitches which was in a data set recently sent to me by a reader, and one that was giving him trouble finding a solution.  The data is very clean, except for a nearly simultaneous cycle-slip (shown by red ticks) on every satellite.

rec_glitch

Here is a zoomed in image of the same glitch.

rec_glitch2

I see these glitches on both the M8N and the M8T receivers.  Every occurrence I have seen, the glitch occurred within a few minutes of turning on the receiver, and was present on every satellite.  In this example it occurred seven minutes after starting up, usually I see it within in the first five minutes.

These glitches are very disruptive to the RTKLIB solution.  Since the cycle-slips affect every satellite, all the phase-bias kalman filter states are reset and the solution has to start again from the beginning.  In some cases, the phase-biases initial values may have larger than normal errors in which case it is even worse than starting over.

I don’t have any good suggestions on how to deal with these other than to avoid them in the first place.  From my experience I believe they are more likely to occur if the external environment of the receiver has just changed.  For example if it went from hot to cold, or into the sun.  Once the receiver has had time to stabilize, everything is usually OK.

Giving the receiver time to adapt to it’s current environment before collecting data and protecting the receiver from sudden changes should help avoid these glitches.  Using external antennas with cables rather than the small antennas that come with the receivers helps because it allows you to place the receiver in a more protected location than the antenna.  For example, when I collect data from a moving car, I place the antenna on the roof but keep the receiver in the car.

For information on plotting the observations with cycle slip enabled see this post.  For another post where I discuss this problem in more detail, see this post.

Does anyone else have more information on what causes these glitches and maybe other steps that can be taken to avoid or deal with them?

 

 

Counterfeit M8N modules

I had a few  comments recently on counterfeit u-blox M8N modules so I thought I would take a closer look at some of my receivers to see if I could spot any fakes.

Here is a photo of the module label for a unit from CSG, the most expensive M8N receiver I have and based on their reputation, the one I have the most faith that it is genuine.

csg_ubx

 

Here are photos from two of my other receivers.  The on on top is from a GYGPSV5-NEO I got from ebay.  As far as I can tell this one is genuine as well since the label looks very similar.  Performance-wise, it is also indistinguishable from the CSG unit.

real_ubxfake_ubx

The photo on the bottom is a from a very inexpensive M8N based receiver I bought recently on ebay but have not used.  They didn’t even try very hard to make it look real!  The font is different, the QR code is different, the copyright symbol is a completely different size.    I don’t think there is any question that this is a fake.  I have not used this module so I don’t know how well it performs compared to the genuine modules.  It’s possible it works just as well, I don’t know.  I also didn’t take off the module cover and look inside but I would assume it has a real ublox M8030 chip inside.  Apparently some of the fake units cut corners on some of the other components inside such as the size of the flash.  Here’s a photo of the unopened unit.

neom8n_dg

 

I did open up one of my GYGPSV5-NEO receivers that I had accidentally damaged by using 5 volts on the UART lines instead of 3.3 volts.  This is what it looked like, in case anybody is curious.

inside_ubx

 

On another note, I have just updated the demo5 executables on my website.  The new code is merged up to RTKLIB 2.4.3 b26 and now matches what I have on my Github page.  It includes the changes I described in my last post as well as a change for post-processing “combined mode” that I will describe in a future post.

Pseudorange corrections for the u-blox TRK-MEAS command

When configuring u-blox GPS receivers to output raw pseudorange and carrier phase data, we normally use the RXM-RAWX command for the M8T receiver. For the M8N receiver, since it does not support the RXM-RAWX command, we normally use the undocumented TRK-MEAS command instead. These are what the “xxx.cmd” scripts in RTKNAVI or STR2STR are doing when starting up the receivers.

Something I did not realize until fairly recently was that the M8T also supports the TRK_MEAS command and furthermore, both commands can be enabled simultaneously.

This is normally not a good thing to do since it confuses the RTKLIB decode apps and will result in a cycle slip reported for every epoch. In fact I first discovered the capability to run both at once accidentally by running the M8N “cmd” script on an M8T after previously running the M8N script. I then spent an embarrassingly long time figuring out why the data was so garbled. If you ever see two outputs in your observation file for every epoch, this is probably the cause.

But, for learning purposes, this is actually quite an interesting configuration because it allows us to directly compare the TRK-MEAS output to the RXM-RAWX output and verify if the two are providing the same information.

To do this experiment I first combined the two command scripts to create one that would enable both raw measurement commands. I then collected some data with an M8T receiver using this script to configure the receiver. Running an unmodified version of RTKCONV on the resulting raw output file allowed me to confirm I was collecting output from both commands. Here’s one epoch from the observation file with output from both commands. I’ve deleted some of the satellites to make it easier to read. The last column is SNR which is reported with a resolution of 0.25 by the TRK-MEAS command and 1.0 by the RXM-RAWX command which makes results from the two commands easy to distinguish.

trkmeas1

Psuedorange and carrier phase are the two 13 digit fields. At first glance, the two command outputs look quite different. This is at least in part because the TRK-MEAS command reports transmission time rather than pseudorange which RTKLIB converts to a sort of pseudo-pseudorange by subtracting an arbitrary constant time off each satellite in the epoch. This error will be removed later as part of the receiver clock offset so it can be ignored. It will be constant for all satellites so we can determine it’s value by removing the common offset between all satellites.

My analysis tools don’t have an easy way to separate the two sets of data from the combined observation file and I also wanted to run solutions on each data set separately so rather than work with the combined file I chose to modify RTKCONV to separate the two sets of data. I compiled two temporary versions of this app, one with the TRK-MEAS decode function disabled and one with the RXM-RAWX decode function disabled. I then ran each on the combined raw data file to create two observation files, one with the TRK-MEAS output and one with the RXM-RAWX output.

Here’s the difference between the pseudorange measurements from the two commands, the top plot is the GPS and SBAS satellites and the bottom plot is the GLONASS satellites. In both cases they are actually differenced with a reference satellite (GPS) to remove the common clock error mentioned above.

trkmeas2

What this plot shows is that once the common error is removed, the pseudorange outputs of TRK_MEAS and RXM-RAWX are identical for the GPS and SBAS satellites but differ by constant integer number of meters for the GLONASS satellites.

Halfway through this exercise I remembered someone had left a comment a few months ago with a link referencing something similar. At the time I hadn’t fully understand the significance of the comment but going back to it I realized they were talking about exactly the same thing. The link was to the OpenStreetMap project and this is the table from the link. Apparently someone there must have done a very similar experiment and their results match mine exactly.

trkmeas3

It turns out, not surprisingly, that the integer offsets correspond directly to the carrier frequency of each GLONASS satellite, and the above table can be expressed more concisely that way. They also found that the integer offsets are different between the 2.30 u-blox firmware and the 3.01 firmware which is what the column titles refer to.  My M8T receivers are running the 2.30 firmware.

trkmeas4

I find the arbitrariness of the numbers in this table quite strange but the data suggests very strongly that they are real. If they are real and unchanging then they can quite easily be corrected in the RTKLIB TRK-MEAS decode function. Of course, the data only shows they are different, it doesn’t show which is correct. It seems more likely that the RXM-RAWX would be more accurate since it is the documented command, but we can verify this.

To do that, I ran solutions for both data sets. In the plot below, the yellow/green trace is the solution for the RXM-RAWX data, and the green/blue trace is the solution for the TRK-MEAS data. The pseudorange measurements will have a steadily diminishing effect on the solution as the kalman filter converges and the carrier-phase measurements start to dominate. What this plot shows is that the initial errors, when psuedorange dominates, are smaller in all 3 axes with the RXM-RAWX data and presumably because of this, the fix occurs earlier with this data.

trkmeas5

I then modified the TRK-MEAS decode function in ublox.c to include an adjustment to the pseudorange measurements based on the values in the table above. Rerunning the solutions with this change gave the following result. As you can see the two commands now give virtually identical solutions.

 

trkmeas6

It would not be very useful if this correction to the TRK-MEAS results applied only to the M8T and not to the M8N, but since the two modules share the same hardware, it is very likely that the corrections apply to both.

I had collected some data with an M8N receiver running 2.01 firmware at the same time I collected the M8T data above, so let’s take a look at that data next to see if we can confirm this. I converted the M8N TRK-MEAS raw data to two sets of observation files using the unmodified and modified version of RTKCONV to give uncorrected and corrected measurements. I then ran solutions on both sets of data.

In the plot below, the yellow/green trace is the solution for the corrected measurements and the green/blue trace is the uncorrected measurements. Again all three axes show smaller initial errors with the corrected measurements, although in this case it didn’t result in an earlier fix. On average, smaller position errors result in earlier fixes, but the correlation is not 100% and the fix times tend to be quite discrete so I believe the reduced initial position errors are significant even though they did not result in an earlier fix in this particular example.

trkmeas7

Just to be sure though, let’s dig in a little deeper to see if we can find some more convincing data.  Let’s look at the pseudorange residuals first.  We would expect that reducing errors in the GLONASS pseudorange measurements should be most visible in the pseudorange residuals.  Plotting the pseudorange residuals for just the GLONASS satellites, uncorrected on the left, corrected on the right confirms this.

trkmeas9

The same plot for the GPS satellite pseudorange residuals shows little change between corrected and uncorrected, again as we would expect since we have not corrected those.

trkmeas10

All of this is quite encouraging and suggests it would be worthwhile to add this correction feature to the code. So I’ve gone ahead and done this to the demo5 RTKLIB code by adding a receiver option for the u-blox receivers. Receiver options are entered from the “Options” menu from RTKCONV or RTKNAVI and from the command line with CONVBIN. Below is an example of setting the new option with RTKCONV. The name of the option is “-TRKM_ADJ” and it is set to “2” to apply the 2.01 or 2.30 firmware offsets and “3” to apply the 3.01 firmware corrections. (Note:  the second dash in the option specified in the image below is incorrect, it should be an underscore.)

trkmeas8

The options used by RTKLIB during decoding are listed in the header of the observation file so you can verify which options were used by looking there.

This change should help the M8N solutions get to a first fix quicker and more reliably.

I’ve already uploaded the source code changes to my Github page and plan to update the executables soon.

 

New website

My previous post is actually part of a new website I am in the process of building to eventually replace this blog.  It’s been nearly a year since I started this blog and while it has been a good experience, I am starting to feel the blog format can be somewhat limiting.  A website should make it easier to organize and maintain the existing information and also allows for  better upload and download capabilities for code and data.   It will be intended more as a general resource and less of a description of my own personal experiences but I will also continue to post what I’m up doing to my blog, either as part of the website, or link to it from there.   I haven’t figured out exactly how to integrate the two yet.

However, the most important reason I’m making the change is to try and migrate to a much more user-interactive experience.  A place where every reader can have their own page and can describe what they are doing and communicate with others rather than just read about what I am doing.  The only similar forum with high activity that specializes in low-cost precision GPS that I am aware of is the Emlid forum, and while it is very good, it is obviously intended just for users of their products.  I’d like to create something somewhat similar, but to serve a broader audience to include any hardware, software, or application related to low-cost precision GPS.  I want to find out what everyone else is doing with RTKLIB.

The website is not quite ready for prime time but it is getting close.  If you’d like to check it out you can go to rtkexplorer.com and let me know if you have any ideas or suggestions to improve it.  I took the “lib” out of the name partially to make it easier to remember but also to broaden the potential scope beyond RTKLIB.

 

Selecting a GPS receiver (M8N vs M8T)

 

[This is an updated version of my very first post with more info about the differences between the M8N and M8T]

Selecting a GPS receiver

The first thing you will need to begin your journey into low-cost precision GPS is a receiver that provides access to the raw GPS position signals;  pseudorange and carrier phase.  There are only a few low cost GPS chips that provide these signals.  I chose the u-blox receivers because they seem to be the most available and lowest cost option out there.  Also I was able to find examples of other people successfully using them with RTKLIB, including Tomoji Takasu, the author of RTKLIB (see here).

The NEO-M8 series is the latest generation from Ublox.  There are three basic versions of the chip, the NEO-M8N,  the NEO-M8T, and the NEO-M8P.  The NEO-M8P uses u-blox’s own integerated RTK (real-time kinematics) solution and is significantly more expensive than the other two.  I have not worked with this version and don’t know anything about it.  Assuming you plan to use the RTKLIB open-source software to process the raw GPS signals, then you will want to choose between the M8T and the M8N.

NEO-M8T

The NEO-M8T is more capable and more expensive than the NEO-M8N.  Unlike the M8N, it is specifically intended to be used for precision positioning and officially supports output of the raw signals.  The current firmware supports the GPS and GLONASS satellite systems and newer firmware should be available soon to also support the Galileo system.

The best source for a M8T based receiver that I am aware of is from CSG Shop for $75.  It has a USB interface which means it can easily be connected directly to a computer without any kind of adapter.  It does not come with an antenna but CSG also sells a u-blox antenna for an additional $20.  I have had good results with this antenna and would recommend it.  Assuming you buy two units, one for a base and one for a rover, this setup will cost just over $200 with shipping.  If you are looking for maximum performance and easy setup, and the $200 is within your budget, I would recommend this choice over the M8N.  Here’s a photo of the receiver and antenna from CSG.

UBLOX NEO-M8N GPS GNSS receiver board with SMA for UAV, Robotsantenna

Another M8T-based option, if you are looking for a more integrated solution and willing to spend a little more is the  Emlid Reach.  This is a pair of M8T receivers combined with Intel Edison SBCs with wireless and bluetooth as well as higher quality Tallysman antennas for $570 for the pair.  It uses RTKLIB for the GPS solutions but also includes an additional layer of code to make setup and use easier for the average user.

NEO-M8N

If you’d prefer a less expensive choice than the M8T and are willing to accept a few compromises then you should consider the M8N.  The NEO-M8N chip does not officially support output of the raw GPS signals but can be configured to do so with undocumented and unsupported commands over the serial port.  These commands are no longer available in the latest firmware (3.01).  However most units shipping today still have the older 2.01 firmware and so still work.  Also, the firmware can be downgraded from 3.01 to 2.01 if you did end up with a receiver with the newer firmware.  The older firmware does not support Galileo.  Going forward, as that system becomes more capable,  this will become a more significant disadvantage of the M8N receiver.

Performance-wise, the M8N and M8T are based on the same core and for the most part are very similar.  There is one noticeable difference however in the way the M8N processes the GLONASS measurements.  Without getting into too many of the details, the issue is that normally when using two identical receivers, the GLONASS satellites can be used to solve the integer ambiguities, but with the M8N this is generally not true because of some additional error terms.  I have added a partial fix to my public branch of RTKLIB to calibrate out these errors after first fix.  If you are using the standard 2.4.3 version of RTKLIB, though, you will not have this capability, and either way you will not have this for the initial acquisition which means it will take a little longer with the M8N to get a good fix.

Most of the inexpensive M8N receivers are intended for use in drones and use a UART interface rather a USB interface.  This means you will need an FTDI type adapter to translate UART to USB and most likely will need to solder a few wires to get this hooked up.  You will find many choices available online for $15 to $40 per receiver including shipping.  These usually include an inexpensive, lower-performance antenna.  You will have to add $5-$15 for the FTDI adapter.  Still, you should be able to put together a pair of receivers fairly easily for under $75, less than half the cost of using the M8Ts.  If you are willing to wait for parts from China, you could do it for less than $50 for the pair.  Although not quite as capable as the M8Ts, if you are careful to collect good quality data and include a little more time for initial acquire, much of the time the results will be indistinguishable between the M8N and the M8T.

I have experience with three different M8N based receivers and have gotten good results with all three.  The first was from CSG Shop and while a perfectly good receiver I would not recommend it because the price is only ten dollars less than the M8T so if you are going to go that route, get the M8T.

The second receiver I have used is intended for drones and is marked as a GY-GPSV3-NEOM8N.  It is available from several suppliers, I bought it on Ebay for $25.78 including antenna and shipping.

The third type of receiver I have used is very similar but includes an on-board magnetometer.  It is labeled as GY-GPSV5-NEOM8N and sells for about $5 more than the GY-GPSV3-NEOM8N and is also available from multiple sources.  The magnetometer can be useful for collecting additional information about heading and orientation but I have not used it much yet.

Here’s a couple of other M8N receivers worth considering.  I have ordered both of them but have not had time to evaluate them yet.  For the very lowest cost and with an integrated receiver/antenna package, the unit on the left from ebay, shipped from China is  $16.65 including shipping.   The Reyax RY835AI unit on the right includes an accelerometer, gyroscope, and magnetometer with onboard antenna, all for $18.99 from Amazon Prime  (thanks to Ken McGuire for this suggestion).

[Update 12/6/16:  I have not tested the unit on the left yet but have verified the M8N module is counterfeit based on inconsistencies between the labels on this module and my other modules.  Preliminary testing of the Reyax unit was disappointing for me with low satellite count and low SNRs.  I suspect it may be because the antenna is passive unlike my other receivers that all have active antennas, but Ken has shown data with his receiver that looks much better so I’m not sure why the differences.  He has extended the ground plane on his unit but that doesn’t usually have a large enough effect to explain the differences I see.]

 

neom8n_dg 81yneho8uxl-_sl1500_

 

In summary, I would recommend the M8T receiver with a u-blox antenna for someone that has a specific application in mind and is looking for maximum performance and ease of setup.  However, the M8N with included antennas is how I got started and I still think it is a good choice for anyone that just wants to explore the capability of precision GPS without spending a lot of money.  It could also be a good choice for someone planning on building multiple units for a more price-sensitive application and is willing to work within it’s constraints.   Combining the M8N with a u-blox or other external antenna is another possibility that will put you somewhere in the middle for both capability and cost.