update on RTK-GPS

Back in 2014 I wrote a post on RTK-GPS using Navspark NS-RAW boards. Back then I promised to write a follow-up once I have done some testing. I didn’t quite think it would take so long but the reason behind the delay is that I never quite got it working as well as I expected and tried various things over the years which took time, and I lost interest couple of times in between.

A couple of people have asked me how it worked, so finally I decided that enough is enough and I’ll just describe how far I got.

TLDR version: NS-RAW in seems to perform significantly worse than the u-blox of the same era. Even if it had performed at a similar level, single frequency GNSS in general just seems to be unsuitable for reliable ground based robot navigation. It might work at some times of the day where the satellite visibility and geometry happens to be just right and you are testing in a large open field, have good antennas etc. but for most realistic cases it will not be reliably usable.


Navspark has this to say about the required conditions to be met for a stable RTK FIX:

NS-HP or NS-HP-GL are single frequency RTK receivers. For reliable consistent single-frequency RTK operation, they require 12 or more usable satellite signals above 15 degree elevation angle with SNR no less than 38dB/Hz.

NS-RAW is single-constellation so I’m limited to only GPS. Looking at the GNSS radar tells me 5-9 GPS satellites would be visible from my location at different times of the day (with 15 degree elevation). So 12 satellites would be impossible here. Other sources say that you need 7 satellites min. to get a RTK FIX solution (and min. 5 to hold it). That would have been a bit more realistic requirement, and besides, an earlier u-blox LEA-6T test got a FIX solution just fine so I decided to go on with the test.

Here’s what my test ground looks like:

The plot has 20m high forest in the N & NE directions. Other sides have better visibility but all the sides have at least one row of 20-30m trees + some sporadic buildings and trees all over the place.

BS1 is the original base station that was described in the previous post on the topic. It uses Satmar FME marine active GPS antenna. I have added a 15cm wide ground plane below it (a paint can lid). The location of BS1 is somewhat unfortunate since it is basically surrounded by some trees from all the sides. When I originally chose the location for the base station I didn’t have good access to the roof of the main building so I chose a spot that was furthest away from the house, so that it wouldn’t block satellites from that side. Here’s the picture of the location:

BS2 is the new base station at the top of the roof. It’s about 8m higher than BS1 and hence has better satellite visibility. Tri-Band GPS/Galileo, Beidou, GLONASS Active Antenna is used. It looks like this:

“Rover” is me walking around with a laptop and NS-RAW with an antenna setup identical to BS1.
Everything is connected over WIFI.

Best case – localization between two base stations

Using BS2 as base station and BS1 as rover in the Kinetic mode should give us a good idea of what is the best that can be achieved with this hardware on my plot. Even though BS2 doesn’t have good sky visibility it’s better than a real rover will ever have since it’s located on a pole that is a couple of meters higher than the rover will ever be, and has less sky blocked by the house than a rover normally would.

I finally got RTK working rather well in this scenario and it has FIX most of the time. The location stays in a ~5 cm^2 area for the 8h session:

I was cheating a bit though – for localizing static points I use Integer Ambiquity Res mode FIX and hold. This mode takes past measurements more into account when calculating the current location than Instantaneous or Continuous would, which makes position mode stable but would also make it return the wrong position for longer if the rover was actually moving. I also used demo5 ver. of RTKLIB by rtklibexplorer which got more FIX solutions than the mainline RTKLIB.

Driveway test

Next I walked up and down the driveway as a rover a couple of times to see if I can get comparable results to my u-blox test at the same location in 2013.

The results were not bad but worse than the earlier u-blox LEA-6T test:

There were lots of slips, large residuals and ambiguity validation failures in the RTKLIB logs. Most of these errors are said to be commonly caused by not having clear enough view of the sky and the consequent multipath errors.
This seem likely since the rover certainly didn’t have a great view of the sky from 2 sides and things seemed to get worse with stronger winds (when trees had leaves and these were moving a lot).

