forked from tuupola/micropython-mpu9250
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmpu6500.py
More file actions
229 lines (190 loc) · 7.12 KB
/
mpu6500.py
File metadata and controls
229 lines (190 loc) · 7.12 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# Copyright (c) 2018-2019 Mika Tuupola
# Copyright (c) 2019 Eike Welk
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copied of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
Python I2C driver for MPU6500 6-axis motion tracking device
"""
__version__ = "0.1.0-a"
# pylint: disable=import-error
import struct
import time
import Adafruit_GPIO.I2C
# pylint: enable=import-error
_GYRO_CONFIG = 0x1b
_ACCEL_CONFIG = 0x1c
_ACCEL_CONFIG2 = 0x1d
_INT_PIN_CFG = 0x37
_ACCEL_XOUT_H = 0x3b
_ACCEL_XOUT_L = 0x3c
_ACCEL_YOUT_H = 0x3d
_ACCEL_YOUT_L = 0x3e
_ACCEL_ZOUT_H = 0x3f
_ACCEL_ZOUT_L= 0x40
_TEMP_OUT_H = 0x41
_TEMP_OUT_L = 0x42
_GYRO_XOUT_H = 0x43
_GYRO_XOUT_L = 0x44
_GYRO_YOUT_H = 0x45
_GYRO_YOUT_L = 0x46
_GYRO_ZOUT_H = 0x47
_GYRO_ZOUT_L = 0x48
_WHO_AM_I = 0x75
#_ACCEL_FS_MASK = 0b00011000
ACCEL_FS_SEL_2G = 0b00000000
ACCEL_FS_SEL_4G = 0b00001000
ACCEL_FS_SEL_8G = 0b00010000
ACCEL_FS_SEL_16G = 0b00011000
_ACCEL_SO_2G = 16384 # 1 / 16384 ie. 0.061 mg / digit
_ACCEL_SO_4G = 8192 # 1 / 8192 ie. 0.122 mg / digit
_ACCEL_SO_8G = 4096 # 1 / 4096 ie. 0.244 mg / digit
_ACCEL_SO_16G = 2048 # 1 / 2048 ie. 0.488 mg / digit
#_GYRO_FS_MASK = 0b00011000
GYRO_FS_SEL_250DPS = 0b00000000
GYRO_FS_SEL_500DPS = 0b00001000
GYRO_FS_SEL_1000DPS = 0b00010000
GYRO_FS_SEL_2000DPS = 0b00011000
_GYRO_SO_250DPS = 131
_GYRO_SO_500DPS = 62.5
_GYRO_SO_1000DPS = 32.8
_GYRO_SO_2000DPS = 16.4
_TEMP_SO = 333.87
_TEMP_OFFSET = 21
# Used for enabling and disabling the i2c bypass access
_I2C_BYPASS_MASK = 0b00000010
_I2C_BYPASS_EN = 0b00000010
_I2C_BYPASS_DIS = 0b00000000
SF_G = 1
SF_M_S2 = 9.80665 # 1 g = 9.80665 m/s2 ie. standard gravity
SF_DEG_S = 1
SF_RAD_S = 0.017453292519943 # 1 deg/s is 0.017453292519943 rad/s
class MPU6500:
"""Class which provides interface to MPU6500 6-axis motion tracking device."""
def __init__(
self, i2c_interface=None, busnum=1, address=0x68,
accel_fs=ACCEL_FS_SEL_2G, gyro_fs=GYRO_FS_SEL_250DPS,
accel_sf=SF_M_S2, gyro_sf=SF_RAD_S,
gyro_offset=(0, 0, 0)
):
if i2c_interface is None:
# Use pure python I2C interface if none is specified.
import Adafruit_PureIO.smbus
self.i2c = Adafruit_PureIO.smbus.SMBus(busnum)
else:
# Otherwise use the provided class to create an smbus interface.
self.i2c = i2c_interface(busnum)
#self.i2c = i2c
self.address = address
if 0x71 != self.read_whoami():
raise RuntimeError("MPU6500 not found in I2C bus.")
self._accel_so = self._accel_fs(accel_fs)
self._gyro_so = self._gyro_fs(gyro_fs)
self._accel_sf = accel_sf
self._gyro_sf = gyro_sf
self._gyro_offset = gyro_offset
# Enable I2C bypass to access for MPU9250 magnetometer access.
char = self._read_register_char(_INT_PIN_CFG)
char &= ~_I2C_BYPASS_MASK # clear I2C bits
char |= _I2C_BYPASS_EN
self._write_register_char(_INT_PIN_CFG, char)
def read_acceleration(self):
"""
Acceleration measured by the sensor. By default will return a
3-tuple of X, Y, Z axis acceleration values in m/s^2 as floats. Will
return values in g if constructor was provided `accel_sf=SF_M_S2`
parameter.
"""
so = self._accel_so
sf = self._accel_sf
xyz = self._read_register_three_shorts(_ACCEL_XOUT_H)
return tuple([value / so * sf for value in xyz])
def read_gyro(self):
"""
X, Y, Z radians per second as floats.
"""
so = self._gyro_so
sf = self._gyro_sf
ox, oy, oz = self._gyro_offset
xyz = self._read_register_three_shorts(_GYRO_XOUT_H)
xyz = [value / so * sf for value in xyz]
xyz[0] -= ox
xyz[1] -= oy
xyz[2] -= oz
return tuple(xyz)
def read_temperature(self):
"""
Die temperature in celsius as a float.
"""
temp = self._read_register_short(_TEMP_OUT_H)
return ((temp - _TEMP_OFFSET) / _TEMP_SO) + _TEMP_OFFSET
def read_whoami(self):
""" Value of the whoami register. """
return self._read_register_char(_WHO_AM_I)
def calibrate_gyro(self, count=256, delay=0):
ox, oy, oz = (0.0, 0.0, 0.0)
self._gyro_offset = (0.0, 0.0, 0.0)
n = float(count)
while count:
time.sleep(delay/1000)
gx, gy, gz = self.read_gyro()
ox += gx
oy += gy
oz += gz
count -= 1
self._gyro_offset = (ox / n, oy / n, oz / n)
return self._gyro_offset
def _read_register_short(self, register):
buf = self.i2c.read_i2c_block_data(self.address, register, 2)
return struct.unpack(">h", buf)[0]
def _write_register_short(self, register, value):
buf = struct.pack(">h", value)
self.i2c.write_i2c_block_data(self.address, register, buf)
def _read_register_three_shorts(self, register):
buf = self.i2c.read_i2c_block_data(self.address, register, 6)
return struct.unpack(">hhh", buf)
def _read_register_char(self, register):
return self.i2c.read_byte_data(self.address, register)
def _write_register_char(self, register, value):
self.i2c.write_byte_data(self.address, register, value)
def _accel_fs(self, value):
self._write_register_char(_ACCEL_CONFIG, value)
# Return the sensitivity divider
if ACCEL_FS_SEL_2G == value:
return _ACCEL_SO_2G
elif ACCEL_FS_SEL_4G == value:
return _ACCEL_SO_4G
elif ACCEL_FS_SEL_8G == value:
return _ACCEL_SO_8G
elif ACCEL_FS_SEL_16G == value:
return _ACCEL_SO_16G
def _gyro_fs(self, value):
self._write_register_char(_GYRO_CONFIG, value)
# Return the sensitivity divider
if GYRO_FS_SEL_250DPS == value:
return _GYRO_SO_250DPS
elif GYRO_FS_SEL_500DPS == value:
return _GYRO_SO_500DPS
elif GYRO_FS_SEL_1000DPS == value:
return _GYRO_SO_1000DPS
elif GYRO_FS_SEL_2000DPS == value:
return _GYRO_SO_2000DPS
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
pass