Raspberry Pi GPS

Raspberry Pi Embedded Cap With GPS & 10DOF

In this post we will show you how to geotag and capture the “attitude”  of photos taken with the Raspberry Pi camera and record these values within the photo itself using EXIF metadata

We used a modified (hacked?) cap to take the images in this post. The cap took photos, geo-tagged and recorded attitude as we walked around Sydney Harbour.

Components used were;

  • Raspberry Pi Zero W
  • BerryGPS-IMU
  • Raspberry Camera V2
  • A cap

The BerryGPS-IMU was used to capture the GPS coordinates as well as “attitude”.   No external antenna was needed as the BerryGPS-IMU includes an internal antenna.

The “attitude” would include values such as pitch, roll, direction. Some of this data you can see annotate in the image below.

raspberry pi camera gps

Other programs can use some of this data to plot the image on a map and even show the direction of the camera at the time the image was taken.  A good example of this is seen in  GeoSetter

Camera attitude


The Cap

The cap has the BerryGPS-IMU sitting on top of the visor, with the Raspberry Pi sitting under the viso.  Some holes where made in the visor to allow connectivity between the BerryGPS-IMU and Raspberry Pi.
We also created a basic camera mount out of 3mm laser cut acrylic. M2.5 Nylon screws were used to hold everything in place.
Raspberry Pi GPS


