LSM303D 6DoF Motion Sensor Breakout - Arduino

Ahoy!

I’ve purchased a LSM303D 6DoF Motion Sensor Breakout and I’m trying to use it with a Bluno Beetle V1.1.

I’ve connected the pins as follows:

BlunoLSM303D
SDA → SDA
SCL → SCL
VIN → 3-6V
GND → GND

Now I’m trying the following:

/* LSM303DLM Example Code base on LSM303DLH example code by Jim Lindblom SparkFun Electronics

   date: 9/6/11
   license: Creative commons share-alike v3.0

   Modified by:Frankie.Chu
   Modified by:Jacky.Zhang 2014-12-11: Ported to 6-Axis Accelerometer&Compass of Seeed Studio
   Modified by:Jacky.Zhang 2015-1-6: added SPI driver

   Summary:
   Show how to calculate level and tilt-compensated heading using
   the snazzy LSM303DLH 3-axis magnetometer/3-axis accelerometer.

   Firmware:
   You can set the accelerometer's full-scale range by setting
   the SCALE constant to either 2, 4, or 8. This value is used
   in the initLSM303() function. For the most part, all other
   registers in the LSM303 will be at their default value.

   Use the write() and read() functions to write
   to and read from the LSM303's internal registers.

   Use getLSM303_accel() and getLSM303_mag() to get the acceleration
   and magneto values from the LSM303. You'll need to pass each of
   those functions an array, where the data will be stored upon
   return from the void.

   getHeading() calculates a heading assuming the sensor is level.
   A float between 0 and 360 is returned. You need to pass it a
   array with magneto values.

   getTiltHeading() calculates a tilt-compensated heading.
   A float between 0 and 360 degrees is returned. You need
   to pass this function both a magneto and acceleration array.

   Headings are calculated as specified in AN3192:
   http://www.sparkfun.com/datasheets/Sensors/Magneto/Tilt%20Compensated%20Compass.pdf
*/

/*
hardware & software comment
I2C mode:
1, solder the jumper "I2C EN" and the jumper of ADDR to 0x1E
2, use Lsm303d.initI2C() function to initialize the Grove by I2C
SPI mode:
1, break the jumper "I2C_EN" and the jumper ADDR to any side
2, define a pin as chip select for SPI protocol.
3, use Lsm303d.initSPI(SPI_CS) function to initialize the Grove by SPI
SPI.h sets these for us in arduino
const int SDI = 11;
const int SDO = 12;
const int SCL = 13;
*/

#include <LSM303D.h>
#include <Wire.h>
#include <SPI.h>

/* Global variables */
int accel[3];  // we'll store the raw acceleration values here
int mag[3];  // raw magnetometer values stored here
float realAccel[3];  // calculated acceleration values here
float heading, titleHeading;

#define SPI_CS 10

void setup()
{
    char rtn = 0;
    Serial.begin(115200);  // Serial is used for debugging
    Serial.println("\r\npower on");
    rtn = Lsm303d.initI2C();
    //rtn = Lsm303d.initSPI(SPI_CS);
    if(rtn != 0)  // Initialize the LSM303, using a SCALE full-scale range
    {
        Serial.println("\r\nLSM303D is not found");
        while(1);
    }
    else
    {
        Serial.println("\r\nLSM303D is found");
    }
}

void loop()
{
    Serial.println("\r\n**************");
    //getLSM303_accel(accel);  // get the acceleration values and store them in the accel array
    Lsm303d.getAccel(accel);
    while(!Lsm303d.isMagReady());// wait for the magnetometer readings to be ready
    Lsm303d.getMag(mag);  // get the magnetometer values, store them in mag

    for (int i=0; i<3; i++)
    {
        realAccel[i] = accel[i] / pow(2, 15) * ACCELE_SCALE;  // calculate real acceleration values, in units of g
    }
    heading = Lsm303d.getHeading(mag);
    titleHeading = Lsm303d.getTiltHeading(mag, realAccel);

    printValues();

    delay(200);  // delay for serial readability
}

void printValues()
{  
    Serial.println("Acceleration of X,Y,Z is");
    for (int i=0; i<3; i++)
    {
        Serial.print(realAccel[i]);
        Serial.println("g");
    }
    //print both the level, and tilt-compensated headings below to compare
    Serial.println("The clockwise angle between the magnetic north and x-axis: ");
    Serial.print(heading, 3); // this only works if the sensor is level
    Serial.println(" degrees");
    Serial.print("The clockwise angle between the magnetic north and the projection");
    Serial.println(" of the positive x-axis in the horizontal plane: ");
    Serial.print(titleHeading, 3);  // see how awesome tilt compensation is?!
    Serial.println(" degrees");
}

But I cannot get pass this line: rtn = Lsm303d.initI2C();

Something happens in the initialization of the sensor and I can see no output nor errors. Arrrr!

Does anyone here have some suggestion on how to solve this issue?

Thanks in advance,

Salvo.

Greetings,

I also own a LSM303D breakout. I don’t own an Arduino. Looking at the product page here, there’s no support stated for Pico or Arduino. As stated with the “Compatible with Raspberry Pi 3B+, 3, 2, B+, A+, Zero, and Zero W” line.

After asking a similar question on the forum in this post, I (with assistance from the ever helpful Hel) did manage to find this clever persons implementation on github for the LSM303D. A link to that.

Using this I was able to return meaningful data from the sensor using a Pico. It could probably be adapted for the Arduino, as I’d imagine the micro pythonic principles are not too far apart.

Another forum poster maybe able to help further for the Arduino implementation.

I hope this helps you in some way. 👍

Cheers! 😀

Hello and thanks for your suggestions :)

