Operácie

Acrob030

Z SensorWiki

Following text will show You a basic connection and operation of the digital compass module.

Parallax HM55B.jpg

Product page: #29123 Hitachi HM55B Compass Module

Schematic diagram:

Parallax HM55B Schematic.png

Demo program (from the http://arduino.cc/playground/Main/HM55B):

/* Htachi HM55B Compass by the Pparallax (#29 123)

 AUTHOR:   kiilo kiilo@kiilo.org
 License:  http://creativecommons.org/licenses/by-nc-sa/2.5/ch/

 http://parallax.com/Store/Microcontrollers/BASICStampModules/tabid/134/txtSearch/hm55b/List/1/ProductID/98/Default.aspx?SortField=ProductName%2cProductName
 http://sage.medienkunst.ch/tiki-index.php?page=HowTo_Arduino_Parallax_HM55B_Kompass
 http://arduino.cc/playground/HM55B

*/

#include <math.h> // (no semicolon)

//// VARS
byte  EN_pin = 4;
byte CLK_pin = 5;
byte DIO_pin = 6;

int X_Data = 0;
int Y_Data = 0;
int angle;

//// FUNCTIONS

void ShiftOut(int Value, int BitsCount) {
  for(int i = BitsCount; i >= 0; i--) {
    digitalWrite(CLK_pin, LOW);
    if ((Value & 1 << i) == ( 1 << i)) {
      digitalWrite(DIO_pin, HIGH);
      //Serial.print("1");
    }
    else {
      digitalWrite(DIO_pin, LOW);
      //Serial.print("0");
    }
    digitalWrite(CLK_pin, HIGH);
    delayMicroseconds(1);
  }
//Serial.print(" ");
}

int ShiftIn(int BitsCount) {
  int ShiftIn_result;
    ShiftIn_result = 0;
    pinMode(DIO_pin, INPUT);
    for(int i = BitsCount; i >= 0; i--) {
      digitalWrite(CLK_pin, HIGH);
      delayMicroseconds(1);
      if (digitalRead(DIO_pin) == HIGH) {
        ShiftIn_result = (ShiftIn_result << 1) + 1; 
        //Serial.print("x");
      }
      else {
        ShiftIn_result = (ShiftIn_result << 1) + 0;
        //Serial.print("_");
      }
      digitalWrite(CLK_pin, LOW);
      delayMicroseconds(1);
    }
  //Serial.print(":");

// below is difficult to understand:
// if bit 11 is Set the value is negative
// the representation of negative values you
// have to add B11111000 in the upper Byte of
// the integer.
// see: http://en.wikipedia.org/wiki/Two%27s_complement
  if ((ShiftIn_result & 1 << 11) == 1 << 11) {
    ShiftIn_result = (B11111000 << 8) | ShiftIn_result; 
  }


  return ShiftIn_result;
}

void HM55B_Reset() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B0000, 3);
  digitalWrite(EN_pin, HIGH);
}

void HM55B_StartMeasurementCommand() {
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1000, 3);
  digitalWrite(EN_pin, HIGH);
}

int HM55B_ReadCommand() {
  int result = 0;
  pinMode(DIO_pin, OUTPUT);
  digitalWrite(EN_pin, LOW);
  ShiftOut(B1100, 3);
  result = ShiftIn(3);
  return result;
}


void setup() {
  Serial.begin(115200);
  pinMode(EN_pin, OUTPUT);
  pinMode(CLK_pin, OUTPUT);
  pinMode(DIO_pin, INPUT);

  HM55B_Reset();
}

