-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathhmc5883l.py
executable file
·100 lines (81 loc) · 3.1 KB
/
hmc5883l.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python
# vim: set fileencoding=UTF-8 :
# HMC5888L Magnetometer (Digital Compass) wrapper class
# Based on https://bitbucket.org/thinkbowl/i2clibraries/src/14683feb0f96,
# but uses smbus rather than quick2wire and sets some different init
# params.
import smbus
import math
import time
import sys
class hmc5883l:
__scales = {
0.88: [0, 0.73],
1.30: [1, 0.92],
1.90: [2, 1.22],
2.50: [3, 1.52],
4.00: [4, 2.27],
4.70: [5, 2.56],
5.60: [6, 3.03],
8.10: [7, 4.35],
}
def __init__(self, port=1, address=0x1E, gauss=1.3, declination=(0,0)):
self.bus = smbus.SMBus(port)
self.address = address
(degrees, minutes) = declination
self.__declDegrees = degrees
self.__declMinutes = minutes
self.__declination = (degrees + minutes / 60) * math.pi / 180
(reg, self.__scale) = self.__scales[gauss]
self.bus.write_byte_data(self.address, 0x00, 0x70) # 8 Average, 15 Hz, normal measurement
self.bus.write_byte_data(self.address, 0x01, reg << 5) # Scale
self.bus.write_byte_data(self.address, 0x02, 0x00) # Continuous measurement
def declination(self):
return (self.__declDegrees, self.__declMinutes)
def twos_complement(self, val, len):
# Convert twos compliment to integer
if (val & (1 << len - 1)):
val = val - (1<<len)
return val
def __convert(self, data, offset):
val = self.twos_complement(data[offset] << 8 | data[offset+1], 16)
if val == -4096: return None
return round(val * self.__scale, 4)
def axes(self):
data = self.bus.read_i2c_block_data(self.address, 0x00)
#print map(hex, data)
x = self.__convert(data, 3)
y = self.__convert(data, 7)
z = self.__convert(data, 5)
return (x,y,z)
def heading(self):
(x, y, z) = self.axes()
headingRad = math.atan2(y, x)
headingRad += self.__declination
# Correct for reversed heading
if headingRad < 0:
headingRad += 2 * math.pi
# Check for wrap and compensate
elif headingRad > 2 * math.pi:
headingRad -= 2 * math.pi
# Convert to degrees from radians
headingDeg = headingRad * 180 / math.pi
return headingDeg
def degrees(self, headingDeg):
degrees = math.floor(headingDeg)
minutes = round((headingDeg - degrees) * 60)
return (degrees, minutes)
def __str__(self):
(x, y, z) = self.axes()
return "Axis X: " + str(x) + "\n" \
"Axis Y: " + str(y) + "\n" \
"Axis Z: " + str(z) + "\n" \
"Declination: " + self.degrees(self.declination()) + "\n" \
"Heading: " + self.degrees(self.heading()) + "\n"
if __name__ == "__main__":
# http://magnetic-declination.com/Great%20Britain%20(UK)/Harrogate#
compass = hmc5883l(gauss = 4.7, declination = (-2,5))
while True:
sys.stdout.write("\rHeading: " + compass.degrees(compass.heading()) + " ")
sys.stdout.flush()
time.sleep(0.5)