Project tutorial

Hiking Tracker © LGPL

Tracks compass heading, altitude, temperature, pressure, humidity, time, travel distance and GPS location during a hike.

  • 7,334 views
  • 16 comments
  • 46 respects

Components and supplies

Necessary tools and machines

Hy gluegun
Hot glue gun (generic)
09507 01
Soldering iron (generic)

Apps and online services

About this project

What is Hiking Tracker ?

Hiking Tracker is a device to sense the change in surrounding environment of a hiker during hiking.

The idea is to observe the change in temperature, pressure, humidity, altitude, location, direction etc. It gives some interesting insight of hiking.

On the mountains where it is cold, dry, low density air compared to lower lands, many people find it hard to breath. Some experience dry skin irritation. This device lets people interested in hiking to know their limits. There is also the fun of going to high altitude places. Being able to know the altitude is a fun thing !

Not only the mountains but also exploring swamps, deserts, forests - with each has its unique environmental profile, being able to monitor the environment on the go is a better way to understand the nature.

Video Demonstration

Sensors data

Step 1 : Hardware, which for what ?

There are lots of sensing going around with this project

The accessory shield comes with some I2C devices on board :

  • LM 75B temperature sensor for sensing ambient temperature
  • ADXL345 3-axis accelerometer for sensing tilt and gravity
  • DS3231 high-precision RTC for sensing time
  • 1306 OLED for viewing data
  • Buzzer for alarm beep
  • RGB LED is not needed for this project
  • XBee interface is not used but Arduino D2, D3, D9, D10 can be brought out from this interface for other projects, D2 is connected to reset, which allows resetting the Arduino from code !
  • 5-way joystick is not used
  • 101 pot is not used

In addition to this few more I2C sensor modules will be needed:

  • HMC5883 3-axis magnetic sensor for sensing compass heading
  • AM2320 humidity sensor for sensing % RH of air
  • BMP180 pressure sensor for sensing atmospheric pressure and altitude
  • MTK3339 GPS sensor for sensing location and walked distance

On the Arduino Uno:

  • 3.9k + 22k voltage divider for sensing 4 AA battery voltage

Step 2 : Modifying & Connecting the Hardware

Few modifications are made on the Arduino Uno. It is mounted on a 4 AA Battery holder with screw standoffs and hot glue.

4 AA and CR1220 (for RTC) are installed on battery holders.

There is a space between the battery holder and Arduino Uno board where the pressure, humidity, magnetic and GPS sensor can be placed.

I2C sensors are soldered together on a piece of pref board and placed in this space

These sensors are connected to Arduino Uno from the bottom side :

A voltage divider is added to measure battery voltage of 4 AA batteries.

The AA battery pack voltage sense line goes to ADC A1 :

The joystick of the shield is mapped to the ACD pin A1 through pin A5. That is why the joy stick is desoldered and removed.

By connecting some pad on the Accessory Shield (for schematic see reference) with solder bridge D2 (for soft reset), D3, D9, D10 pins of Arduino are made available on Xbee interface.

The components stack like this:

  • Top Layer : Accessory Shield on Arduino
  • Middle Layer: Other Sensors and GPS will go between Uno and Battery Case
  • Bottom Layer: 4 AA Battery Holder with batteries

And the connections look like this:

Step 3 : Programming the Device

Arduino IDEBuild 1.8.5 is used to program the device. First all the following libraries are included or downloaded using the library manager.

By typing the name of the sensor on the search box of library manager, appropriate libraries will appear.

Some of the Accessory Shield libraries (see reference) are added through zip.file option

After adding necessary libraries, example codes for each sensor is reviewed to find out the APIs for associated sensors.

Next, all the library headers are included in one empty Arduino sketch.

List of Header files

math.h,inttypes.h,Wire.h,lm75.h,ADXL345.h,ChainableLED.h,U8glib.h,ds3231.h,Adafruit_Sensor.h,Adafruit_AM2320.h,Adafruit_BMP085_U.h,Adafruit_HMC5883_U.h,Adafruit_GPS.h

