MinIMU accelerometer read outs flip between 1g and 0g

Hello,

I just received my MinIMU-9 and wanted to access it with a raspberryPi.
I started with the accelerometer. After some testing I now get partly reasonable results:

Accelerometer:   X:     -0.000977       Y:      -0.000977       Z:      -0.002930
Accelerometer:   X:     -0.011719       Y:      -0.030275       Z:      -0.001953
Accelerometer:   X:     0.003906        Y:      -0.040042       Z:      -0.001953
Accelerometer:   X:     -0.003906       Y:      -0.015626       Z:      -0.003906
Accelerometer:   X:     0.015626        Y:      -0.006836       Z:      -1.056705
Accelerometer:   X:     -0.004883       Y:      -0.001953       Z:      -1.040103
Accelerometer:   X:     -0.005860       Y:      -0.028322       Z:      -0.002930
Accelerometer:   X:     -0.003906       Y:      -0.002930       Z:      -0.001953
Accelerometer:   X:     0.019532        Y:      -0.030275       Z:      -0.004883
Accelerometer:   X:     0.003906        Y:      -0.006836       Z:      -1.009827
Accelerometer:   X:     -0.007813       Y:      -0.001953       Z:      -1.031313
Accelerometer:   X:     -0.005860       Y:      -0.001953       Z:      -0.002930
Accelerometer:   X:     0.005860        Y:      -0.027345       Z:      -1.027406
Accelerometer:   X:     -0.004883       Y:      -0.041018       Z:      -1.014710
Accelerometer:   X:     0.003906        Y:      -0.030275       Z:      -1.044009
Accelerometer:   X:     0.003906        Y:      -0.028322       Z:      -1.042056
Accelerometer:   X:     -0.005860       Y:      -0.005860       Z:      -1.029360
Accelerometer:   X:     -0.007813       Y:      -0.004883       Z:      -0.007813
Accelerometer:   X:     -0.004883       Y:      -0.001953       Z:      -1.042056
Accelerometer:   X:     -0.004883       Y:      -0.003906       Z:      -1.030336
Accelerometer:   X:     0.005860        Y:      -0.002930       Z:      -0.005860
Accelerometer:   X:     -0.006836       Y:      -0.041018       Z:      -1.042056
Accelerometer:   X:     -0.004883       Y:      -0.001953       Z:      -1.040103
Accelerometer:   X:     -0.005860       Y:      -0.005860       Z:      -0.006836
Accelerometer:   X:     0.000000        Y:      -0.028322       Z:      -1.043032
Accelerometer:   X:     -0.000977       Y:      -0.002930       Z:      -0.007813
Accelerometer:   X:     -0.006836       Y:      -0.002930       Z:      -0.003906
Accelerometer:   X:     -0.004883       Y:      -0.028322       Z:      -1.028383
Accelerometer:   X:     0.000000        Y:      -0.004883       Z:      -0.006836
Accelerometer:   X:     -0.003906       Y:      -0.028322       Z:      -1.010804
Accelerometer:   X:     0.000000        Y:      -0.002930       Z:      -0.005860
Accelerometer:   X:     -0.007813       Y:      -0.015626       Z:      -1.028383
Accelerometer:   X:     -0.005860       Y:      -0.044925       Z:      -1.028383

As expected the acceleration measured in Z-direction is around -1 g. When I turn my bread board than it shows up on the other axis’ as expected.
My problems are the “holes” between these correct values. As you can see between several -1g-values are several one around 0g.
I already enabled the BDU bit changed the period of the read loop between 100ms and 1s and tried higher output frequencies for the chip (50 Hz, 100 Hz and 400 Hz so far), but nothing helped.

Here is the important part of the code for interfacing the sensor I use:

Initializing

int facc;
const float accelerometerGainSI = 0x3fff; /*!< constant to get SI units from the accelerometer output */

