Bicycle North Indicator

10K276

Intro: Bicycle North Indicator


Magnetoception is the ability of some animals to detect magnetic fields as a means of orienting themselves.  Although humans do not seem to posses the same biological mechanisms that allow other animals to sense magnetic fields, there are still many ways that we can improve our sense of spatial orientation. 

This project is an attachment to your bicycle that beeps to let you know that you are moving in the direction of magnetic north.  It uses a parallax digital compass module, an Arduino, and a piezo buzzer to give you directional feedback as you bike.  The basic idea here is that by providing a constant source of stimuli in a certain direction, you might find yourself becoming more aware of other visual or sensory cues in your commute that indicate your orientation: geographical landmarks, air currents, inclines, or the position of the sun, moon, and stars.


(1x) Parallax 3-Axis Compass Module Radioshack 276-123
(1x) 85dB Piezo Buzzer Radioshack 273-060
(1x) Arduino Uno REV 3 Radioshack 276-128
(1x) 9V Alkaline Battery Radioshack #23-866
(1x) Heavy-Duty 9V Snap Connectors Radioshack #270-324
(1x) PC Board with Copper Radioshack #276-147
(1x) SPST PC-Mountable Submini Toggle Switch Radioshack #275-645
(2x) Male Header Pins Jameco 103393
(1x) Female Pin Sockets Jameco 308567
(1x) 9-Volt Battery Holder Radioshack 270-326


Additional Materials:

Heat Shrink Radioshack #278-1611
22 Gauge Wire Radioshack #278-1224
Solder Radioshack #64-013
zip ties
Drill
Screwdriver
4-40 x 1" nuts and bolts

STEP 1: Schematic

The schematic above shows how simple this project is.  A 9V battery and switch are connected in series to the Vin and ground pins of the Arduino- this is the power supply for the project.  The Arduino supplies power to two pins of the compass module (see note in the image above) and analog pins A4 and A5 are used to receive data from the compass module.  the piezo buzzer is controlled by Arduino digital pin 7.

STEP 2: Solder Header Pins to Perf Board

Solder three rows of header pins to the copper side of the perf board so that the Arduino snaps on.  The headers pins should fit inside the Arduino's power pins, analog inputs, and digital i/o 0-7.  I did not solder header pins for pins 8-13 because the spacing between digital pins 7 and 8 is not the standard 2.54mm spacing.  It is a little challenging to solder the header pins to the copper side  of the board (I got some extra solder on some of the copper pads), but it is necessary so that the compass module can snap on the perf board without touching the Arduino.

STEP 3: Parallax Compass

Solder a row of 5 female sockets on the protoboard as shown in the images above.  The Parallax compass chip should fit nicely in this socket.  Connect the pin labelled ground to Arduino's ground, Vin to Arduino's 5V, SCL to Analog 5, and SDA to Analog 4 as indicated in the schematic above.

Upload the following code onto the Arduino.  It will print the raw x, y, and z data from the compass chip (the directions are indicated on the chip in figure 4).  If you have wired everything correctly you should see the raw data printed on your serial monitor (control/command+shift+m) in the Arduino IDE.  I found this code on the parallax website.
#include <Wire.h>

#define Addr 0x1E               // 7-bit address of HMC5883 compass

void setup() {
  Serial.begin(9600);
  delay(100);                   // Power up delay
  Wire.begin();
  
  // Set operating mode to continuous
  Wire.beginTransmission(Addr); 
  Wire.write(byte(0x02));
  Wire.write(byte(0x00));
  Wire.endTransmission();
}

void loop() {
  int x, y, z;

  // Initiate communications with compass
  Wire.beginTransmission(Addr);
  Wire.write(byte(0x03));       // Send request to X MSB register
  Wire.endTransmission();

  Wire.requestFrom(Addr, 6);    // Request 6 bytes; 2 bytes per axis
  if(Wire.available() <=6) {    // If 6 bytes available
    x = Wire.read() << 8 | Wire.read();
    z = Wire.read() << 8 | Wire.read();
    y = Wire.read() << 8 | Wire.read();
  }
  
  // Print raw values
  Serial.print("X=");
  Serial.print(x);
  Serial.print(", Y=");
  Serial.print(y);
  Serial.print(", Z=");
  Serial.println(z);
  
  delay(500);
}

STEP 4: Piezo Buzzer

The piezo buzzer says that it should run off a 9-16V supply, but if you hook it up to 5V it will still run, just somewhat quieter.  I didn't necessarily want it to buzz at maximum loudness so it worked out well to hook it directly to one of the Arduino's digital pins for this project.  If you really want to run the buzzer at 9V, you can wire it up with a transistor to the battery supply and use a transistor to switch it on and off.

Solder the red lead from the piezo buzzer to digital pin 7.  Solder the black wire to Arduino ground.

STEP 5: Power Connections

Connect the switch in series with the battery so that it becomes an on/off switch.

Solder the red lead from the battery snap to one of the outside pins on the switch.  Solder a red wire between the middle pin of the switch and the Vin pin on the Arduino.  Solder the black lead from the battery snap to Arduino ground.

STEP 6: Firmware

Here is the final firmware.  I chose the values of xVal, yVal, and zVal based on the output I saw from the code from step 3 when I had the +x direction pointed vertically up, and the -y direction pointed towards north and parallel to the ground.  You might find that different values work better for you.  When the incoming directional values from the compass module equal the values of xVal, yVal, and zVal, the Arduino turns the piezo buzzer on.  The variable "tolerance" sets the sensitivity of the device, you may want to increase or decrease this depending on what you like.