With that said, the driveway basically has the best visibility in my yard that a real rover could ever have, so this is the most optimistic-realistic scenario. Even though the common satellite count is really low and we seem to be in FLOAT mode half of the time, the points are reasonably close (~20-30cm) and it would be usable for real navigation if this precision were repeatable 24/7 all year round. This test was done in January so no leaves on the trees which probably reduced errors a bit and made it even more of a best-case scenario.

Rover circle

Now for a more realistic test – walking in a circle with 20m diameter in the middle of the yard in mid-summer when trees have leaves.

This looks rather bad, only 2.1% of the points have FIX solution. The FLOAT solution was reasonably precise for 3 circles and then suddenly wandered through the circle. We see that most of these points have a lower confidence than FLOAT points on the actual circle so we could filter those out on that basis, but we also see a single FIX solution point in that path which is a couple of meters away from the actual location.
This test was done with integer ambiquity res. set to continuous.


What next?

I have put the navigation project on hold for now. I expect L5 capable chips to be much more common in the next 2 years which along with new Galileo satellite launches should considerably improve the precision of navigation at my location (NE Europe). L5 should be much less prone to multipath problems that seemed one of the main things throwing my rover signal off. Broadcom 47755 is the first mass consumer L1/L5 chip and others will surely follow.

Finally here’s a list of relatively cheap alternatives to NS-RAW that are available right now and would be rather interesting to try in similar situation but not interesting enough for me to actually buy the test hardware:

  • My original tests in 2013 seemed to get much better results with LEA-6T so u-blox LEA-8T that is available for ~75$ per module might give better results. You would also be able to try out various hacks and configuration tweaks described in the awesome rtklibexplorer blog.
  • Navspark NS-HP series (NS-HP-GL, NS-HP-BD) might also give somewhat better results than NS-RAW since these have multi-constellation support. Having the ability to use Glonass satellites in addition to GPS would almost double the average number of visible satellites in my location. These chips also do RTK on board so you don’t have to have a separate computer for running RTKLIB which will save you both weight and power. They also claim significant improvements in environments like mine in the newer firmware versions.
  • u-blox M8P based boards might also be interesting, these are multi constellation (GPS, BD, Glonass) L1 chips that do RTK calculations on board so you only have to provide a communication link. Such boards are for example Tiny RTK from Drotek (~215€) or the one from CSG (~239€).
  • Drone operators seem to like Emlid Reach. Under the hood it’s a combo of u-blox M8T + Intel Edison for processing and RTKLIB with much friendlier frontends than bare RTKLIB has. It seems that some of their customers are happy with the results and others seem to almost never get a FIX solution.

After having read lots of forums of users trying to use these cheap single frequency RTK solutions, my conclusion so far is that it seems to require intimate knowledge of almost endless GNSS related stuff, a very good sky visibility, living in a place where satellite geometry is just right for large part of the time, good antennas and specific weather conditions. In short it doesn’t seem to be feasible for generic rover navigation that requires constant precision in the dm range in all corners of the yard.

esp8266 relay

Just some quick notes on using 5V esp8266 relay module. Manufacturers page seems to be this even though terminal and pin positioning on the pictures is a bit different.

For just ~2.4€ it will give you the ability to switch electrical loads over Wi-Fi 🙂

There are actually 2 basic designs floating around on Aliexpress. The one that I’m talking about here is where esp8266 module plugs into the mainboard through 8 pin connector like this:

The other one integrates esp8266 on the relay board directly.

From the shipping perspective this modular design is a bit unfortunate since cheap/free shipping from Aliexpress will usually arrive in normal soft envelopes that just have 1 layer of bubble wrap as a padding.

As a result all 3 boards that I ordered arrived looking like this:

Nevertheless they actually worked fine. I was probably just lucky though and I kind of like modular things more in principle.

Interesting thing about this modular design though is that the relay is actually controlled by the STC 15f104W MCU on the main board which is programmed to turn the relay on when it sees “\xa0\x01\x01\xa2” on its UART port and off when it sees “\xa0\x01\x00\xa1“.
That UART is accessible either through the 4 PINs between the screw terminals or input from the esp8266. So you can actually run it without the esp8266 and control the relay directly over UART PINs or even reprogram the 15f104w.