After multiple edit, compile and debug ( including loose connection, where I discovered the BMP180 works without Vcc due to leakage power for I2C pins maybe ) and upload - finally the code was ready.

The Caveats

  • Altitude calculation is based on Air Pressure Drop, applicable only during normal weather condition.
  • Compass code is not tilt compensated in software, device must be held in a level plane. There is a fixed compass circle, in which there is another variable radius circle. When the device is tilted, the inner circle will increase. When it is in a leveled position ( i.e. both x and y component of acceleromere is almost 0 ) the inner circle will reduce to a point. This is when the compass heading is more accurate.
  • Compass pointer declination angle depends on location and variation of Earth's magnetic field. Which may get affected by Solar storm. If declination angle is not included, compass heading will be off by few degrees.

Find declination for your area : http://www.magnetic-declination.com

  • Compass heading is prone to nearby magnetic objects, like presence of strong magnetic minerals on mountains.
  • Device minimum operating voltage is about 4.5 volts. This is when AA batteries should be replaced.
  • Time and Date is programmed from code, If time is needed to change the coin cell battery must be unplugged and plugged. A fresh program upload with new time in the code will change the time.
  • During development GPS module was not available. Hence, demo coordinates are placed in lat long. If someone withes to replicate this project, it is required to include GPS library and associated codes.
  • XY plane of Accelerometer and Magnetometer are subject to placement on PCB. Code is required to be adjustment accordingly.
  • Accelerometer reading accuracy is prone to vibration. It is advised to use the device on stand still condition.

Scope of Improvement

Improvements can be done from the firmware side for few more features:

  • Periodic logging of parameters on EEPROM
  • Buzzer alarm beep on reaching altitude/location milestone
  • Drink water reminder
  • Take a break reminder
  • Low battery alarm
  • Low temperature, humidity alert
  • Compass software calibration for tilt compensation (lots of trigonometry stuff)
  • Auto fetch declination using GPS and IoT connectivity

As for the hardware part of improvement :

  • User input switches for setting time, declination etc.
  • Custom 3D case for the device
  • Using Rechargeable LiPo Battery
  • Single board compact PCB design for more portability

Conclusion

Hiking is fun. It's more fun when you can check the change in surrounding environment. Specially, checking the altitude, humidity, pressure and temperature changes within hours while hiking. This device lets you know at what height you feel altitude sickness, what humidity level makes your skin dry - stuffs like that. Although there is room for improvement in both circuit layout and code to deal with the caveats, it's still cool to have a gadget like this while going into the wilderness!

External Resources

https://www.waveshare.com/wiki/Accessory_Shield

Code

Hiking_Tracker.inoC/C++
main.c
/*/////////// NOTE //////////
D2 allows soft reset assertable from code
D3,D9,D10 are available through 
12,13,16 of xbee interface
D4, D13 are not accessable
///////////////////////////*/

//// HEADER FILES FOR LIBRARY /////
#include <math.h>
#include <inttypes.h>

#include <Wire.h>
#include <lm75.h>
#include <ADXL345.h>
#include <ChainableLED.h>
#include "U8glib.h"
#include "ds3231.h"

#include "Adafruit_Sensor.h"
#include "Adafruit_AM2320.h"
#include <Adafruit_BMP085_U.h>
#include <Adafruit_HMC5883_U.h>
#include <Adafruit_GPS.h>


///////////////////////RTC Variables///////////////////
uint8_t time[8];
struct ts t;
int s;
int m;
int h;
int dy;
int mo;
int yr;

///////////////// Accelerometer Variables/////////////
float X=0.0;
float Y=0.0;
float Z=0.0;
float Gravity = 0.0;
///////////////// Accelerometer Variables/////////////
float Xm=0.0;
float Ym=0.0;
float Zm=0.0;
 

/////////////////////// RGB LED Variables///////////////
const int rgb_pwr = 12;                                     
const int clk_pin = 6;                                    
const int data_pin = 5;                                    
float hue = 0.0;
boolean up = true;

