-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathhmc5883l.py
86 lines (65 loc) · 2.58 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
import math
import machine
from ustruct import pack
from array import array
class HMC5883L:
__gain__ = {
'0.88': (0 << 5, 0.73),
'1.3': (1 << 5, 0.92),
'1.9': (2 << 5, 1.22),
'2.5': (3 << 5, 1.52),
'4.0': (4 << 5, 2.27),
'4.7': (5 << 5, 2.56),
'5.6': (6 << 5, 3.03),
'8.1': (7 << 5, 4.35)
}
def __init__(self, scl=4, sda=5, address=30, gauss='1.3', declination=(0, 0)):
self.i2c = i2c = machine.I2C(scl=machine.Pin(scl), sda=machine.Pin(sda), freq=100000)
# Initialize sensor.
i2c.start()
# Configuration register A:
# 0bx11xxxxx -> 8 samples averaged per measurement
# 0bxxx100xx -> 15 Hz, rate at which data is written to output registers
# 0bxxxxxx00 -> Normal measurement mode
i2c.writeto_mem(30, 0x00, pack('B', 0b111000))
# Configuration register B:
reg_value, self.gain = self.__gain__[gauss]
i2c.writeto_mem(30, 0x01, pack('B', reg_value))
# Set mode register to continuous mode.
i2c.writeto_mem(30, 0x02, pack('B', 0x00))
i2c.stop()
# Convert declination (tuple of degrees and minutes) to radians.
self.declination = (declination[0] + declination[1] / 60) * math.pi / 180
# Reserve some memory for the raw xyz measurements.
self.data = array('B', [0] * 6)
def read(self):
data = self.data
gain = self.gain
self.i2c.readfrom_mem_into(30, 0x03, data)
x = (data[0] << 8) | data[1]
z = (data[2] << 8) | data[3]
y = (data[4] << 8) | data[5]
x = x - (1 << 16) if x & (1 << 15) else x
y = y - (1 << 16) if y & (1 << 15) else y
z = z - (1 << 16) if z & (1 << 15) else z
x = round(x * gain, 4)
y = round(y * gain, 4)
z = round(z * gain, 4)
return x, y, z
def heading(self, x, y):
heading_rad = math.atan2(y, x)
heading_rad += self.declination
# Correct reverse heading.
if heading_rad < 0:
heading_rad += 2 * math.pi
# Compensate for wrapping.
elif heading_rad > 2 * math.pi:
heading_rad -= 2 * math.pi
# Convert from radians to degrees.
heading = heading_rad * 180 / math.pi
degrees = math.floor(heading)
minutes = round((heading - degrees) * 60)
return degrees, minutes
def format_result(self, x, y, z):
degrees, minutes = self.heading(x, y)
return 'X: {:.4f}, Y: {:.4f}, Z: {:.4f}, Heading: {}° {}′ '.format(x, y, z, degrees, minutes)