ESP8266 board comes flashed with esp8266 AT firmware which allows esp8266 to be controlled using AT commands on the serial port.

By default the module comes in AP mode which means that it will show up as an Wifi access point that you can connect to. I wasn’t really interested in that so I reconfigured it to connect as a client to my main wifi network.
To reconfigure ESP8266 you have to connect UART over the 4 pins between the screw terminals using an USB to UART TTL cable like this:

I just happened to have the 5V power supply also connected but it’s not really required at this step, just for reconfiguring power from USB should be enough.

This can be done like this:

$picocom -b 115200 --omap crcrlf /dev/ttyUSB5

After this, communications will switch from 115200 to 9600 baud so you will lose the link and would need to switch picocom to 9600 baud to do anything further. But anything else isn’t really required anyway for our simple use case, so just disconnect picocom with CTRL+A CTRL+X.

AT+CIFSR command should have printed out what is the IP of the module. In my case it looked like this:


Now you can just create a TCP connection to that IP at port 8080 and send the relay commands that I mentioned before. ESP8266 will pass these to the STC 15f104W MCU which in turn will control the relay.

As an example here’s a trivial python script that will connect to the relay and turn the relay on and off in an endless loop in 4s intervals:

import sys
import time
import socket
IP = ""
PORT = 8080
RELAY_OPEN_CMD = "\xa0\x01\x01\xa2"
RELAY_CLOSE_CMD = "\xa0\x01\x00\xa1"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
while 1:

And here’s how the result looks like:

pgconf.eu 2016

pgconf  2016.11.04 16:15:14

Since this year’s European PostgreSQL conference pgconf.eu happened to take place in my home country I just couldn’t pass the opportunity to go.
I’m not really a huge PostgreSQL user though — I mostly use it for personal projects, but have also done at least one rather unconventional proof-of-concept project on it at work (a largeish graph DB).

At work the main production databases that I’m currently responsible for (or have been in the past) are all based on MySQL/MariaDB, but this is mainly because these decisions were made 10+ years ago when the pros and cons of each choices were quite different than they are today. It’s rather likely that for all the new projects I would rather use PostgreSQL.

I won’t go over the talks one by one but rather share some general themes that I noticed.


There’s a German word Zeitgeist which loosely means the spirit of the time. I have begun to notice that at conferences there’s often some unifying subtopic of the project that is somewhat unproportionally important to the particular community at that time for some reason. For example at Europython 2010 the zeitgeist was all about concurrency and ways to get around the GIL. At Europython 2015 I barely heard anything about concurrency anymore, even though things at that front haven’t changed much in between — instead everyone was focused on data mining and scientific computing. So anyway I feel that at pgconf 2016 the central topic was replication. There were many talks exploring different approaches to replication and various master-slave switchover orchestration tools. It will be interesting to see what solution the community will settle on in the next couple of years.


PostgreSQL has been gaining a lot of popularity over the recent years, probably mainly because of the uncertainty related to MySQL after Oracle bought it. This also means that many commercial companies see opportunities in selling support/consultancy around postgres related things. In general for-profit companies tend to be interested in having something to differentiate themselves from the competition so they are somewhat inherently motivated to create custom extensions and solutions instead of working together. It certainly felt at the times that each company at the conference had a different solution for handling replication and cluster orchestration each with its own up- and downsides. Let’s just hope it doesn’t end with a full scale Unix wars scenario. PostgreSQL has always had a rather rich landscape of forks so maybe they have already learned to handle this somehow.

Where to do the complex stuff?

There were several talks about some of the more powerful constructs and capabilities of PostgreSQL from window functions, recursive CTEs, lateral joins, upserts, aggregate filters to various nosql capabilities, custom datatypes, foreign tables, operator overloading and support for countless programming languages.

Which brings us to a rather classical dilemma: should we use various powerful tools that the DB provides and be tied down to it as a result, or use the DB as a simple datastore and do the complex stuff in the app? I see it as a continuum where on one end you only use simple queries (probably through ORM) and on the other end you have monstrosities like Oracle APEX where even the application itself is in the DB.