////////////////////// potentiometer///////////////////
int pot=0;  
//////////////////// Batt/Supply Vin /////////////////
float Vbatt =0.0;
//////////////////////Thermometer////////////////////
float temp = 0.0;
///////////////////// Humidity///////////////////////
float humid = 0.0;
////////////////////Air pressure////////////////////
double prsr = 0.0;
////////////////////Altitude ////////////////////
float alt = 0.0;
/////////////////// Lat, Long////////////////////
float lat = 0.0; float lon = 0.0;
//////////////////Compass Heading/////////////////
float heading =0.0;
///////////////////// Ohter Variables ///////////////

int mstime =0;
int sensor_selector = 1;
//////////// ENUM //I2C Device type Object /////////////////

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);   // I2C OLED  Display
TempI2C_LM75 termo = TempI2C_LM75(0x48,TempI2C_LM75::nine_bits); // I2C Temp  Sensor
ADXL345 accelerometer;                                           // I2C Acce  Sensor
ChainableLED leds(clk_pin, data_pin, rgb_pwr, 1);                // I2C RGB   LED
Adafruit_AM2320 am2320 = Adafruit_AM2320();                      // I2C Humid Sensor
Adafruit_BMP085_Unified bmp180 = Adafruit_BMP085_Unified(10085); // I2C Press Sensor
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);  // I2C Compa Sensor

// uncomment the following 2 lines to enable GPS
// Serial Debugging won't be availabel

//HardwareSerial mySerial = Serial;
//Adafruit_GPS GPS(&mySerial);
 



void setup(void) {

// 1.1V Internal Analog Ref //
analogReference(INTERNAL);

///////////// Signals for OLED on Accessory Shield /////////////
// solder bridged on shield needed for D2,D3,D9,D10
// pinMode(2,1); // self reset D2 to RST
   pinMode(3,1); // outs at xbee int 12, 
   pinMode(9,1); // outs at xbee int 13
   pinMode(10,1);// outs at xbee int 16
// digitalWrite(2,HIGH);  
   digitalWrite(3,HIGH); 
   digitalWrite(9,LOW);  
   digitalWrite(10,HIGH); 

 pinMode(7,1);
 pinMode(8,1);
 digitalWrite(7,HIGH);  
 digitalWrite(8,LOW);
 // 10k POT on A0
 // Vin Batt/Supply on A1 (3.91k/21.76k)
////////////////////////////////////////////
///////// Serial Comm for Debuging (optional)////////
// Serial.begin(9600);

////////////// Accel Init Waiting /////////
  if (!accelerometer.begin())
  {
    delay(50);
  }

/////////////// RTC Interrupt enabling /////////
DS3231_init(DS3231_INTCN);                                          
//////////////// Buzzer Init ////////////////
pinMode(11,1);
digitalWrite(11,LOW);  

 }


void loop(void) 
{
  
  // picture loop
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );

// switch between I2C sensors
 sensor_selector++;
 if (sensor_selector >= 3)
 {sensor_selector=0;}

////// Temperature Fetch API  //////
  temp=termo.getTemp(); 
  delay(5);
// "C
/////// Pressure Fetch API ////////
if(sensor_selector == 0)
{
  ///////////// Pressure Sensor Init /////////
  if(!bmp180.begin())
  delay(11);
  
  sensors_event_t event;
  bmp180.getEvent(&event);
 
  if (event.pressure)
  {
  prsr = event.pressure/10; //hP to kP 
  delay(50);
  }
  
}
////////////// GPS Init //////////
//GPS.begin(9600);


/////// Altitude Fetch API ////////
if(sensor_selector == 0)
{
    sensors_event_t event;
  bmp180.getEvent(&event);

  alt = bmp180.pressureToAltitude(1013.25,event.pressure);
  delay(50);
//  bmp180.end();
}
// in meter
  ////////////// Humidity Sensor Init ///////