void loop() {
  HM55B_StartMeasurementCommand(); // necessary!!
  delay(40); // the data is 40ms later ready
  Serial.print(HM55B_ReadCommand()); // read data and print Status
  Serial.print(" ");  
  X_Data = ShiftIn(11); // Field strength in X
  Y_Data = ShiftIn(11); // and Y direction
  Serial.print(X_Data); // print X strength
  Serial.print(" ");
  Serial.print(Y_Data); // print Y strength
  Serial.print(" ");
  digitalWrite(EN_pin, HIGH); // ok deselect chip
  angle = 180 * (atan2(-1 * Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!
  Serial.print(angle); // print angle
  Serial.println("");

}

If the program works correctly, it will send to the serial port (115 200 Bd) following data: Status Xvalue Yvalue a Azimuth. For example, compass facing NORTH will send following

12 42 0 0
12 41 -1 1
12 40 7 -9
12 40 0 0
12 40 7 -9
12 38 0 0


Demo software (from the http://ozguraytekin.blogspot.com/2010/12/using-hm55b-compass-module-from.html) - run the code below in the Processing language to obtain the following result:

HM55B ProcessingScreen.png
// Author:  Özgür Aytekin - http://ozguraytekin.blogspot.com
// License: http://creativecommons.org/licenses/by-nc-sa/2.5/ch/

// The Processing serial library allows for easily reading and writing data to and
// from external machines.
// It allows two computers to send and receive data and gives you the flexibility
// to communicate with custom microcontroller devices, using them as the input or
// output to Processing programs. 
import processing.serial.*;

// Define variable for receiving data using the communication protocol
Serial serialPort;

// Define variables for storing miscellaneous variables (delivered from arduino)
float hm55bStatus, fieldStrengthInX, fieldStrengthInY, angleRawValue, angleRotateValue = 0;

// Define a variable for storing angle between 0 and 360 degree
float angleDisplayValue = 0;

// Called once when the program is started.
void setup()
{
  // Defines the dimension of the display window in units of pixels.
  // The size() function must be the first line in setup().
  size(640, 480);

  // Specifies the number of frames to be displayed every second.
  // If the processor is not fast enough to maintain the specified rate,
  // it will not be achieved.
  // For example, the function call frameRate(24) will attempt to refresh 24 times a second.
  // It is recommended to set the frame rate within setup().
  // The default rate is 60 frames per second.
  frameRate(24);

  // Gets a list of all available serial ports.
  // Use println() to write the information to the text window.
  println(Serial.list());

  // Class for sending and receiving data using the serial communication protocol.
  // Constructor Serial(parent, name, rate)
  // parent = PApplet: typically use "this", name = String: name of the port (COM1 is the default),
  // rate = int: 115200 
  serialPort = new Serial(this, Serial.list()[2], 115200);

  // Sets a specific byte to buffer until before calling serialEvent().
  // Don't generate a serialEvent() until get a newline character
  serialPort.bufferUntil('\n');
}

// Called when data is available.
void serialEvent(Serial serialPort)
{
  // Reads from the port into a buffer of bytes up to and including a particular character.
  // If the character isn't in the buffer, 'null' is returned.
  String inputString = serialPort.readStringUntil('\n');

  if (inputString != null)
  {
    // Removes whitespace characters from the beginning and end of a String.
    // In addition to standard whitespace characters such as space, carriage return,
    // and tab, this function also removes the Unicode "nbsp" character.
    inputString = trim(inputString);

    // The split() function breaks a string into pieces using a character or string as the divider.
    // filling substrings into a float array
    float[] values = float(split(inputString, " "));

    // we are waiting for four elements
    // put the numbers in the values array-variable
    if(values.length >= 4)
    {
      hm55bStatus = values[0];
      fieldStrengthInX  = values[1];
      fieldStrengthInY = values[2];
      angleRawValue = values[3];

      // hm55b is delivering values between 0 and 180 and 0 and -179
      // when the angle value is less than 0, adding 360 to angle
      // is delivering the degree between 0 and 359
      if(angleRawValue >= 0 && angleRawValue <= 180)
      {
        angleDisplayValue = angleRawValue;
      }
      else if(angleRawValue < 0)
      {
        angleDisplayValue = 360 + angleRawValue;
      }
    }
  }
}

// Called directly after setup() and continuously executes the lines of code contained inside
// its block until the program is stopped or noLoop() is called.
// The draw() function is called automatically and should never be called explicitly. 
void draw()
{
  // The background() function sets the color used for the background of the Processing window. 
  background(200);
  // Sets the color used to fill shapes.
  fill(153);

  print("angleRawValue: ");
  print(angleRawValue);
  print('\t');
  
  print("angleDisplayValue: ");
  println(angleDisplayValue);

  // Re-maps a number from one range to another.
  angleRotateValue = map(angleRawValue, 0, 359, 0, PI * 2);

  noFill();
  ellipseMode(CENTER);
  ellipse(width/2, height/2, 200, 200);
  ellipse(width/2, height/2, 20, 20);

  text("North", width/2 - 16, 130);
  text("South", width/2 - 16, 360);

  text("West", 180, height/2);
  text("East", 430, height/2);

  // Specifies an amount to displace objects within the display window.
  // The x parameter specifies left/right translation,
  // the y parameter specifies up/down translation,
  // and the z parameter specifies translations toward/away from the screen.
  translate(width/2, height/2);

  // Rotates a shape the amount specified by the angle parameter.
  rotate(angleRotateValue);

  // Draws a rectangle to the screen.
  rect(-6, - 100, 12, 100);

  // Forces the program to stop running for a specified time. 
  delay(500);
}

Download from here...


Arduino page about HM: http://www.arduino.cc/playground/Main/HM55B



Theory behind

What actually measures magnetic sensor? Yes, the strength of the magnetic field. It is just random coincidence, that current north magnetic pole is near the geographic one. Also, the Earth magnetic field is very unhomogenous. See picture:

http://netdaw.com/wp-content/uploads/2010/10/solar_wind1.jpg

Also beware of the magnetic inclination and declination... More:

You will need Your home coordinations. Determine Your location using Google Maps or GPS.


Tip: how to find lat and lon without the GPS: http://astro.unl.edu/naap/motion1/tc_finding.html