====== Raspberry Pi Explorer Kit ====== In this page I will tell you about some experiments that I made with the **[[http://aerocene.org/exploration-tools|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 **[[https://www.adafruit.com/product/2324|Adafruit Ultimate GPS HAT]]** for the Raspberry Pi * One Miuzei Raspberry Pi **camera module** (OV5647 sensor, 2592x1944 = 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: {{.:raspberrypi:aerocene_explorer_kit.jpg?direct&400|}} ===== 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 === {{ .:raspberrypi:raspberry_pi_cam_miuzei_ov5647.jpg?direct&180|Image captured by the OV5647 camera}} The camera mounted in our kit is based on the **OV5647 sensor**, capable of 2592x1944 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 ===== {{.:raspberrypi:sensors-front.jpg?direct&500|Misc sensors: GPS, Accel & Gyro, Magnetic, Pressure}} {{.:raspberrypi:sensors-back.jpg?direct&500|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 [[https://www.raspberrypi.org/downloads/raspbian/]]. 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 update_config=1 country=IT network={ ssid="MyESSID" psk="SuperSecret" key_mgmt=WPA-PSK } Those files will be seend by the bootstrap procedure and will configure the ssh and WiFi services. ==== raspi-config ==== 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 https://github.com/adafruit/Adafruit_Python_GPIO.git cd Adafruit_Python_GPIO python setup.py 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 address 169.254.255.198 netmask 255.255.0.0 ==== 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: START_DAEMON="true" USBAUTO="false" DEVICES="/dev/ttyAMA0" GPSD_OPTIONS="-n" 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 {"class":"VERSION","release":"3.16","rev":"3.16-4","proto_major":3,"proto_minor":11} {"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyAMA0","driver":"MTK-3301", "subtype":"AXN_2.31_3339_13101700-5632","activated":"2018-09-06T10:17:33.154Z", "flags":1,"native":0,"bps":9600,"parity":"N","stopbits":1,"cycle":1.00,"mincycle":0.20}]} {"class":"WATCH","enable":true,"json":false,"nmea":true,"raw":0,"scaled":false, "timing":false,"split24":false,"pps":false} $GPGGA,101734.000,4351.5026,N,01105.8562,E,2,11,0.84,35.1,M,47.6,M,0000,0000*5F $GPGSA,A,3,20,26,32,27,18,21,08,16,10,07,11,,1.34,0.84,1.04*0C $GPRMC,101734.000,A,4351.5026,N,01105.8562,E,0.27,348.07,060918,,,D*6E $GPZDA,101734.000,06,09,2018,,*52 $GPGGA,101735.000,4351.5025,N,01105.8562,E,2,11,0.84,35.1,M,47.6,M,0000,0000*5D $GPGSA,A,3,20,26,32,27,18,21,08,16,10,07,11,,1.34,0.84,1.04*0C $GPGSV,4,1,14,27,78,333,13,10,66,118,26,20,51,065,20,16,45,197,17*77 ==== 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 [[https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=909082|bug #909082]] on Debian. Changing the file name to be created, is a workaround for this problem. ===== GPS u-blox NEO-6 ===== {{.:raspberrypi:neo-6m-gps.jpg?direct&180|u-blox NEO-6 GPS with small antenna}} {{.:raspberrypi:neo-6m-gps_back.jpg?direct&180|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 | | 2 GND | PIN 6 - GND | | 3 TXD | PIN 10 - GPIO#15 UART0_RXD | | 4 RXD | PIN 8 - GPIO#14 UART0_TXD | | 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) server 127.127.28.0 fudge 127.127.28.0 refid GPS The magic pseudo-IP address **127.127.28.0** 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**: 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** ([[wp>Pulse-per-second_signal|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. dtoverlay=pps-gpio,gpiopin=4 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: ntpshmmon # 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 127.127.28.2 prefer fudge 127.127.28.2 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. server 127.127.28.0 fudge 127.127.28.0 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 **127.127.28.2** and **127.127.28.0** are not actual IP addresses, but codes referring the [[http://doc.ntp.org/4.2.8/refclock.html|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 **127.127.28.2** (shared memory driver instance #2) instead of **127.127.28.1** (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 *127.127.28.2 .PPS. 0 l 17 64 377 0.000 0.009 0.003 -127.127.28.0 .GPS. 0 l 16 64 377 0.000 144.112 26.009 -212.45.144.3 193.204.114.232 2 u 60 64 357 48.265 1.829 22.972 +212.45.144.206 193.204.114.232 2 u 38 64 377 47.864 0.490 22.703 -188.213.165.209 193.204.114.233 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: [[https://pthree.org/2013/11/05/real-life-ntp/|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 [[https://www.eecis.udel.edu/~mills/ntp/html/cluster.html|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 [[wp>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 127.127.28.0 and 127.127.28.1"// (i.e. the gpsd shared memory drivers). See **[[http://lists.nongnu.org/archive/html/gpsd-users/2016-08/msg00019.html|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 127.127.28.0 prefer fudge 127.127.28.0 time1 0.523 refid GPS flag1 1 # Instance #0 of the "PPS Clock Discipline (PPS)". # This driver access the /dev/pps0 kernel device directly. server 127.127.22.0 fudge 127.127.22.0 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 **[[https://www.ntpsec.org/white-papers/stratum-1-microserver-howto/|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: {{.:raspberrypi:pms5003_cable.jpg?400|}} 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 | | 4 RXD | Blue | TXD | PIN 8 - GPIO#14 UART0_TXD | | 5 TXD | Green | RXD | PIN 10 - GPIO#15 UART0_RXD | For the software part, we will install some scripts from the **[[https://github.com/RigacciOrg/AirPi|AirPi project]]** on GitHub: cd /usr/local/src git clone https://github.com/RigacciOrg/AirPi cd AirPi make install-lib Edit (create) the configuration file **/etc/airpi/airpi.cfg** with your settings: [pms5003] DEVICE: /dev/ttyUSB0 LOG_LEVEL: DEBUG AVERAGE_READS_SLEEP: -1 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.: AVERAGE_READS_SLEEP: 20 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 Pypi.org has a [[https://pypi.org/project/qmc5883l/|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 [[https://www.raspberrypi.org/forums/viewtopic.php?p=1102197#p1102197|this]] and [[https://www.raspberrypi.org/forums/viewtopic.php?t=184556|that]]). So I wrote my own Python module, named **py_qmc5883l** which is available on **[[https://github.com/RigacciOrg/py-qmc5883l|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 https://github.com/RigacciOrg/py-qmc5883l mkdir /usr/local/lib/python2.7/dist-packages cd py-qmc5883l python setup.py install Now you can access the magnetic sensor with a simple Python program: import py_qmc5883l sensor = py_qmc5883l.QMC5883L() m = sensor.get_magnet() print(m) ===== Web References ===== * [[https://www.adafruit.com/product/2324|Adafruit Ultimate GPS HAT for Raspberry Pi]] * [[https://cdn-learn.adafruit.com/downloads/pdf/adafruit-ultimate-gps-hat-for-raspberry-pi.pdf|Adafruit GPS HAT documentation]] * [[https://www.ntpsec.org/white-papers/stratum-1-microserver-howto/|Stratum-1-Microserver HOWTO]] * [[http://doc.ntp.org/4.2.8/drivers/driver28.html|NTP Shared Memory Driver]] * [[http://unixwiz.net/techtips/raspberry-pi3-gps-time.html|Building a GPS Time Server with the Raspberry Pi 3]] * [[https://www.raspberrypi.org/forums/viewtopic.php?t=140585|RPi as high precise NTP Server with GPS/PPS dev]] * [[http://www.catb.org/gpsd/gpsd-time-service-howto.html|GPSD Time Service HOWTO]] * [[https://pthree.org/2013/11/05/real-life-ntp/|Real Life NTP]] (here a {{.:raspberrypi:real-life-ntp.pdf|local copy}}). * [[http://www.danmandle.com/blog/getting-gpsd-to-work-with-python/|Use Python to read GPS data]] * [[https://www.raspberrypi.org/forums/viewtopic.php?t=102617|Add GPS Exif data in realtime]] === GPS + PPS falseticker problem === * [[http://lists.ntp.org/pipermail/questions/2011-December/031473.html|GPS NMEA offset with PPS]] * [[https://groups.google.com/forum/#!topic/comp.protocols.time.ntp/7_q0EO2aAZw|Single GPS/PPS time source gets marked as a falseticker]] * [[http://doc.ntp.org/4.2.8/miscopt.html|NTP Miscellaneous Commands and Options]] (e.g. //tos// and //tinker// options). === QMC5883L 3-Axis Magnetic Sensor === * [[https://github.com/RigacciOrg/py-qmc5883l|Python driver for qmc5883l by Niccolo Rigacci]] (working) * [[https://github.com/norges/qmc5883l|Python driver for qmc5883l by Fabian Mruck]] (not working) * [[https://www.raspberrypi.org/forums/viewtopic.php?p=1102197#p1102197|Wrong I2C Address]] * [[https://www.raspberrypi.org/forums/viewtopic.php?t=184556|GY-271 HMC5883L Compass Returning 0]] * [[https://github.com/kriswiner/MPU6050/wiki/Simple-and-Effective-Magnetometer-Calibration|Simple and Effective Magnetometer Calibration]] === Other Sensors === * [[https://forum.sparkfun.com/viewtopic.php?t=47880|LIS3DH Accelerometer with Raspberry Pi]] * [[https://www.instructables.com/id/how-to-use-the-ADXL345-on-Raspberry-pi/|How to Use the ADXL345 on Raspberry Pi]]