The keynote speaker from Adyen said that he believes that the decision to avoid procedures, triggers etc. was the best tech decision they did even though it was for completely different reasons. My experience is more or less the same – I think a good rule of thumb is to avoid non-declarative features but be rather liberal with everything else.

Case studies

For me the most interesting talks at the conference were various talks about real system setups and problems encountered along the way. There were several of these types of talks, starting with the keynote delivered by Michiel Toneman from Adyen which is a quickly growing payment processing company currently serving ~60 billion payments per year. They have been undergoing exponential growth for years which has led to some rather interesting scaling problems. Their master database is currently over 40TB and has 11 tables with a size over 1TB. Their largest table is currently around 11TB. Michiel talked about the reasoning and complexities around choosing PostgreSQL for a payment processing company, which is in a field usually dominated by high cost proprietary databases like Oracle and Sybase. It was interesting that postgres usage at Skype had been kind of a validation that probably made it a acceptable choice elsewhere.

Another interesting talk was about problems that Skype has encountered with PostgreSQL. The interesting part for me was that even though we use MySQL we still have encountered most of the same problems. That’s because many of these problems were just something that you encounter when running DB under serious load (lock queues, small degradations in IO performance having snowball effects, lagging read replicas, cleaning up bloat etc.)

if it hurts, do it more often

For the last month or so me and my partner have taken cold showers in the morning. There are seemingly endless lists of benefits of this available on the Internet so I won’t bore you with another one. For me the main goals were to boost the immune system and to really wake up, both of which it really seems to provide.

It’s also a good exercise of willpower.

We have also extended our open water swimming period. Here’s a nice picture from today of the local bog lake (Kõnnu järv).
The air was at 15 degrees C and the water probably somewhere around 7 degrees C. After going in, there was this burning cold feeling but it’s kind of enjoyable in its own strange way. After coming out the air actually feels rather warm and there’s this strange heating feeling under the skin all over the body long afterwards.

good news everyone!

The Tom of Finland exhibition in Helsinki has been extended until 13.09.2016.

In addition to many Tom’s works there’s also this Tom-inspired 3D printed drinking fountain in the lobby:
Tom of Finland inspired drinking fountain

It wasn’t usable for its intended purpose for some reason but is still one of the best real uses of 3D printing I have seen so far.

There was also this drawing of a duck by Tom from his youth. As a duck keeper I have to say Tom’s tendency to exaggerate the sizes of certain body parts is indeed clearly visible.
Tom's duck

fixing the temperature sensor

As mentioned in my last post about cheap Chinese wireless temperature/humidity sensors, one of the three devices that I ordered was broken. It did show correct values on the local screen but no messages were seen over the radio link.

I decided to open it up to see if there’s anything obviously wrong inside. Here’s how the internals looked like:
insides of the temperature sensors

The 2 working sensors both had the blue radio module shown on the left and the non-working sensor had the white module shown on the right. Since I had RTL-SDR I decided to see if the broken module sends out any signal at all. I found a very detailed blog post describing the steps for doing it.

Here’s what my signals looked like:
sensor signals

The topmost signal is from the broken radio module as measured ~30cm from the antenna. The next one is the signal from the replacement radio module from the same distance and the last 2 signals are from the two other sensors which were located much further from the antenna.

As we can see the broken signal is rather unstable and can’t hold stable high.
It looks even more interesting when zoomed in:
sensor signals zoomed

Here’s how the sensor looks with the replacement radio module:

The fixed sensor works rather well, the signal is clear from ~20m away through 2 concrete floors.

cheap temperature sensors

I was kind of missing the fun temperature charts that I had at my previous home so I decided to get some sensors for the new house too. Using 1-wire network like I did previously didn’t seem reasonable this time around since my current house has 3 floors and cabling it in a way that wouldn’t be ugly would have taken too much effort.

