User Tools

Site Tools


Raspberry Pi Explorer Kit

In this page I will tell you about some experiments that I made with the Aerocene Explorarion Tools. I got an exploration kit consisting of the following parts:

  • The Raspberry Pi 2 Model B
  • One solar panel with litium-ion polymer battery (5000 mAh)
  • One Adafruit Ultimate GPS HAT for the Raspberry Pi
  • One Miuzei Raspberry Pi camera module (OV5647 sensor, 2592×1944 = 5 Mpixels)
  • One LogiLink USB WiFi dongle
  • Two BME280 pressure/temperature/humidity sensor
  • One Plantower PMS5003 particulate matter sensor
  • One USB-to-serial adapter

Here it is a photo of the prototype assembled into a plastic case:

Connecting the Hardware

Adafruit GPS unit

The Adafruit GPS unit communicates with the Raspberry Pi using the serial interface which is available on PIN 8 and PIN 10 of the Raspberry Pi, marked as GPIO14/UART0_TXD and GPIO15/UART0_RXD on many pinout schemes. The standrad Raspbian configuration allocate the serial line for a console (boot messages and login prompt), so a special configuration is required to free the serial line. The raspi-config tool will be used for this.

BME280 sensors

The BME280 sensors are mounted on small breakout modules, which provide the I2C and the power interface. The I2C bus is available on the Raspberry Pi at PIN 3 and PIN 5 marked as GPIO2/SDA1 and GPIO3/SCL1. We have to connect also a ground PIN and a power PIN. The breakouts we used are capable to use both 3.3 or 5.0 volt power available from the Raspberry Pi connector. To connect two sensors at the same time, they must use different I2C addresses, to change the default address 0x76 to the alternative 0x77 it is required to cut and solder a track on the breakouts circuit itself.

PMS5003 sensors

The Plantower PMS5003 particulate matter sensor has a serial interface and requires a 5 volt power. If the serial port of the Raspberry Pi is already taken by the GPS module, we have to provide anoter serial interface via an USB adapter. There are several cheap USB to serial adapter, which also provide a pin for the 5 volt power.

USB to serial adapter

As said above, we required this adapter to connect the PMS5003 sensor. The one we used is based on a Prolific Technology PL2303 chip (USB id 067b:2303), which is automatically detected by the Linux kernel and exposed as the /dev/ttyUSB0 serial device.

WiFi dongle

The WiFi connection is provided by a simple adapter based on the Ralink RT5370 chip (USB id 148f:5370). To operate the adapter we need the rt2870.bin firmware (non-free), which is shipped into the firmware-misc-nonfree package. The package is already installed into the default Raspbian Stretch Lite distribution.

Raspberry Pi Camera Module

Image captured by the OV5647 camera The camera mounted in our kit is based on the OV5647 sensor, capable of 2592×1944 pixels (5 Mpixels). The camera has a wide viewing angle of 175°. The camera requires a manual focus adjust, turning the lens mount clockwise or counerclockwise. The focus resulted a bit critical: trying to focus to infinity it resulted that the mere rotation of 1/16 of a turn, can mess-out the focus very badly. Also the quality of the pictures is not exceptional, they miss the crisp level that we would expect from a 5 Mpixels sensor.

Other Sensors

Misc sensors: GPS, Accel & Gyro, Magnetic, Pressure

Sensor's Back Side

  • GPS u-blox NEO-6
  • GY-521: MPU-6050 Accelerometer and Gyroscope
  • GY-273: QMC5883L 3-Axis Magnetic Sensor
  • GYBMEP: BME280 pressure, humidity and temperature sensor

Software Setup

We used a GNU/Linux box to download the software and to prepare the micro SD for the Raspberry Pi.

Installing the Raspbian Distribution

Download the Raspbian Stretch Lite 2018-06-27 distribution from Unzip and copy the file to the micro SD:

dd bs=4M if=2018-06-27-raspbian-stretch-lite.img of=/dev/sdc conv=fsync

To enable ssh and WiFi at the first Raspberry Pi bootstrap, we created two files into the first FAT partition of the micro SD. The first file must be named ssh and can be empty, the second file must be named wpa_supplicant.conf and should contain the credential to access your WiFi network:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev

Those files will be seend by the bootstrap procedure and will configure the ssh and WiFi services.


We used the raspi-config tool, which customizes several system configuration files and re-configure some installed packages. Once logged into the Raspberry via ssh, we gained root privileges with sudo su - and launched raspi-config, then we configured the following options:

  • Localisation Options
    • Change Locale
      • en_US.UTF-8
      • it_IT.UTF-8
    • Change Timezone
      • Europe/Rome
  • Interfacing Options
    • Camera (Yes)
    • I2C (Yes)
    • Serial
      • Login shell over serial (No)
      • Serial port hardware enabled (Yes)
  • Advanced Options
    • Memory Split 128 (suggested by raspistill)

The files changed by that configuration are (among others):

  • /boot/config.txt
  • /boot/cmdline.txt
  • /etc/timezone

Disable getty program on tty1

Once the console tty1 on serial line is disabled, be sure also to disable the getty program running on it (which provides the login prompt):

systemctl disable getty@tty1.service

Adding Extra Packages

To operate the hardware devices and to run our software, we need some extra packages, available from the Raspbian distribution. From the command line, using the root privileges, run:

apt-get update
apt-get upgrade
apt-get install git i2c-tools python-dev python-setuptools python-spidev
apt-get install gpsd gpsd-clients python-gps pps-tools ntp ntpstat
apt-get install busybox-syslogd
apt-get install nginx php7.0-fpm
apt-get install ssmtp at

Other required software is not included into the official Raspbian distribution, so we will download (and install) from a GitHub respository:

cd /usr/local/src/
git clone
cd Adafruit_Python_GPIO
python install

This procedure will download and install the Adafruit_Python_GPIO library and the pre-required Adafruit_PureIO library. The destination directory of the installation is /usr/local/lib/python2.7/dist-packages/.

Beware to install setuptools and spidev from the official Raspbian packages before this setup procedure, otherwise the procedure will try to download and install those libraries from extra respositories, possibly messing the things a bit.

Removing Some Packages

The system will run mainly headless (without a monitor attached) and without Bluetooth devices. To avoid unnecessary bootstrap delay and errors, we removed some packages:

dpkg --purge plymouth mountall pi-bluetooth

Configuring the Network

Once configured the /etc/wpa_supplicant/wpa_supplicant.conf file, the wlan0 interface will simply work. If an Ethernet cable is plugged-in, the dhcp will bring up the eth0 interface with a suitable address. But if the Raspberry is bootstrapped without a reachable WiFi and without an Ethernet cable, a very long timeout will occur (over 5 minutes) and some services will not start (e.g. the Samba nmbd).

To avoid such troubles, we can just configure a static IP alias for the interface eth0:0 by creating a file /etc/network/interfaces.d/local with the following:

auto eth0:0
iface eth0:0 inet static

Nginx Webserver

To enable the PHP, edit /etc/nginx/sites-available/default, add index.php to the index list and enable the php7.0-fpm.sock part.

We want that Nginx write log messages into memory instead of microSD files (we are running busybox-syslogd). This was not possibile with Nginx 1.6.2 (Raspbian Jessie) but it is possible with Nginx 1.10.3 (Raspbian Stretch), so we changed the file /etc/nginx/nginx.conf in this way:

http {
    #access_log /var/log/nginx/access.log;
    #error_log /var/log/nginx/error.log;
    access_log syslog:server=unix:/dev/log;
    error_log syslog:server=unix:/dev/log;

Hardware Setup and Test

Adafruit GPS

Run the dmesg command and verify that the kernel detected the serial device /dev/ttyAMA0 (this is for the Raspberry Pi 2 models). Use raspi-config as explained above, to enable the serial line and let it free.

The quickest approach to set the serial line parameters at boot time is to edit the /etc/rc.local file and add this one-line command:

# Set serial line for GPS device.
stty -F /dev/ttyAMA0 raw 9600 cs8 clocal -cstopb

Edit the /etc/default/gpsd file and set:


restart the gpsd service:

systemctl restart gpsd.service

Notice that recent implementations of gpsd (as the one provided by the Raspbian Stretch distro) do not start the gpsd daemon automatically at bootstrap. Instead they start an Unix socket (/var/run/gpsd.sock) and listen there for incoming client connections. Beside that, they terminate the gpsd instance if no clients are connected for some time.

We need instead an ever-running gpsd, because it will provide precise clock information via shared memory to the ntpd daemon. For this purpose the -n option will prevent gpsd to terminate if no clients are connected. We need also to launch a client at least for a short time to fire-up the gpsd instance, e.g. adding this single line in /etc/rc.local:

# Start a gpsd client for a short time, so that gpsd will be started.
gpspipe -r -n 5 > /dev/null 2>&1 &

Now you can verify that the GPS is running and providing position data (place the device in open sky view, it does not work in a closed room!):

gpspipe -r -n 10

gpxlogger bug

I use gpxlogger (from the gpsd-clients Debian package) to acquire track logs from the GPS. It seems that the program has a bug handling the -f option, sometimes it crashes with the error free(): invalid next size (fast). I opened bug #909082 on Debian. Changing the file name to be created, is a workaround for this problem.

GPS u-blox NEO-6

u-blox NEO-6 GPS with small antenna u-blox NEO-6 GPS back view

A cheap alternative to the Adafruit Ultimate GPS HAT is the u-blox NEO-6 GPS module. It has a serial interface and a pin to carry the PPS signal.

u-blox Raspberry Pi
1 VCC PIN 2 - 5V
5 PPS PIN 7 - GPIO#7

Time Syncronization with GPS and NTP

The gpsd daemon provides time syncronization data via shared memory, and the ntpd daemon is able to read that information and adjust system time. This is very important because the Raspberry Pi does not have a RTC (realtime clock), so it does not have the correct system time at bootstrap. The ntpd can get time from the network and/or from gpsd, just edit the /etc/ntp.conf file and add the following, after the pool information:

# GPS Serial data reference (NTP0)
fudge refid GPS

The magic pseudo-IP address is not a real IP address, it identifies the ntpd shared-memory driver connected to the serial data given by gpsd.

You can verify that shared memory information are available for NTP, using ntpshmmon:

#      Name   Seen@                Clock                Real               L Prec
sample NTP0 1536230152.827339676 1536230152.627168673 1536230152.000000000 0  -1
sample NTP0 1536230153.638095698 1536230153.637403780 1536230153.000000000 0  -1

GPS time is very accurate, but serial communication from GPS device and gpsd is not. A means to get a more precise timing is activating a PPS (Pulse per second) signal. The Adafruit GPS HAT can provide PPS on GPIO 4 and the Linux kernel must be instructed to read that signal, add the following line at the end of /boot/config.txt file:

# Enable GPS PPS (Pulse Per Second) kernel device, drived by GPIO#14.

At the next reboot the kernel modules pps_core and pps_gpio will be loaded and you should read the following kernel logs via dmesg:

pps_core: LinuxPPS API ver. 1 registered
pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <>
pps pps0: new PPS source pps@4.-1
pps pps0: Registered IRQ 169 as PPS source
pps_ldisc: PPS line discipline registered
pps pps1: new PPS source ttyAMA0
pps pps1: source "/dev/ttyAMA0" added

the important part is pps0: new PPS source pps@4 stating that a /dev/pps0 device is created, exposing the PPS signal from GPIO#4. When the GPS has a fix, we can check that the PPS source is working with ppstest (from the pps-tools package):

ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1537517136.001471057, sequence: 787 - clear  0.000000000, sequence: 0
source 0 - assert 1537517137.001467380, sequence: 788 - clear  0.000000000, sequence: 0

We can see one PPS signal per second, as expected. Now we need to instruct gpsd to get data from that device too, not only from the serial line. Edit /etc/default/gpsd and set:

DEVICES="/dev/ttyAMA0 /dev/pps0"

Restart the gpsd service and check that bot time sources are availables via shared memory:

#      Name   Seen@                Clock                Real               L Prec
sample NTP2 1537596317.998856273 1537596284.999277455 1537596285.000000000 0 -20
sample NTP0 1537596318.371946497 1537596318.371124108 1537596318.000000000 0  -1

you should see both NTP0 (GPS via serial line) and NTP2 (PPS via GPIO) time sources. This configuration is available with gpsd 3.16 and ntp 4.2.8; it works letting gpsd to combine the GPS NMEA data with the PPS provided by the GPIO signal (via kernel device /dev/pps0) and write it in shared memory as an already cooked time source.

Finally we have to instruct ntpd to use both sources; in /etc/ntp.conf write the lines:

# Instance #2 of the "Shared Memory Driver (SHM)".
# Filled by gpsd (under the name NTP2) with a combination of GPS NMEA
# serial data and PPS reference from /dev/pps0 kernel device.
# To allow long-distance initial jumps (skip limit check), "flag1" is set.
server prefer
fudge refid PPS flag1 1

# Instance #0 of the "Shared Memory Driver (SHM)".
# Filled by gpsd (under the name NTP0) with GPS NMEA serial data.
# A very high average offset is compensated with the "time1" option.
fudge time1 0.523 refid GPS

# Minimum distance used by the selection algorithm, default is .001 s.
# Need to increase largely to allow combining GPS (serial) and PPS (GPIO)
# sources. GPS jitter is near 100 ms.
tos mindist 0.100

here again and are not actual IP addresses, but codes referring the drivers included into ntpd. The first one reads shared memory under the name NTP2, where there is data cooked by gpsd combining NMEA serial data with PPS signal from kernel device /dev/pps0 (the GPIO line). The second reference source reads shared memory under the name NTP0, getting NMEA serial data provided by gpsd too. Despite they are the same hardware, two sources are required so that ntpd can apply its standard NTP protocol.

We have to use (shared memory driver instance #2) instead of (instance #1), because instance #2 is the one filled by gpsd when is running as non-root user.

The options fudge time1 and tos mindist resulted to be necessary to allow ntpd to succeeed in the NTP algorithm and to decide to sync the system time. Infact GPS serial data have so large offset and jitter values, that it is normally discarded by the NTP algorithm. See below about the falseticker problem.

Restart the ntp service. After several minutes (about 20), we can check the NTP status with ntpq:

ntpq -p -n
     remote           refid      st t when poll reach   delay   offset  jitter
 0.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.001
 1.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.001
 2.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.001
 3.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.001
*    .PPS.            0 l   17   64  377    0.000    0.009   0.003
-    .GPS.            0 l   16   64  377    0.000  144.112  26.009
-  2 u   60   64  357   48.265    1.829  22.972
+  2 u   38   64  377   47.864    0.490  22.703
-  2 u   53   64  377   56.702   -0.123  22.437

Notice the .GPS. and .PPS. refid lines: they are the GPS time sources. Verify the reach field: that number must be greather than zero, meaning that the source is reachable. The output of the ntpq command is explained in this page: Real Life NTP.

The offset field is the difference in milliseconds (using root mean squares) between the client server and the source, the jitter indicates the root mean squared deviation of that offsets, in milliseconds.

The single character at the right of the remote name is an * for the PPS source, this means that the source was choosed as the sync peer, it was infact marked as prefer in the configuration file. There is not the character o in front of the PPS source, which should be the one displayed for PPS sources. This is because we did not use the PPS Clock Discipline driver of ntpd, but the Shared Memory one (see below for an alternative configuration). The - in front of the GPS time source, means that it was discarded by the cluster algorithm; this is because the reference source have so high offset and jitter (it is async serial data!), that network NTP servers are preferable. When the network is not available, ntpd should syncronize with both the PPS and GPS time sources, marking them with the characters * and + respectively. If, instead, you see an x in front of the GPS time source, it means that it was discarded by the Intersection algorithm, indicating that the time1 and/or mindist parameters should be adjusted).

Alternative: using different drivers for GPS and PPS

The one seen above, should be the preferred configuration of gpsd/ntpd, despite ntpd will not be aware that it is using a PPS source. Infact Gary E. Miller (a main gpsd developer) says: “If you are using gpsd and ntpd together your should ONLY be using refclocks and” (i.e. the gpsd shared memory drivers). See this post.

The alternative is to let ntpd to access the /dev/pps0 device directly (as a pure PPS signal, not cooked with NMEA data by gpsd). In this way ntpq will clearly show that we are using a PPS time reference, because it display the o character in front of it. Unfortunately ntpd is less suited in combining the pure PPS signal with the GPS NMEA serial data.

In /etc/ntp.conf declare the two reference sources:

# Instance #0 of the "Shared Memory Driver (SHM)".
# Filled by gpsd (under the name NTP0) with GPS NMEA serial data.
# A very high average offset is compensated with the "time1" option.
# To allow long-distance initial jumps (skip limit check), "flag1" is set.
server prefer
fudge time1 0.523 refid GPS flag1 1

# Instance #0 of the "PPS Clock Discipline (PPS)".
# This driver access the /dev/pps0 kernel device directly.
fudge refid PPS

# Minimum distance used by the selection algorithm, default is .001 s.
# Need to increase largely to allow combining GPS (serial) and PPS (GPIO)
# sources. GPS jitter is near 100 ms.
tos mindist 0.100

Notice that the first reference is of type shared memory (127.127.28.x) and the second is of type PPS Clock Discipline (127.127.22.x).

A More Powerful Alternative

As described by the Stratum 1 Microserver HOWTO, the stock ntpd software is not well suited to build a stratum 1 timeserver, we should instead use an improved version called NTPsec. The above HOWTO describe how to compile the code yourself, or may be you can wait untill the package (now in Debian Testing) will arrive in a future version of Raspbian.

GPS and PPS Falseticker Problem

We tried to use ntpd with only two local time sources: the standard GPS serial data and the GPIO PPS signal. Network connectivity to other peers was blocked. In the long run we find the system with no valid time sources: both .GPS. and .PPS. are marked by ntpq with the x character, meaning they were discarded by the intersection algorithm:

ntpq -pn
     remote           refid      st t when poll reach   delay   offset  jitter
x127.127.28.0    .GPS.            0 l   24   64  377    0.000  -67.198   9.930
x127.127.22.0    .PPS.            0 l   26   64  377    0.000   24.897   5.913

GPS data has a very low rate (one timestamp per second), it is sent over the slow and asyncronous serial line; so it has very high offset and jitter values. Roughly speaking, offset is the average distance between GPS timestamp and system clock, jitter is the variability of such distance. To solve the falseticker problem we need to compensate the offset and allow a so large jitter; in this way ntpd can combine the two time sources with the NTP algorithm and provide a reliable system time.

After some hours of system running, ntpq show an offset for the .GPS. source of about -450 milliseconds and a jitter sometimes over 70 milliseconds. We need to change /etc/ntp.conf adding the time1 option to compensate for the offset and adding the tos mindist option to allow a so large jitter in the combine algorithm, as seen in the above example configuration file.

PMS5003 Sensor

First of all we need to build a cable to connect the Plantower PMS5003 sensor to the standard 2.54 mm pins of the Raspberry Pi (or the USB to serial adapter). I used the little cable provided with the sensor and some spare cables with Dupont female connectors, I had to solder and insulate with heat shrink tubing. Here it is a photo:

You can connect the PMS5003 through a Serial/USB adaptor or directly to the Raspberry Pi. This table will help you:

PMS5003 Pin Color To Serial/USB… …or direct to the Raspberry Pi
1 VCC Violet +5V PIN 2 - 5V
2 GND Orange GND PIN 6 - GND
5 TXD Green RXD PIN 10 - GPIO#15 UART0_RXD

For the software part, we will install some scripts from the AirPi project on GitHub:

cd /usr/local/src
git clone
cd AirPi
make install-lib

Edit (create) the configuration file /etc/airpi/airpi.cfg with your settings:

DEVICE: /dev/ttyUSB0

We are ready to read data from the sensor, just launch the script /usr/local/lib/airpi/pms5003:

2018-09-13 09:35:57 INFO Sending wakeup command
2018-09-13 09:35:59 INFO Waiting 40 seconds for sensor to settle
2018-09-13 09:36:53 DEBUG Got valid data frame:
 PM1.0 (CF=1) μg/m³: 12;
 PM2.5 (CF=1) μg/m³: 16;
 PM10  (CF=1) μg/m³: 17;
 PM1.0 (STD)  μg/m³: 12;
 PM2.5 (STD)  μg/m³: 16;
 PM10  (STD)  μg/m³: 17;
 Particles >  0.3 μm count: 2154;
 Particles >  0.5 μm count: 632;
 Particles >  1.0 μm count: 56;
 Particles >  2.5 μm count: 9;
 Particles >  5.0 μm count: 2;
 Particles > 10.0 μm count: 0;
 Reserved: 0x91 0x00;
 Checksum: 709;
2018-09-13 09:36:53 INFO Got 16 valid readings, calculating average
2018-09-13 09:36:53 INFO Exiting main loop

The script, after 16 valid reads from the sensor, calculates the values average, writes them into the /var/run/pms5003.status file, and then exits. If you want the script to run in continous loop, set the option AVERAGE_READS_SLEEP to the interval in seconds between consecutive reads, e.g.:


Beware that if the sleep time is lower than three times the sensor settling time (default 40 x 3 = 120 seconds), the sensor fan will not be stopped between each read, so be prepared for a shorter life of the sensor.

GY-273 QMC5883L 3-Axis Magnetic Sensor

The GY-273 magnetometer is based upon the QMC5883L chip, which is similar to the HMC5883L one.

PMS5003 Pin Color Raspberry Pi
1 VCC Red PIN 1 - 3.3V
2 GND Black PIN 9 - GND
3 SCL Yellow PIN 5 - SCL
4 SDA Green PIN 3 - SDA
5 DRDY Not Connected

Connect the device, enable the I2C bus using raspi-config and install the i2c-tools package. You should see the device at address 0x0d of the bus:

i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- 0d -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

GitHub and has a Python driver by Fabian Mruck, which unfortunately does not work for me, it returns always [0, 0, 0]. Also the software existing for the HMC5883L chip is not compatible, according to several posts (see this and that).

So I wrote my own Python module, named py_qmc5883l which is available on GitHub py-qmc5883l repository. To access the I2C bus it requires the python-smbus package. The full recipe is:

apt-get install python-smbus
cd /usr/local/src
git clone
mkdir /usr/local/lib/python2.7/dist-packages
cd py-qmc5883l
python install

Now you can access the magnetic sensor with a simple Python program:

import py_qmc5883l
sensor = py_qmc5883l.QMC5883L()
m = sensor.get_magnet()

Web References

GPS + PPS falseticker problem

QMC5883L 3-Axis Magnetic Sensor

Other Sensors

doc/appunti/hardware/raspberry_explorer.txt · Last modified: 2018/11/26 08:42 by niccolo