Setup Raspberry Pi

  1. Configure your Raspberry Pi to work with a GPS module on the BerryGPS-IMU. Use this guide.
  2. Configure your Raspberry Pi so it can use the IMU on the BerryGPS-IMU, this guide can be followed.
  3. Confirm you Raspberry Pi camera module is working.
  4. Install exiftool and imagemagick

    exiftool  is used to update the metadata within the image.

    The convert utility that comes with imagemagick will be used to annotate the photos.

    pi@raspberrypi ~ $ sudo apt-get install exiftool imagemagick-y
  5. Configure exiftool

    The current specification of EXIF metadata  doesn’t include a field for roll or pitch, we can however add these using custom fields. You will need to create a exiftool config file in the home directory, where we will define the custom tags for GPSPitch and GPSRoll.

    pi@raspberrypi ~ $ nano ~/.ExifTool_config

    Copy the text in below

    # exiftool config file
    %Image::ExifTool::UserDefined = (
    # GPS
        'Image::ExifTool::GPS::Main' => {
            0xd000 => {
                Name => 'GPSPitch',
                Writable => 'rational64s',
            0xd001 => {
                Name => 'GPSRoll',
                Writable => 'rational64s',
  6. Test exiftool

    You can now test exiftool by adding some exif metadata to an image and then view this data.


    pi@raspberrypi ~ $ exiftool -GPSRoll=123.45 photo.jpg


    pi@raspberrypi ~ $ exiftool -GPSRoll* photo.jpg
    GPS Roll : 123.45

    This is what it looks like when the image is geotagged and attitude added.

    pi@raspberrypi ~ $ exiftool -GPS* image_20170624_023731.jpg

    GPS Version ID                  :
    GPS Latitude Ref                : South
    GPS Longitude Ref               : East
    GPS Altitude                    : 12.2 m
    GPS Time Stamp                  : 02:37:37
    GPS Img Direction Ref           : Magnetic North
    GPS Img Direction               : 45.58
    GPS Date Stamp                  : 2017:06:24
    GPS Pitch                       : 11.34
    GPS Roll                        : 26.66
    GPS Date/Time                   : 2017:06:24 02:37:37Z
    GPS Latitude                    : 33 deg 51' 17.81" S
    GPS Longitude                   : 151 deg 12' 36.73" E
    GPS Position                    : 33 deg 51' 17.81" S, 151 deg 12' 36.73" E

Connect GPS fix pin to GPIO on the Raspberry Pi

We will use a bash script which will start when the Raspberry Pi boots and it will be configured to take a photo every 120 seconds.
Once the photo has been taken, it will be updated with attitude (roll,pitch and direction) and if we have GPS fix, it will also add the GPS coordinates.

To detect that the GPS has a fix, you will need to connect the fix pin on the BerryGPS-IMU(shown below) to a GPIO pin on the Raspberry Pi. We will use GPIO  21 (physical pin 40) in this guide.

GPS Raspberry Pi

Taking photos automatically and updating metadata

As the Raspberry Pi, BerryGPS-IMU and camera will all be sitting on our head (with the cap), we will need to use a bash script to take the photos automatically.  We will set it to take one very 2 minutes.

The script will also detect if the BerryIMU has a GPS fix and update the image with GPS data.

    1. Download the code used to read pitch, roll and the direction from the IMU on the BerryGPS-IMU.

      pi@raspberrypi ~ $ wget ozzmaker.com/downloads/berryIMU.py
      pi@raspberrypi ~ $ wget ozzmaker.com/downloads/LSM9DS0.py

      Test the python code you just downloaded.

      pi@raspberrypi ~ $ python berryIMU.py
      {“Roll”:”8.97″,”Pitch”:”-2.39″, “tiltCompensatedHeading”:”334.57″}
      {“Roll”:”12.64″,”Pitch”:”-2.99″, “tiltCompensatedHeading”:”335.06″}
      {“Roll”:”14.24″,”Pitch”:”-3.01″, “tiltCompensatedHeading”:”335.05″}
      {“Roll”:”14.86″,”Pitch”:”-3.50″, “tiltCompensatedHeading”:”334.32″}
      {“Roll”:”14.87″,”Pitch”:”-3.43″, “tiltCompensatedHeading”:”334.95″}
      {“Roll”:”14.89″,”Pitch”:”-3.84″, “tiltCompensatedHeading”:”334.51″}
      {“Roll”:”14.87″,”Pitch”:”-3.63″, “tiltCompensatedHeading”:”335.25″}
      {“Roll”:”14.82″,”Pitch”:”-3.68″, “tiltCompensatedHeading”:”334.76″}
      {“Roll”:”15.20″,”Pitch”:”-3.71″, “tiltCompensatedHeading”:”334.26″}
      {“Roll”:”15.10″,”Pitch”:”-3.52″, “tiltCompensatedHeading”:”334.93″}

      This python code reads the angles from the IMU ten times and prints them out a JSON readable format. The last line contains the values we be adding to the metadata of the photo.

    2. Download the main bash script which will be doing all the work and set it to executable.

      pi@raspberrypi ~ $ wget ozzmaker.com/downloads/takephoto.sh
      pi@raspberrypi ~ $ chmod +x takephoto.sh

      Below is a copy of the bash script;

      #Setup GPIO21 as input. GPIO21 will be used to detect if the GPS has a fix.
      echo "21" > /sys/class/gpio/export
      echo "in" > /sys/class/gpio/gpio21/direction
      while true; do
        #Check to see if GPS has a FIX.  GPS fix pin will go high every 1 sec if there is a fix.
        FIX="NO"  # Reset fix condition
        #Stay in this 'while' loop if there is no fix and less than two secands have passed.
        while [ $FIX == "NO" ] && [ $(($SECONDS  - $START_TIME)) -lt 2 ]; do
          fixcheck=$(cat /sys/class/gpio/gpio21/value)      #GPIO21 is connected to the fix indication pin on BerryGPS-IMU
          if [ "$fixcheck" == "0" ]; then
        #If there is a fix, grab all the relevant GPS data
        if [ $FIX == "YES" ]; then
              tpv=$(gpspipe -w -n 10 | grep -m 1 TPV)
              latitude=$(echo $tpv | python -c 'import sys, json; print json.load(sys.stdin)["lat"]')
              longitude=$(echo $tpv | python -c 'import sys, json; print json.load(sys.stdin)["lon"]')
              altitude=$(echo $tpv | python -c 'import sys, json; print json.load(sys.stdin)["alt"]')
              speed=$(echo $tpv | python -c 'import sys, json; print json.load(sys.stdin)["speed"]')
              time=$(echo $tpv | python -c 'import sys, json; print json.load(sys.stdin)["time"]')
              #Convert latitude and longitude to 5 decimal places
              latitude=$(printf "%0.5f\n" $latitude)
              longitude=$(printf "%0.5f\n" $longitude)
        #Get angles and heading from the IMU
        attitude=$(sudo python /home/pi/berryIMU.py | tail -1)
        roll=$(echo $attitude | python -c 'import sys, json; print json.load(sys.stdin)["Roll"]')
        pitch=$(echo $attitude | python -c 'import sys, json; print json.load(sys.stdin)["Pitch"]')
        heading=$(echo $attitude | python -c 'import sys, json; print json.load(sys.stdin)["tiltCompensatedHeading"]')
        #Create file name with current time
        FILE="/home/pi/image_$(date +%Y%m%d_%H%M%S).jpg"
        #Remove old file
        sudo rm -f /home/pi/image.jpg
        #Take photo
        sudo raspistill -o /home/pi/image.jpg  -ex auto -w 1280 -h 720 --nopreview  --rotation 180
        #Add GeoTags and attitude to bottom of image and save with new file name
        if [ $FIX == "YES" ];then
              cmd="convert /home/pi/image.jpg -gravity SouthEast -stroke '#000C' -pointsize 24 -strokewidth 2 -annotate 0 'Lat: $latitude $
              #If you dont want to annotate the photos with the metadata, comment out the above line and use the line below.
              #cmd="convert /home/pi/image.jpg   $FILE"
              eval $cmd
              #Update the photo with all the relevant exif metadata
              exiftool -fast -fast2 -overwrite_original_in_place '-gpstimestamp<${DateTimeOriginal}+1:00' '-gpsdatestamp<${DateTimeOrigina$
              #As there isnt a GPS fix, only add roll,pitch and direction.
              cmd="convert /home/pi/image.jpg -gravity SouthEast -stroke '#000C' -pointsize 24 -strokewidth 2 -annotate 0 'Pitch: $pitch R$
              eval $cmd
              #Update EXIF information
              exiftool -fast -fast2 -overwrite_original_in_place -GPSroll="$roll" -GPSpitch="$pitch" -GPSImgDirectionRef="m" -GPSImgDirect$
        #Delay loop, set to how often you want a photo to be taken
        while [ $(($SECONDS  - $START_TIME)) -lt 120 ]; do
              sleep 1

      Detailed description of the important sections in the script:

      • Lines 11 to 21
        In this while loop we test to see if there is a GPS fix. The fix pin on the BerryGPS-IMU is connected to GPIO21 on the Raspberry Pi. If there is a GPS fix, this pin will go high once a second. The loop will continue to check for 2 seconds, if the pin doesn’t go high within 2 seconds, the $FIX = NO and we exit the loop
      • Lines 23 to 35
        If there is a fix, we need to grab all the relevant GPS data. On line 25, gpspipe is used to get the last ten NMEA sentences from the GPS, we then grep this to get one line which matches TPV. This will have all the coordinates needed outputted in JSON format, which is stored in $tpv. Here is an example


        We then use the python command line to parse the JSON data in $tpv and separate the GPS data into individual variables.
        Line 33 and 34 will limit the latitude longitude values to 5 decimal places.

      • Lines 37 to 41
        This is where we read the attitude values from the IMU. The output of BerryIMU.py is in JSON format, so we use python to separate all the values stored in $attitude.
      • Lines 56 to 60.
        This is where the photo is annotated with GPS and attitude data. The convert utility from imagemagick is used to perform this
      • Line 63
        exiftool is used to update the metadata on the photo.
      • Lines 77 to 79
        This loop is used to create a delay. Currently the delay is set to 120 seconds and the loop will only exit once 120 seconds have past since the start of the main loop.

        BerryGPS Raspberry Pi GPS

    3. Automatically run the script when the Raspberry Pi boots.

      To do this, we need to edit rc.local

      pi@raspberrypi ~ $ sudo nano /etc/rc.local

      Just before ‘exit 0’, add the two lines below;

      su pi -c '/home/pi/takePhoto.sh >> /tmp/takePhoto.log 2>&1 &'
      su pi -c 'gpspipe -r  > /home/pi/`date +"%Y%m%d%h%m%s"`.nmea'

      The first line will run the script which will take the photos. it will also log any output to a log file.
      The second like will record the NMEA sentences from the GPS, which can be used later to plot out the route.

  1. Viewing your Photo

    Geosetter (Windows only)is a great free tool which can be used to view geotagged photos.
    Save your photos and your route (.NMEA ) files into the same folder and open Geosetter and selected ‘Images’ ‘Open Folder’

You can also use the convert utility to straighten the horizon on an image by using the pitch value.

Here is the original;

Opera House
We can use exiftool to look at the metadata to see what the roll is.

pi@raspberrypi ~ $ exiftool -GPSRoll image_20170624_023906.jpg
GPS Roll : 12.09

The roll is 12.09. Now we can use convert to rotate the image by this amount to straighten the horizon.

pi@raspberrypi ~ $ convert -rotate 12.09 -background black image_20170624_023906.jpg output.jpg



7 thoughts on “Raspberry Pi Embedded Cap With GPS & 10DOF”

  1. Could this be adapted to record video with the BerryGPS-IMU data overlayed onto the recording? I’d like to attach to a rocket!

  2. Hi Mark,

    Is the link to “Takephoto.sh” broken? And are a few of the lines of the script truncated in the copy posted above? Any chance of getting a copy of the complete script? Thanks!

  3. Hi Mark,

    Thanks again for fixing that so quickly, that helped me figure out what I was doing wrong. A few more tweaks and my system is working. I don’t have an IMU, just the Berry-GPS, so if there is no fix, I am not writing any updated exif data, and if there is a fix then I am just writing the GPS position info.


Leave a Reply

Your email address will not be published. Required fields are marked *