Introduction: 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
Question 1 year ago
Hi,
Can I use this sensor on jetson xavier agx?
Thank you...
3 years ago
Any help pse, i got this , next what ?
pi@pi:~/project $ . ./quick2wire.env
-bash: pi@pi:~/project: No such file or directory
Thank You
3 years ago
The connections will be the same for all raspberry pi models?
6 years ago
Man, you are great! I just followed your instructions and I made it! It took less than 10 minutes. :)
6 years ago
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 !
7 years ago
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
Reply 6 years ago
Hi, I am getting this same error. Did you figure out what was wrong?
Reply 6 years ago
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'
Reply 6 years ago
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
Reply 6 years ago
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)
Reply 6 years ago
This link to the datasheet should actually work http://bit.ly/2qqna3E
Reply 6 years ago
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?
Reply 6 years ago
Maybe your sensor is QMC5833 ,the address is 0d, the Register Map is different.
Reply 6 years ago
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.
Reply 6 years ago
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.
Reply 6 years ago
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?
Reply 6 years ago
did you already find a solution for the zeroes in your readings? I have the same problem
Reply 6 years ago
Diego, any fixes for the zero readings? Maybe the sensor could be faulty? I got mine for kinda cheap.
Reply 6 years ago
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?
Reply 6 years ago
I am getting zero readings too. Did you find a fix to solve this?