grovepi/Software/Python/grove_6axis_acc_compass/lsm303d.py
2025-03-21 16:04:17 +01:00

211 lines
5.6 KiB
Python

#!/usr/bin/env python
#
# GrovePi Library for using the Grove - 6-Axis Accelerometer&Compass v2.0(http://www.seeedstudio.com/depot/Grove-6Axis-AccelerometerCompass-v20-p-2476.html)
#
# This sensor uses LSM303D chip and the library works in Python for the Raspberry Pi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this library? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
# Released under the MIT license (http://choosealicense.com/licenses/mit/).
# For more information see https://github.com/DexterInd/GrovePi/blob/master/LICENSE
import time,sys
import RPi.GPIO as GPIO
import smbus
import math
# use the bus that matches your raspi version
rev = GPIO.RPI_REVISION
if rev == 2 or rev == 3:
bus = smbus.SMBus(1)
else:
bus = smbus.SMBus(0)
class lsm303d:
# LSM303 Address definitions
LSM303D_ADDR = 0x1E # assuming SA0 grounded
# LSM303 Register definitions
TEMP_OUT_L = 0x05
TEMP_OUT_H = 0x06
STATUS_REG_M = 0x07
OUT_X_L_M = 0x08
OUT_X_H_M = 0x09
OUT_Y_L_M = 0x0A
OUT_Y_H_M = 0x0B
OUT_Z_L_M = 0x0C
OUT_Z_H_M = 0x0D
WHO_AM_I = 0x0F
INT_CTRL_M = 0x12
INT_SRC_M = 0x13
INT_THS_L_M = 0x14
INT_THS_H_M = 0x15
OFFSET_X_L_M = 0x16
OFFSET_X_H_M = 0x17
OFFSET_Y_L_M = 0x18
OFFSET_Y_H_M = 0x19
OFFSET_Z_L_M = 0x1A
OFFSET_Z_H_M = 0x1B
REFERENCE_X = 0x1C
REFERENCE_Y = 0x1D
REFERENCE_Z = 0x1E
CTRL_REG0 = 0x1F
CTRL_REG1 = 0x20
CTRL_REG2 = 0x21
CTRL_REG3 = 0x22
CTRL_REG4 = 0x23
CTRL_REG5 = 0x24
CTRL_REG6 = 0x25
CTRL_REG7 = 0x26
STATUS_REG_A = 0x27
OUT_X_L_A = 0x28
OUT_X_H_A = 0x29
OUT_Y_L_A = 0x2A
OUT_Y_H_A = 0x2B
OUT_Z_L_A = 0x2C
OUT_Z_H_A = 0x2D
FIFO_CTRL = 0x2E
FIFO_SRC = 0x2F
IG_CFG1 = 0x30
IG_SRC1 = 0x31
IG_THS1 = 0x32
IG_DUR1 = 0x33
IG_CFG2 = 0x34
IG_SRC2 = 0x35
IG_THS2 = 0x36
IG_DUR2 = 0x37
CLICK_CFG = 0x38
CLICK_SRC = 0x39
CLICK_THS = 0x3A
TIME_LIMIT = 0x3B
TIME_LATENCY = 0x3C
TIME_WINDOW = 0x3D
ACT_THS = 0x3E
ACT_DUR = 0x3F
MAG_SCALE_2 = 0x00 #full-scale is +/-2Gauss
MAG_SCALE_4 = 0x20 #+/-4Gauss
MAG_SCALE_8 = 0x40 #+/-8Gauss
MAG_SCALE_12 = 0x60 #+/-12Gauss
ACCELE_SCALE = 2
X = 0
Y = 1
Z = 2
# Set up the sensor
def __init__(self,):
self.write_reg(0x57, self.CTRL_REG1) # 0x57 = ODR=50hz, all accel axes on
self.write_reg((3<<6)|(0<<3), self.CTRL_REG2) # set full-scale
self.write_reg(0x00, self.CTRL_REG3) # no interrupt
self.write_reg(0x00, self.CTRL_REG4) # no interrupt
self.write_reg((4<<2), self.CTRL_REG5) # 0x10 = mag 50Hz output rate
self.write_reg(self.MAG_SCALE_2, self.CTRL_REG6) # magnetic scale = +/-1.3Gauss
self.write_reg(0x00, self.CTRL_REG7) # 0x00 = continouous conversion mode
time.sleep(.005)
# get the status of the sensor
def status(self):
if self.read_reg(self.WHO_AM_I) !=73:
return -1
return 1
# Write data to a reg on the I2C device
def write_reg(self,data,reg):
bus.write_byte_data(self.LSM303D_ADDR, reg, data)
# Read data from the sensor
def read_reg(self,reg):
return bus.read_byte_data(self.LSM303D_ADDR, reg)
# Check if compass is ready
def isMagReady(self):
if self.read_reg(self.STATUS_REG_M)&0x03!=0:
return 1
return 0
# Get raw accelerometer values
def getAccel(self):
raw_accel=[0,0,0]
raw_accel[0]=((self.read_reg(self.OUT_X_H_A)<<8)|self.read_reg(self.OUT_X_L_A))
raw_accel[1]=((self.read_reg(self.OUT_Y_H_A)<<8)|self.read_reg(self.OUT_Y_L_A))
raw_accel[2]=((self.read_reg(self.OUT_Z_H_A)<<8)|self.read_reg(self.OUT_Z_L_A))
#2's compiment
for i in range(3):
if raw_accel[i]>32767:
raw_accel[i]=raw_accel[i]-65536
return raw_accel
# Get accelerometer values in g
def getRealAccel(self):
realAccel=[0.0,0.0,0.0]
accel=self.getAccel()
for i in range(3):
realAccel[i] = round(accel[i] / math.pow(2, 15) * self.ACCELE_SCALE,3)
return realAccel
# Get compass raw values
def getMag(self):
raw_mag=[0,0,0]
raw_mag[0]=(self.read_reg(self.OUT_X_H_M)<<8)|self.read_reg(self.OUT_X_L_M)
raw_mag[1]=(self.read_reg(self.OUT_Y_H_M)<<8)|self.read_reg(self.OUT_Y_L_M)
raw_mag[2]=(self.read_reg(self.OUT_Z_H_M)<<8)|self.read_reg(self.OUT_Z_L_M)
#2's compiment
for i in range(3):
if raw_mag[i]>32767:
raw_mag[i]=raw_mag[i]-65536
return raw_mag
# Get heading from the compass
def getHeading(self):
magValue=self.getMag()
heading = 180*math.atan2(magValue[self.Y], magValue[self.X])/math.pi# // assume pitch, roll are 0
if (heading <0):
heading += 360
return round(heading,3)
def getTiltHeading(self):
magValue=self.getMag()
accelValue=self.getRealAccel()
X=self.X
Y=self.Y
Z=self.Z
pitch = math.asin(-accelValue[X])
print(accelValue[Y],pitch,math.cos(pitch),accelValue[Y]/math.cos(pitch),math.asin(accelValue[Y]/math.cos(pitch)))
roll = math.asin(accelValue[Y]/math.cos(pitch))
xh = magValue[X] * math.cos(pitch) + magValue[Z] * math.sin(pitch)
yh = magValue[X] * math.sin(roll) * math.sin(pitch) + magValue[Y] * math.cos(roll) - magValue[Z] * math.sin(roll) * math.cos(pitch)
zh = -magValue[X] * (roll) * math.sin(pitch) + magValue[Y] * math.sin(roll) + magValue[Z] * math.cos(roll) * math.cos(pitch)
heading = 180 * math.atan2(yh, xh)/math.pi
if (yh >= 0):
return heading
else:
return (360 + heading)
if __name__ == "__main__":
acc_mag=lsm303d()
while True:
print(acc_mag.getRealAccel())
while True:
if acc_mag.isMagReady():
break
print(acc_mag.getHeading())
# Do not use, math error
# print acc_mag.getTiltHeading()