So instead I decided to find some cheap wireless temperature sensors. It turns out you can get a reasonably looking temperature+humidity sensor with a local display and 433 Mhz radio for just 7€ a piece (with free shipping). You can also buy these sensors in a cheap kit with a central screen that shows values from all the senors plus some additional stuff like clock and sunrise times.

I wasn’t really interested in the central screen, so I just bought 3 sensors.
433Mhz temperature sensors

These sensors display humidity and temperature values on the screen and send out these measurements once a minute. When the sensor sends the message it blinks the red led in the front panel which might be a bit annoying if you place it somewhere where you can see it at night. I would probably tape it over or solder it off under these circumstances.
A switch inside the battery compartment allows you to select the channel which makes it possible to differentiate one sensor from another. The switch has 3 positions so it seems that with the normal central screen you are probably limited to 3 sensors. Technically this channel just changes a value in the message so it’s not a radio channel or something like that.

From the protocol perspective there’s also a 8 bit field called random id(rid) which is initialized when the sensor starts. Using the rid field alone or in conjunction with the channel value allows you to use far more sensors than 3. Since rid isn’t under your direct control it might take a bit of fiddling to find a free ID with a larger number of sensors and at some point you will probably have too many collisions in the air but I imagine using 10-20 of these sensors wouldn’t be a problem.

Since I didn’t buy the central screen I still needed a way to actually listen for the measurements that these sensors broadcast. It turns out cheap RTLSDR compatible DVB-T receivers can be used for that purpose with the RTL 433 application.
So I bought the receiver USB dongle with an external antenna and remote from ebay for ~10€.
rtlsdr dongle with antenna

Once RTL 433 is installed all you need to do to listen for the measurements is to run the rtl_433 command:

# rtl_433 -R 3 -F json
{"time" : "2016-02-13 23:10:19", "model" : "Prologue sensor", "id" : 5, "rid" : 55, "channel" : 2, "battery" : "OK", "button" : 0, "temperature_C" : 10.000000, "humidity" : 52}
{"time" : "2016-02-13 23:10:24", "model" : "Prologue sensor", "id" : 5, "rid" : 170, "channel" : 3, "battery" : "OK", "button" : 0, "temperature_C" : 23.400000, "humidity" : 29}
{"time" : "2016-02-13 23:10:33", "model" : "Prologue sensor", "id" : 5, "rid" : 51, "channel" : 1, "battery" : "OK", "button" : 0, "temperature_C" : 19.800000, "humidity" : 39}

This output can be easily interfaced to whatever system you use for home automation. My graphs look like this:
temperature on floor 2

My receiver is located on the second floor and the furthest sensor is about 20 meters away through 2 concrete floors and there don’t seem to be any communication problems so far.

One of the sensors came with a faulty radio that I had to replace, but more on that in a separate posting later.

iceskating on the bog pools

This winter started with a sudden cold wave without snow which created perfect conditions for cross-country skating.
Such as this clear and thick (~10cm) ice on our pond:

ice on pond

The pond is a bit small though for serious skating so we headed for the bogs.

Since about 20% of Estonia is covered with wetlands we have lots of bogs to choose from. My partner happens to be a bog enthusiast so we tend to go to different ones too.

Bog pools are nice for skating for a couple of reasons. They are usually shallower than lakes so they tend to freeze faster. Secondly bog pools form interesting systems with lots of nooks, crannys and islands which might be a bit more interesting than skating on a big lake.

We started with a skating trip to Suru Suursoo with 360.ee on the afternoon of New Year’s Eve. There we skated on two different bog pool systems, Tallekesejärv and Suursoo umbjärv:

Suursoo umbjärv

And here’s just a random picture of how nice the frozen bog looks like
Suru suursoo in the winter

Next day we went to Kõnnu järv which is located near our home. That one is more of a lake than bog pool:

skating on frozen Kõnnujärv

And finally we went to Mukri soo where we skated on Lake Eidapere.

skating on Eidapere järv

As you can see each successive picture has a bit more snow on it so it’s rather likely that by now there’s too much snow for skating. That’s really the only downside of cross country skating – the natural conditions suitable for it are present for a week or so per year and sometimes even less.