if(sensor_selector == 1)
{
  am2320.begin();
  delay(50);
////// Humidity Fetch API /////////
  humid= am2320.readHumidity();
  delay(50);
//  am2320.end();
  
// in % of RH

}
// in kPa
////// Acceleration Fetch API //////

  Vector norm = accelerometer.readNormalize();
  X = norm.XAxis ; Y = norm.YAxis; Z = norm.ZAxis; 
  Gravity =sqrt(X*X + Y*Y+ Z*Z)-(0.3);// offset
// in m/s^2
///// Time Fetch API ////////
  
  DS3231_get(&t);
  s=t.sec; m=t.min; h=t.hour;
  dy=t.mday; mo=t.mon; yr=t.year;
 
///// Pot Position Fetch ///////
  
  pot=analogRead(A0)*5/(10*3);
  delay(2);

///// VBatt/Supply Fetch ///////

  // 1.1 is 1.08 for this chip 
  Vbatt=(1.08*analogRead(A1)/1023)/3.91*((3.91+21.76));
  delay(2);
///////// Compass Heading ////////
if(sensor_selector == 2)
{
  if(!mag.begin())
  {    while(1);
  }
 // delay(70);
  sensor_t sensor2;
  mag.getSensor(&sensor2);
  delay(70);
    // declination angle depends on Geo Location
  // use Lat Long from GPS to calculate
  sensors_event_t event2; 
  mag.getEvent(&event2);
 // Xm = event2.magnetic.x;
 // Ym = event2.magnetic.y;
  delay(70);
  float declination = 0.0; 
  heading = atan2(event2.magnetic.y, event2.magnetic.x);
  heading += declination; 
  //  sign correction
  if(heading < 0)
    heading += 2*PI;
  if(heading > 2*PI)
    heading -= 2*PI;
  // Convert radians to degrees for readability.
    heading = heading * 180/M_PI; 
//    mag.end();
} 
  
///// Buzzer Control //////////

  if (pot>80)
    {digitalWrite(11,1);}
   else 
    {digitalWrite(11,0);}

///// RGB Addressable LED Control /////////////
   if(pot>40)
  { 
    leds.pwr_set(PWR_ENABLE);                              
    for (byte i=0; i<1; i++)
    leds.setColorHSB(i, hue, 1.0, 0.5);
    
    if (up)
      hue+= 0.025;
    else
      hue-= 0.025;
    
     if (hue>=1.0 && up)
      up = false;
      else if (hue<=0.0 && !up)
      up = true;
  }

/////////////////////////////////
////////// Self Reset ///////////
  //  digitalWrite(2,LOW);
/////////////////////////////////  
 
}///////// Void Loop ends Here ///



//////////////////// Oled Picture Loop Draw Fn///////////////////