int accelerometerInit(char deviceName[])
{
    //initialize i2c-device
    facc = open(deviceName, O_RDWR | O_NOCTTY | O_NDELAY);
    if (facc == -1)
    {
        printf("open_port: Unable to open i2c-bus");
        return FALSE; //0 == error
    }

    if (ioctl(facc, I2C_SLAVE, LSM303_LIN_ACC_ADDR) < 0)
    {
        printf("Failed to acquire bus access and/or talk to slave.\n");
        return FALSE; // 0 == error
    }

    // LSM303 configuration settings
    int8_t LSM303_CTRL_REG1_set = (1<<PM0);                     // Set Power Mode to normal
    LSM303_CTRL_REG1_set |= (1<<DR0);                           // Set output data rate to 100 Hz (maybe 50 Hz enough?) //0b00100111;  // (Atheel recommends: 0b00100111) enable: normal power mode, highest filter cut-off freq, Z-Y-X axes
    LSM303_CTRL_REG1_set |= (1<<Zen) | (1<<Yen) | (1<<Xen);     // Enable x,y and z axis of the accelerometer

    /*
          Enable block data update (BDU)
          Use Full scale of +-2g (FS1 and FS0 = 0)
        */
    int8_t LSM303_CTRL_REG4_set = (1<<BDU) | (1<<BLE);

    /* set LSM303 CTRL REG1 register
           create an array of 2 bytes
           1st byte: Register address
           2nd byte: value to write to register
        */
    int8_t reg[2];
    reg[0] = LSM303_CTRL_REG1_A;
    reg[1] = LSM303_CTRL_REG1_set;

    //Update register with new value
    if (write(facc, reg, 2) != 2)
    {
        printf("Failed to set REG1\n");
        return FALSE; //0 == error;
    }

    // set LSM303 CTRL REG4 register
    reg[0] = LSM303_CTRL_REG4_A;
    reg[1] = LSM303_CTRL_REG4_set;
    if (write(facc, reg, 2) != 2)
    {
        printf("Failed to set REG4\n");
        return FALSE; //0 == error;
    }

    return TRUE;
}

Read out

int accelerometerReadSI(float xyz[3])
{
    int status = accelerometerReadMeasurements(xyz);

    xyz[0] /= accelerometerGainSI;
    xyz[1] /= accelerometerGainSI;
    xyz[2] /= accelerometerGainSI;

    return status;
}


int accelerometerReadMeasurements(float xyz[3])
{
    /*
        start register is OUT_X_L_A.
        For multiple read, the MSB has to be set. Then the client will
        auto increment the register address.
    */
    int8_t readReg = LSM303_OUT_X_L_A | LSM303_SUB_ADDR_multiple_read;

    //Tell the client to expect multiple reading from start register
    if (write(facc, &readReg, 1) != 1)
    {
        printf("Failed set read register\n");
        return FALSE; //0 == error;
    }

    int8_t buffer[6];   ///< buffer to hold 2 bytes of data for every axis
    //Read data for all 3 axis at once
    if(read(facc, buffer, 6) != 6)
    {
        printf("Read accelerometer xyz failed\n");
        return FALSE;
    }

    //convert to float
    xyz[0] = (float) ((buffer[0]<<8 | buffer[1]));
    xyz[1] = (float) ((buffer[2]<<8 | buffer[3]));
    xyz[2] = (float) ((buffer[4]<<8 | buffer[5]));

    return TRUE;
}

It would be gread if someone would have a suggestion. I will try to implement the magnetometer tomorrow. Maybe I will stumble upon a mistake which would fix my problem.

Best regards,

Jan

Hello, Jan.

You left out important parts of the code, such as the definition of PM0 and your main loop. If you want more help with your code, I suggest simplifying it down to the simplest possible thing that should work but doesn’t, and posting the entire code here. Also, try printing the raw integer values from the accelerometer and make sure those look OK before you convert them to floats and scale them.

I got the MinIMU-9 v2 working nicely on my raspberry pi a while ago. You can see my code here:

github.com/DavidEGrayson/minimu9-rpi-ahrs

This is still under development and we cannot really support it, but if you know what you are doing then you can probably figure it out and it will save you time. Also, it would be fun to have a collaborator :smiley: . It only supports the MinIMU-9 v2 right now, so if you have the older version (MinIMU-9) then you’ll have to make some modifications.

I’m curious, what kernel or distribution are you using to get your I2C support?

–David

Ok.
I found my mistake. I used int8_t for the 6 byte-buffer. With uint8_t it works. :cry:
I hate when these kind of things happen :wink:

But to see the good side of it, I saw your neat code which makes me thinking again if I should use C++ over C.
While reading I think I found a small bug. Check line 46 of I2CBus.cpp. Shouldn’t it be currentAddress = address? But maybe I’m just tired.

At the moment I’m using the raspbian distribution. Before I2C-support got included into the rpi.org-kernel I used the bootc-kernel. At the moment I’m at the beginning of using a RT-Kernel. (Unfortunately^^) I have suceeded in compiling a kernel with RT_PREEMPT patch and one with xenomai. Now I’m spoilt for choice and have to somehow determine which would be more useful for my application.

Ok. I need some sleep. Hope the magnetometer will run without problems tomorrow…

Hey you’re right about the bug! I should fix that. Thanks.

–David