Interfacing Digital Compass (HMC5883L) With Raspberry Pi 2 Using Python3

61K3354

Intro: Interfacing Digital Compass (HMC5883L) With Raspberry Pi 2 Using Python3

Initially, I was working on a maze solving robot. Instead of using ultrasonic and infrared on Arduino Mega for wall following like my friends did, I try to do something different using the digital compass and Raspberry Pi 2. This experience is totally new for me as I'm now using Python instead of C++ (well we still have WiringPi which uses C Language) and figuring how Linux system works is not a one day tasks (can't always remember the syntax like "df" and others).

Anyways, I bought the digital compass without considering how I was going to interface it. When I got my RPi2, I was looking everywhere for tutorials. This tutorial is merely a compilation of the tutorials that I used to interface my digital compass. I just thought that it would be a great idea to post in one place where everyone would look for. After all, this is my first post.

This tutorial uses:

1. Raspberry Pi 2 (and whats necessary to power it up, I'm using headless setup on Raspbian)

2. HMC5883L Digital Compass (from electronic flea market)

3. Female to female jumper cables (4 pieces)

4. Your computer (with SSH client program such as "putty")

STEP 1: Configuring RPi2

In order to use the RPi2's I2C, we have to first enable it. Boot up and login into the RPi.

Enter the RPi Configuration menu using "sudo raspi-config". Under "Advance Options" you can find "I2C" configuration. Select the option and it will prompt an option to enable or to disable I2C function in RPi2 (which is disabled by default). Select yes when prompted to load I2C kernel module by default. Exit the RPi configuration menu by selecting "Finish".

Returning to the terminal, we will need to modify the file called "modules". Using the text editor program called "nano", we can edit the file under superuser permission. Use, "sudo nano /etc/modules" and add these two lines

i2c-bcm2708 #BCM2708 is the family of processors used by RPi, BCM2836 is the specific processor name of the RPi2
i2c-dev

To exit, press "CTRL+X" and select "Y" to save and press Enter to overwrite the previous file. (Actually I don't quite understand why I need to do perform this step since we've already prompted and enable I2C kernel module to load by default. I am still searching for answers, please post in comments if you know)

STEP 2: Getting Necessary Libraries and Packages

This step is very straight forward. Just needed some typing skills and an internet connection.

We will need this few packages and raspbian upgrade which is i2c-tools, python-smbus and python3 (smbus only works in python3). Type in the following commands in the terminal (everything after "#" symbol is just comments for you to read):

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install i2c-tools
sudo apt-get install python-smbus
sudo apt-get install python3 #if you have the latest Raspbian, python3 should be pre-installed

After getting all the packages, reboot the RPi2 using "sudo reboot"

Then it is time to get the libraries. Among the libraries we will be needing is "quick2wire" and "i2clibraries" for python from Think-Bowl. Make a folder for your project, lets say the folder's name is "project", type in the following commands. (everything after "#" symbol is just comments for you to read)

mkdir ~/project #make a folder named 'project' at ~ (home) directory
cd project #change directory into the 'project folder

git clone https://github.com/quick2wire/quick2wire-python-ap... #get quick2wire from github.com

#if don't have git, try "sudo apt-get install git"

mv ./quick2wire-python-api ./code #renaming the quick2wire library folder to code for tidiness, you can skip this if you prefer keeping it original

nano setup.env #create a setup file, basically to point out where the quick2wire library is situated for your python

after this line, terminal will enter text editing mode, type in these lines

export QUICK2WIRE_API_HOME=~/project/code #change the directory address if different than what i'm using
export PYTHONPATH=$PYTHONPATH:$QUICK2WIRE_API_HOME

after that CTRL+X, Y, ENTER to quit, save and overwrite

back in terminal mode

. ./quick2wire.env #run the environment setup, run this once every time after reboot, running twice will append the address directory

#for checking, use "env |grep quick2wire", address shown must be the same with the directory where you install your quick2wire library

cd code #go into the quick2wire folder, this will be where you put your python code

git clone https://bitbucket.org/thinkbowl/i2clibraries.git #getting library files containing functions for i2c devices such as HMC5883L, ITG-3205, ADXL345 and LCD

Now you can shut it down with "sudo shutdown -h now" so that we can do the wiring

STEP 3: Hardware Wiring

The schematic is simple, its not rocket science to wire this baby up.

There are 4 basic connections we need to make, VCC (3.3V), GND, SDA and SCL, colors of the jumpers I used in the pictures are as below

VCC => RED => pin #1
GND => BLACK => pin #6
SDA => WHITE => pin #3
SCL => GREY => pin #5

So the VCC pin of compass connects to pin #1 of RPi2, GND to pin #6, SDA to pin #3 and SCL to pin #5. If you have trouble figuring out which pin on RPi2 is GND, VCC 3.3, SDA and SCL you can refer to the GPIO Pinout for RPi2 model B from Element14.

After connecting the compass, fire up the RPi2 again. To check if the connection is correct, type in:

i2cdetect -y 1 #RPi2 model B uses port 1 i2c, other models may use port 0 of i2c

The result should show a grid with the address '1e' on one of the grid blocks

STEP 4: Coding

To test if this works, you can type in this codes in "nano" and name it as whatevernameyouwant.py

from i2clibraries import i2c_hmc5883l

hmc5883l = i2c_hmc5883l.i2c_hmc5883l(1) #choosing which i2c port to use, RPi2 model B uses port 1

hmc5883l.setContinuousMode()

hmc5883l.setDeclination(0,6) #type in the magnetic declination of your location in the bracket (degrees, minute)

print(hmc5883l)

Run the code using "sudo python3 whatevernameyouwant.py". This should output a series of measurement in terms of x, y and z axis and the calculated angle with reference to your true north.

Happy making!


39 Comments

Any help pse, i got this , next what ?

pi@pi:~/project $ . ./quick2wire.env
-bash: pi@pi:~/project: No such file or directory
Thank You
The connections will be the same for all raspberry pi models?

Man, you are great! I just followed your instructions and I made it! It took less than 10 minutes. :)