void draw(void) {
 
  u8g.setFont(u8g_font_7x13);
  u8g.drawHLine(37, 0, 62);
  
  u8g.setPrintPos(41, 12);if(h<10) u8g.print(0);u8g.print(h);u8g.drawStr( 54,12, ":");
  u8g.setPrintPos(62, 12);if(m<10) u8g.print(0);u8g.print(m);u8g.drawStr( 75,12,":");
  u8g.setPrintPos(83, 12);if(s<10) u8g.print(0);u8g.print(s);
  u8g.drawHLine(37, 14, 62);
  
  
  u8g.setFont(u8g_font_5x8);
  u8g.drawVLine(37, 0, 14);
  u8g.setPrintPos(0, 7);if(dy<10) u8g.print(0);u8g.print(dy);u8g.drawStr( 11,7, "/");
  u8g.setPrintPos(17, 7);if(mo<10) u8g.print(0);u8g.print(mo);u8g.drawStr( 0,16,"/");
  u8g.setPrintPos(6, 16);u8g.print(yr);
  u8g.drawVLine(99, 0, 14);
  u8g.drawStr( 104,7,"BATT"); 
  u8g.setPrintPos(102, 15); u8g.print(Vbatt);u8g.drawStr( 123,15,"V");

//  u8g.setFont(u8g_font_7x13);
//  u8g.setPrintPos(40, 25); u8g.print(round(temp));u8g.drawStr( 55,25, "'C");
//  u8g.print(round(temp));
  
  u8g.setFont(u8g_font_5x8);
//  u8g.drawStr( 5,40, "x "); u8g.setPrintPos(15, 40); u8g.print(round(X));
//  u8g.drawStr( 50,40,"y "); u8g.setPrintPos(60, 40); u8g.print(round(Y));
//  u8g.drawStr( 90,40,"z "); u8g.setPrintPos(100, 40); u8g.print(round(Z));
//  u8g.drawStr( 68,22,"BATT: "); u8g.setPrintPos(95, 22); u8g.print(Vbatt);u8g.drawStr( 123,22,"V");
  u8g.drawVLine(37, 18, 36);
 
  u8g.drawStr( 39,24,"AIR TEMP: "); u8g.setPrintPos(85, 24); u8g.print(temp);u8g.drawStr( 118,24,"C");
  u8g.drawStr( 39,34,"HUMIDITY: "); u8g.setPrintPos(85, 34); u8g.print(humid);u8g.drawStr( 118,34,"%");
  u8g.drawStr( 39,44,"PRESSURE: "); u8g.setPrintPos(85, 44); u8g.print(prsr);u8g.drawStr( 118,44,"hP");
  u8g.drawStr( 39,54,"ALTITUDE: "); u8g.setPrintPos(85, 54); u8g.print(round(alt));u8g.drawStr( 118,54,"m");
  u8g.drawHLine(0, 56, 128);
  u8g.drawStr( 19,64,"LAT:");u8g.setPrintPos(39, 64); u8g.print(23.57); // Demo, replace with LAT when GPS added
  u8g.drawStr( 69,64,"LONG:");u8g.setPrintPos(94, 64); u8g.print(90.36);// demo, replace with LON when GPS added
  
//  u8g.setPrintPos(40, 25); u8g.print(round(temp));u8g.drawStr( 55,25, "'C");

  int r = round(sqrt(X*X + Y*Y));
 // float tid  = atan(Y/X)*180/3.1415;// mathematical issues here
 // int radius = round(tid);
  
  u8g.drawStr( 0,22,"heading");
  u8g.drawCircle(18, 34,r,  U8G_DRAW_ALL);//  inner leveling circle
  u8g.drawCircle(18, 34,10,  U8G_DRAW_ALL);// outer fixed circle

  // inner circle will become a point when no tilt in x and y axis
  // this is when the compass heading is more accurate
  //u8g.drawLine(18, 34,(18+round(Y*2)),(34+round(X*2))); //scaled up 2x
  u8g.setPrintPos(0, 53); u8g.print(heading);
 // 0 or 360 is N
 //       90 is E
 //      180 is S
 //      270 is W
  // u8g.setFont(u8g_font_5x8);
 if ((heading>315)|(heading<=45))
 {
u8g.drawLine(18,34,8,34);
 }
if ((heading>45)&(heading<=135))
{
u8g.drawLine(18,34,18,24);
}
if ((heading>135)&(heading<=225))
{
u8g.drawLine(18,34,28,34);
}
if ((heading>225)&(heading<315))
{
u8g.drawLine(18,34,18,44);
}

// u8g.drawLine(18, 34,(18+round(Y*2)),(34+round(X*2))); //scaled up 2x BASED ON ACCELAROMETER
 
  
// loop ends here  
}
LibrariesC/C++
Unzip it and add the individual library zips to Arduino Library Manager
No preview (download only).

Schematics

Hiking Tracker
Ckt pny0nvpfjy

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 454,699 views
  • 42 comments
  • 237 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 285,922 views
  • 95 comments
  • 672 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 230,688 views
  • 38 comments
  • 240 respects

OpenCat

Project in progress by Team Petoi

  • 196,438 views
  • 154 comments
  • 1,366 respects
Add projectSign up / Login