The piezo buzzer automatically buzzes at ~1Hz.  You can upload the code below if you want to hear the full buzzing potential of the buzzer.
#include <Wire.h>

#define Addr 0x1E               // 7-bit address of HMC5883 compass

boolean buzzer = 0;

//storage variable for direction
int x;
int y;
int z;

//calibrate these
int xVal = -185;
int yVal = 300;
int zVal = -115;

int tolerance = 90;//adjust to change sensitivity



void setup() {
  Wire.begin();
  
  Serial.begin(9600);
  
  // Set operating mode to continuous
  Wire.beginTransmission(Addr); 
  Wire.write(byte(0x02));
  Wire.write(byte(0x00));
  Wire.endTransmission();
  
  pinMode(7,OUTPUT);
}

void loop() {
  Serial.print("X=");
  Serial.print(x);
  Serial.print(", Y=");
  Serial.print(y);
  Serial.print(", Z=");
  Serial.println(z);

  // Initiate communications with compass
  Wire.beginTransmission(Addr);
  Wire.write(byte(0x03));       // Send request to X MSB register
  Wire.endTransmission();

  Wire.requestFrom(Addr, 6);    // Request 6 bytes; 2 bytes per axis
  if(Wire.available() <=6) {    // If 6 bytes available
    x = Wire.read() << 8 | Wire.read();
    z = Wire.read() << 8 | Wire.read();
    y = Wire.read() << 8 | Wire.read();
  }
  
  if (abs(xVal-x)<tolerance){//
    if (abs(yVal-y)<tolerance){
      if (abs(zVal-z)<tolerance){
        buzzer = 1;
      }
      else{
        buzzer = 0;
      }
    }
    else{
      buzzer = 0;
    }
  }
  else{
    buzzer = 0;
  }
  
  if (buzzer){
    digitalWrite(7,HIGH);
  }
  else{
    digitalWrite(7,LOW);
  }
  
  delay(500);
}





I found this buzzing to be a bit much so I pulsed power on and off to the buzzer to quiet it a bit.  See the code below:
#include <Wire.h>

#define Addr 0x1E               // 7-bit address of HMC5883 compass

boolean buzzer = 0;

//storage variable for direction
int x;
int y;
int z;

//calibrate these
int xVal = -185;
int yVal = 300;
int zVal = -115;

int tolerance = 90;//adjust to change sensitivity



void setup() {
  Wire.begin();
  
  Serial.begin(9600);
  
  // Set operating mode to continuous
  Wire.beginTransmission(Addr); 
  Wire.write(byte(0x02));
  Wire.write(byte(0x00));
  Wire.endTransmission();
  
  pinMode(7,OUTPUT);
}

void loop() {
  
  Serial.print("X=");
  Serial.print(x);
  Serial.print(", Y=");
  Serial.print(y);
  Serial.print(", Z=");
  Serial.println(z);

  // Initiate communications with compass
  Wire.beginTransmission(Addr);
  Wire.write(byte(0x03));       // Send request to X MSB register
  Wire.endTransmission();

  Wire.requestFrom(Addr, 6);    // Request 6 bytes; 2 bytes per axis
  if(Wire.available() <=6) {    // If 6 bytes available
    x = Wire.read() << 8 | Wire.read();
    z = Wire.read() << 8 | Wire.read();
    y = Wire.read() << 8 | Wire.read();
  }
  
  if (abs(xVal-x)<tolerance){
    if (abs(yVal-y)<tolerance){
      if (abs(zVal-z)<tolerance){
        buzzer = 1;
      }
      else{
        buzzer = 0;
      }
    }
    else{
      buzzer = 0;
    }
  }
  else{
    buzzer = 0;
  }
  
  if (buzzer){
    digitalWrite(7,HIGH);
    delay(100);
    digitalWrite(7,LOW);
  }
  
  delay(500);
}



STEP 7: Secure Arduino, Buzzer, and Battery Clip to Enclosure

Lay out the arduino, piezo buzzer, and battery clip onto the lid of the project enclosure and mark out the position of the mounting holes.  Drill these holes fasten the components down with nuts and bolts as shown in the images above.

Make sure to orient the arduino so that the x axis of the parallax chip is parallel to the long edge of the project enclosure (fig 3).

STEP 8: Install Switch

Drill a hole in the bottom of the project enclosure and mount the power switch by securing it with a nut.

STEP 9:

Secure the lid of the enclosure with 4 screws.

STEP 10: Attach to Bike

Use zip ties to secure the project to your bike.  Line up the project enclosure so that the front of the bike points in the same direction as -Y on the parallax chip.  Don't forget to turn off the project when you are not using it or you will drain the battery quickly!

6 Comments

Hello !
So... Do you "feel" the North now ?
What might be an interesting feature is to have a "Orienteering" setting. Point the bike in a direction and have a button that sets that as the desired direction.

As for the annoyance that you have with the buzzer, replacing it with a more natural sound might help. The first idea that comes to mind is a solenoid driven bike bell. Another option might be a haptic output: replace with a pager motor or linear resonant actuator. You might even be able to hack the existing piezo buzzer's oscillator to work at 100-300Hz but I think you'd need higher voltages to act as a haptic device.
Very nice!
Where the hey' do you get your ideas from?
i'd like to get me some too.. :)

Thanks for sharing!