Is there a way to put the heading data into a variable as a number so that i can use it in my programs? Any help is appreciated !

Traceback (most recent call last):

File "digital_compass.py", line 3, in <module>

hmc5883l = i2c_hmc5883l.i2c_hmc5883l(1)

File "/home/pi/digital_compass/quick2wire-python-api/i2clibraries/i2c_hmc5883l.py", line 29, in __init__

self.setScale(gauss)

File "/home/pi/digital_compass/quick2wire-python-api/i2clibraries/i2c_hmc5883l.py", line 76, in setScale

self.setOption(self.ConfigurationRegisterB, self.scale_reg)

File "/home/pi/digital_compass/quick2wire-python-api/i2clibraries/i2c_hmc5883l.py", line 87, in setOption

self.bus.write_byte(register, options)

File "/home/pi/digital_compass/quick2wire-python-api/i2clibraries/i2c.py", line 14, in write_byte

writing_bytes(self.addr, *bytes))

File "/home/pi/digital_compass/quick2wire-python-api/quick2wire/i2c.py", line 78, in transaction

ioctl(self.fd, I2C_RDWR, ioctl_arg)

IOError: [Errno 5] Input/output error

Liam getting this error

Hi, I am getting this same error. Did you figure out what was wrong?

The i2c detect returns 0d instead of 1e. Then if I cange the hmc = i2c.i2c_hmc58831.i2c_hmc58831(0), I get the error "..../i2c.py line48, in init File not founderror no such file or dir '/dev/i2c-0'

You may find this thread helpful https://www.raspberrypi.org/forums/viewtopic.php?f...

TL;DR, In short, you (as I) have likely purchased a fake chip. Apparently, it should still work, just on entirely different addresses. Take a look at the actual data sheet for more info. https://github.com/luckypm/commn-informations/blob/master/%E5%9C%B0%E7%A3%81%E6%96%87%E6%A1%A3/%E8%88%AA%E7%BA%AC5983%E6%9B%BF%E4%BB%A3%E6%96%99%E8%B5%84%E6%96%99/QMC5883L%20Datasheet%201.0%20.pdf

I've played a little bit with the addresses and I'm starting to get something else than zeros.
I'm not sure that values are good, but it's a beginning..
Here is the mods I've made on the code:

import math
from i2clibraries import i2c
from time import *

class i2c_hmc5883l:

ConfigurationRegisterA = 0x09
ConfigurationRegisterB = 0x10
ModeRegister = 0x06
AxisXDataRegisterMSB = 0x01
AxisXDataRegisterLSB = 0x00
AxisZDataRegisterMSB = 0x05
AxisZDataRegisterLSB = 0x04
AxisYDataRegisterMSB = 0x03
AxisYDataRegisterLSB = 0x02
StatusRegister = 0x06
IdentificationRegisterA = 0x10
IdentificationRegisterB = 0x11
IdentificationRegisterC = 0x12


MeasurementContinuous = 0x01
MeasurementSingleShot = 0x03
MeasurementIdle = 0x00

def __init__(self, port, addr=0x0d, gauss=1.3):
self.bus = i2c.i2c(port, addr)

This link to the datasheet should actually work http://bit.ly/2qqna3E

Only the file named i2c-1 is in the dev folder. Why is there no i2c-0 file? What could be the problem? Can someone help?

Maybe your sensor is QMC5833 ,the address is 0d, the Register Map is different.

Thanks for the suggestion. It says HMC5883L printed on the compass so I guess it is that. Any other tips to check/lookup? I am still stuck.

I have the same issue , and I don't think i2clibraries support QMC5833L

I have to read the data sheet of this IC ,and finally get it done. You must read and write the registers yourself . I can send the datasheet to you.

Hi

I had this problem. I cured it by editing the i2c_hmc5883l.py file in the i2clibraries folder. Change "addr=0x1e" to "addr=0x0d" (approx line 21) and the pi can now interact with the module. However, all my readings are returning zero - anyone have any ideas?

did you already find a solution for the zeroes in your readings? I have the same problem

Diego, any fixes for the zero readings? Maybe the sensor could be faulty? I got mine for kinda cheap.

Hi, Yep, I got to that point too of changing the i2c_hmc5883l.py file to include 'addr=0x0d' but I am getting zero readings too. Seems like we have the same problem. Did you figure out something?

I am getting zero readings too. Did you find a fix to solve this?

More Comments