The product page is stating “This 6 Degrees of Freedom Motion Sensor Breakout can detect acceleration in three axes - X, Y, and Z - as well as three axes of magnetic heading. It’s ideal for building into robots, rockets, and rovers, or anywhere else where you want to measure motion accurately. It’s compatible with Raspberry Pi or Arduino.” Probably the Arduino compatibility hasn’t been properly documented.

In regard to the post you shared, you mention “After some tinkering with the i2c pin numbers. and some light debugging. It’s accelerometer is returning results.” Do you remember what pin number worked for you? Also did you have to cut the traces between solder pads to change the i2c address?

Thanks again for your help!

Salvo

Here’s the code I was using. Please note that it needed the Pi Foundations default micro python uf2 file to work. Would have no clue as to how that would translate to the Arduino.

Good luck!

'''
Currently doesn't work with the Pimoroni micropython release. Only with the Pi Foundation's default .uf2
Found on github, all credit, thanks and libations go to: https://github.com/staberas/LSM303D-Pico-Micropython
Made some minor tweaks and formatting changes with the output to terminal, otherwise unchanged
'''
from machine import UART, Pin, I2C
import time
import sys
from math import atan2, pi

xMag = 0
yMag = 0
zMag = 0
heading=0

## SET I2C bus - using pico pins 1-2 | 1, scl=machine.Pin(3), sda=machine.Pin(2)
sda=machine.Pin(26)
scl=machine.Pin(27)
i2c=machine.I2C(1,sda=sda, scl=scl, freq=100000)

## Enable LSM303D accelerator at I2C addr 0x1D => 29
config=bytearray(1)
config[0]=39+8
## Reg Control1: (0x20) 50Hz+enable (0x57) + block update
i2c.writeto_mem(29, 32, config)

config=bytearray(1)   
config[0]=0
# LSM303D Mag address, 0x1D(29) or 0x1E(30) 
# Select MR register, 0x02(02)
# 0x00(00) Continous conversion mode
config[0]=0
i2c.writeto_mem(29, 34, config) 
config[0]=0
i2c.writeto_mem(29, 35, config) 
config[0]=100
i2c.writeto_mem(29, 36, config) 
config[0]=32
i2c.writeto_mem(29, 37, config)
config[0]=0
i2c.writeto_mem(29, 38, config) 


def get_axis(reg): ## 40 - X , 42 - Y , 44 - Z
    high=bytearray(1)
    low=bytearray(1)
    i2c.readfrom_mem_into(29, reg, low)
    i2c.readfrom_mem_into(29, reg+1, high)
    res = high[0] * 256 + low[0]
    if (res<16384):
        result = res/16384.0
    elif (res>=16384 & res<49152):
        result = (32768-res)/16384.0
    else: 
        result = (res-65536)/16384.0
    return result

def getMagX():
    high=bytearray(1)
    low=bytearray(1)
    # X-Axis Mag MSB, X-Axis Mag LSB
    i2c.readfrom_mem_into(29, 8, low)
    i2c.readfrom_mem_into(29, 9, high)

    # Convert the data
    xMag = high[0] * 256 + low[0]
    #xMag = data0 * 256 + data1
    if xMag > 32767 :
        xMag -= 65536
    return xMag


def getMagY():
    high=bytearray(1)
    low=bytearray(1)
    # Y-Axis Mag MSB, Y-Axis Mag LSB
    i2c.readfrom_mem_into(29, 10, low)
    i2c.readfrom_mem_into(29, 11, high)
    
    # Convert the data
    yMag = high[0] * 256 + low[0]
    if yMag > 32767 :
        yMag -= 65536
    return yMag


def getMagZ():
    high=bytearray(1)
    low=bytearray(1)
    # Z-Axis Mag MSB, Z-Axis Mag LSB
    i2c.readfrom_mem_into(29, 12, low)
    i2c.readfrom_mem_into(29, 13, high)

    # Convert the data
    zMag = high[0] * 256 + low[0]
    if zMag > 32767 :
        zMag -= 65536
    return zMag

while True:
    time.sleep(.1) 
    xMag = getMagX()
    yMag = getMagY()
    zMag = getMagZ()
    x = ( get_axis(40) + 1)
    y = (-get_axis(42) + 1)
    z = (-get_axis(44) + 1)
    try:
        heading = 180*atan2(yMag,xMag)/pi #assume pitch, roll are 0  
        if(heading < 0):
            heading += 360
        #print("X:", f'{x:.3f}', "Y:", f'{y:.3f}', "Z:", f'{z:.3f}', "xMag:", xMag,"yMag:", yMag, "zMag:", zMag, "Heading:", heading," ")
        #print("X:", f'{x:.3f}', "Y:", f'{y:.3f}', "Z:", f'{z:.3f}', "Heading:", round(heading, 1), "X Mag:", round(xMag),"Y Mag:", round(yMag), "Z Mag:", round(zMag))
        print("X:", f'{x:.4f}', "Y:", f'{y:.4f}', "Z:", f'{z:.4f}', "Heading:", round(heading, 1))
    except:
        print("fail")        
    
    time.sleep(.2)

SOLVED!!!

I missed this bit of info on the product page: The trace between the solder pads (marked ADDR) can be cut (carefully with a craft knife) to change the I2C address from the default of 0x1D to 0x1E, meaning that you can use up to two sensors on the same Raspberry Pi or Arduino. If cut, the pads can be bridged again by soldering to reset the address to 0x1D.

Once I cut the trace between the solder pads, it changed the I2C address and the sensor started to work!
Both Magnetometer and Accellerometer ar working like a charm!

I’m so happy right now!

2 Likes

Glad you got it sorted!