#!/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()