My Accelerometer Problem

I have purchased an accelerometer, on the back is printed on the board MOD-SMB380, I have used the accelerometer driver, with the example code that is in the brochure for the accelerometer. I have the pins plugged into the serial port on the Domino board, with the cable supplied to the accelerometer. My firmware is up to date. And I have the latest drivers. When I run the code, there is an error which points to the driver code.

An unhandled exception of type ‘System.InvalidOperationException’ occurred in Microsoft.SPOT.Hardware.dll
FEZ_Extensions_Accelerometer.cs Line 51 _spi.WriteRead(write, read);

static private byte ReadRegister(byte address) // address value is 20 at function call.
{
write[0] = (byte)(0x80 | address);
write[1] = 0xFF;
_spi.WriteRead(write, read); // <<-- This is line 51.
return read[1];
}

If you hover write in the above line, two lines show up [0] 148 and [1] 255
Hovering read will show [0] 0, and [1] 0
Hovering _spi.WriteRead shows what appears to be configuration data states.

The comments are my addition and do not appear in the actual code.

If you want any additional information I will be happy to supply it. Just so we can get by the obligatory did I plug it in and stuff. I have tested to make sure that there is power to the device. I have tried reversing the plug at the serial port, although, the red wire was originally plugged into the 1 on the serial port. There is only one way to plug in the accelerometer. My current firmware is USBizi (FEZ Mini, FEZ Domino, FEZ Rhino, FEZ Panda) V 4.1.3.0

As per usual, I look forward to hearing from anyone whom is able to help me on this.

Gene:

I got my Accelerometer recently. And I got the same problem.
What you have to do is to change the value from 100 to 200, and that should work.

static public void Initialize()
            {
                if (FEZ.FEZ_System.GetSystemType() == FEZ_Type.Domino)
                {
                    // change 100 to 200 as shown here
                    _spi = new SPI(new SPI.Configuration((Cpu.Pin)FEZ_Pin.Digital.UEXT10, false, 0, 0, true, true, 200, SPI.SPI_module.SPI2));
                                }
                else if (FEZ.FEZ_System.GetSystemType() == FEZ_Type.Mini)
                {
                    _spi = new SPI(new SPI.Configuration((Cpu.Pin)FEZ_Pin.Digital.UEXT10, false, 0, 0, true, true, 100, SPI.SPI_module.SPI1));
                }
                else
                {
                    throw new Exception("Unknown System Type!");
                }

Sam, I bow to your superior knowledge. This solution works, could you please explain to me why this works?

Gene:
Frankly, I’m new to the Accelerometer as well. This is the first time I got my hand on one! :smiley:
I actually found the solution on this problem at this thread:
[url]http://www.tinyclr.com/forum/4/433/[/url]

And some further knowledge on SPI is from this free e-book, page 82
[url]http://www.tinyclr.com/downloads/Beginners%20guide%20to%20NETMF.pdf[/url]

It has something to do with Hardware and SPI clock speed.

Have you purchased the same accelerometer? Because I seem to be having a problem with the Z axis being out of phase to the X and Y axises. It is hard to explain this without a graphic of some type, but it seems that in order to get the Z axis to zero, you have to flip the accelerometer 90 degrees. But flipping the Z axis will affect the X axis. This would seem to preclude me from straight and level flight. It seems impossible to find a plane(geometric) where X,Y and Z all are zero.

This is the one I got, number five from the bottom
[url]http://www.tinyclr.com/hardware/1/fez-domino/#/list/2/[/url]

Here is the value I got from mine, using the driver provided.

[quote]X: 5 Y: 0 Z: 92
X: 5 Y: 0 Z: 91
X: 4 Y: 0 Z: 92
X: 4 Y: 0 Z: 92
X: 4 Y: 0 Z: 91
X: 4 Y: 0 Z: 91
X: 4 Y: 0 Z: 91
X: 5 Y: 0 Z: 91
X: 5 Y: -1 Z: 91
X: 4 Y: 0 Z: 91
X: 4 Y: 0 Z: 91
…[/quote]

I think the values from the accelerometer are raw.
And I’m not sure that the measurements is in G unit either!

the axes seem to be as shown in the image below.

All three will only be zero during free fall, if drag is minimal/non existent.

Gravity is constantly exerting ±1G on the G sensor… :slight_smile:

Hmmm, I looked at the driver and it looks broken. The sensor returns the G in 2 bytes per axis.
Driver code:


            static public void GetXYZ(out sbyte x, out sbyte y, out sbyte z)
            {
                x = (sbyte)ReadRegister(0x02);
                x = (sbyte)ReadRegister(0x03);

                y = (sbyte)ReadRegister(0x04);
                y = (sbyte)ReadRegister(0x05);

                z = (sbyte)ReadRegister(0x06);
                z = (sbyte)ReadRegister(0x07);
            }

Should it not be something like:


            static public void GetXYZ(out sbyte x, out sbyte y, out sbyte z)
            {
                x = (sbyte)(ReadRegister(0x03));

                y = (sbyte)ReadRegister(0x05);

                z = (sbyte)ReadRegister(0x07);
            }

Or to get the 10 bit resolution:


        static public void GetXYZ(out short x, out short y, out short z)
        {
            x = (short)(ReadRegister(0x03) << 2);
            x = (short)(x + (ReadRegister(0x02) >> 6));

            y = (short)(ReadRegister(0x05) << 2);
            y = (short)(y + (ReadRegister(0x04) >> 6));

            z = (short)(ReadRegister(0x07) << 2);
            z = (short)(z + (ReadRegister(0x06) >> 6));
        }

I have not tested this code as I don’t have this G Sensor…

With the old driver you should get 64 counts per G if the sensor is calibrated. With the this code change you should get 256 counts per G.

Sam, you get 91 with the board flat on the table. What do you get if you invert it? -91? or +27? :slight_smile:

Thanks,
Errol

Following are the results from your suggestion:

Here is the data before and after invert.
Using the original driver.

            
            static public void GetXYZ(out sbyte x, out sbyte y, out sbyte z)
            {
                x = (sbyte)ReadRegister(0x02);
                x = (sbyte)ReadRegister(0x03);

                y = (sbyte)ReadRegister(0x04);
                y = (sbyte)ReadRegister(0x05);

                z = (sbyte)ReadRegister(0x06);
                z = (sbyte)ReadRegister(0x07);
            }

[quote]…
X: -27 Y: 0 Z: 81
X: -35 Y: -5 Z: 74
X: -42 Y: -4 Z: 61
X: -46 Y: -9 Z: 51
X: -49 Y: -13 Z: 33
X: -57 Y: -8 Z: 21
X: -49 Y: -6 Z: 19
X: -47 Y: -14 Z: 5
X: -39 Y: -12 Z: -6
X: -23 Y: -4 Z: -12
X: -20 Y: 4 Z: -31
X: -14 Y: 1 Z: -45
X: 4 Y: -18 Z: 8
X: 1 Y: -16 Z: 2
X: 6 Y: -18 Z: -34
X: 11 Y: -8 Z: -37
X: 11 Y: -8 Z: -36
X: 11 Y: -8 Z: -36
X: 11 Y: -8 Z: -36
X: 11 Y: -8 Z: -36
X: 11 Y: -8 Z: -36
X: 11 Y: -8 Z: -36
X: 11 Y: -8 Z: -37

[/quote]

Here is the output before and after invert
with this change


            static public void GetXYZ(out sbyte x, out sbyte y, out sbyte z)
            {
                x = (sbyte)(ReadRegister(0x03));

                y = (sbyte)ReadRegister(0x05);

                z = (sbyte)ReadRegister(0x07);
             }

And this is the output before and after invert
with this code


            static public void GetXYZ(out short x, out short y, out short z)
            {
                x = (short)(ReadRegister(0x03) << 2);
                x = (short)(x + (ReadRegister(0x02) >> 6));

                y = (short)(ReadRegister(0x05) << 2);
                y = (short)(y + (ReadRegister(0x04) >> 6));

                z = (short)(ReadRegister(0x07) << 2);
                z = (short)(z + (ReadRegister(0x06) >> 6));
            }

[quote]X: 50 Y: 994 Z: 869
X: 49 Y: 994 Z: 869
X: 49 Y: 994 Z: 870
X: 50 Y: 993 Z: 868
X: 49 Y: 994 Z: 871
X: 49 Y: 993 Z: 869
X: 49 Y: 994 Z: 869
X: 48 Y: 999 Z: 863
X: 50 Y: 1010 Z: 832
X: 50 Y: 959 Z: 841
X: 75 Y: 932 Z: 855
X: 51 Y: 946 Z: 880
X: 1023 Y: 918 Z: 928
X: 977 Y: 927 Z: 970
X: 922 Y: 937 Z: 1010
X: 877 Y: 941 Z: 11
X: 862 Y: 954 Z: 54
X: 831 Y: 995 Z: 142
X: 834 Y: 1003 Z: 199
X: 856 Y: 941 Z: 211
X: 891 Y: 20 Z: 279
X: 873 Y: 7 Z: 305
X: 928 Y: 9 Z: 297
X: 979 Y: 1009 Z: 334
X: 954 Y: 1 Z: 395
X: 944 Y: 1018 Z: 322
X: 1018 Y: 1017 Z: 391
X: 1003 Y: 1019 Z: 355
X: 1019 Y: 1019 Z: 354
X: 2 Y: 1015 Z: 358
X: 1018 Y: 1010 Z: 358
X: 3 Y: 1020 Z: 347
X: 4 Y: 1021 Z: 348
X: 10 Y: 11 Z: 318
X: 31 Y: 1000 Z: 351
X: 10 Y: 1014 Z: 356
X: 18 Y: 1017 Z: 359
X: 21 Y: 1017 Z: 356
X: 22 Y: 1016 Z: 358
X: 21 Y: 1016 Z: 358
X: 21 Y: 1017 Z: 358
X: 21 Y: 1016 Z: 358
X: 21 Y: 1016 Z: 359
X: 21 Y: 1016 Z: 359

[/quote]

Oh, yeah, I didn’t take the sign into account…


            static public void GetXYZ(out short x, out short y, out short z)
            {
                x = (short)(ReadRegister(0x03) << 2);
                x = (short)(x + (ReadRegister(0x02) >> 6));
                if(x>511)
                {
                    x=(short)(x-1023);
                }

                y = (short)(ReadRegister(0x05) << 2);
                y = (short)(y + (ReadRegister(0x04) >> 6));
                if(y>511)
                {
                    y=(short)(y-1023);
                }
 
                z = (short)(ReadRegister(0x07) << 2);
                z = (short)(z + (ReadRegister(0x06) >> 6));
                if(z>511)
                {
                    z=(short)(z-1023);
                }
            }

So you do get a swing of 128(actually 131 but close enough) if you switch from +1G to -1G.
To calibrate it you must subtract 29.5 from the Z value. (Max-((Max - Min)/2)).
Then you should get +64 one way, 0 on it’s side and -64 upside down…

You can do the calibration for each axis and write it to flash in the G sensor, then it should always be calibrated. But the driver doesn’t contain that functionality yet…

Thanks,
Errol

What is the normal range of numbers? I can only get -70 to 70 if I treat it nice, if I shake it like a welfare baby I get 130 or so.

Do I need to make changes in the driver?

No, you don’t have to make changes. The code I posted just gives you four times the resolution. The sensor gives you 10 bits of data, but the default driver only uses 8 bits and discards 2 bits.

If you get more or less the same reading upright and upside down then you don’t have an offset error. If you really go into the math(To use the G sensor to calculate speed and distance traveled) then you might have to multiply your readings with 0.9 or something to get to +63 and -63.

Shaking it does generate extra G so it going wild is according to design… :slight_smile:

Thanks,
Errol

Errol:

Thanks for helping out here.

You’re helping at least one blind mouse investigating an (elephant) accelerometer.

I’m trying to learn more on this accelerometer (my first encounter with this kind!) :-[

Where the 29.5 comes from?

Thanks in advance,

sam

Hi Sam,

No problem. I don’t have experience with this sensor, but have another one from Freescale, an MMA7455 on my robot.

The 29.5 came from the formula I tried to put in brackets. :slight_smile:

(Max_Reading - ((Max_Reading - Min_Reading)/2))

This calculates the offset required to get an equal swing to positive G and negative G.

To get it really accurate you will also have to adjust the “gain” of the axis. To do that you must multiply it with a value that gives you an answer of exactly +63 and -63. Your Z axis is already very close, but the others might not be.

Hope this helps…

Thanks,
Errol

Gentlemen, I am getting a lot out of this conversation.

I did a test with my accelerometer in a test where I sat the accelerometer in a level for each of the planes of axis, X, Y, and Z. I did ten seconds of sampling at the rate of 100 milliseconds. I took the average and printed it out. I made sure that the test measurements were only taken when the accelerometer was at a level, and there was no movement whatsoever. My results of those six tests.

Z Axis Flip Test
X Ten Second Average: 1
Y Ten Second Average: -1
Z Ten Second Average: 60

X Ten Second Average: 0
Y Ten Second Average: -1
Z Ten Second Average: -70

X Axis Flip Test
X Ten Second Average: -62
Y Ten Second Average: 0
Z Ten Second Average: -4

X Ten Second Average: 62
Y Ten Second Average: -2
Z Ten Second Average: -6

Y Axis Flip Test
X Ten Second Average: 0
Y Ten Second Average: -65
Z Ten Second Average: -3

X Ten Second Average: 0
Y Ten Second Average: 60
Z Ten Second Average: -3

I thought for the most part that the axises were pretty spot on accurate, but the Z axis is clearly not equal in its tests. Y had some deviation, but that might have been how I was holding the accelerometer for the tests. My problems are these.

Is there another way of fixing the accuracy difference in the accelerometer other than hard coding on my end of the program? Two, and this problem is somewhat more vexing to me although it is probably of no consequence to anyone who knows how to use this properly, what does these number mean? What is a 70 Z axis, in comparison to let us say 130 when the accelerometer is moving? Do I have to do drop testing to determine what the numbers actually mean? Also, how do I quantify 70 Z axis into a known direction as opposed to 45? Do I also have to do my own independent measurements to figure this out, or is there some type of chart that I can use?

My reason in purchasing this device was for rudimentary localization of a robot inside of a known space. I realize that I might better be served for more direct localization with a gyrometer, but I thought that this might also be useful in this purpose. If it can not be used for this, then what other purposed do I use it for?

When speaking of eight bits of information as opposed to the possible ten bits, would the two bit increase result in more accuracy, or would it simply provide me with more numbers? I realize that it could give me number ranges in the 1024 range, but would that be any better than the 256 that 8 bits would give?

Forgive my rather long posting, but I am trying to understand this piece of hardware better. I also appreciate the postings already, as they have helped me understand this better. I thank you for being patient with me in this.

Re the calibration: The sensor has an eeprom where you can store the calibration values. This will have to be done once. Then It will give you the correct values directly, without hard coding anything. Thus, if you want to go into production then each G sensor will have to go through it’s own callibration, but the software don’t change…

Re the meaning of the numbers. If all is calibrated correctly then a value of 63 means that the sensor is accelerating at 10 meters per second. This holds true for all directions except down, as the earth is pulling on the G sensor at 1G(9.8m/s2).

To get actual G you need to divide the value from the sensor by 63(original driver, or 255 modified driver).

Convert the G to acceleration by multipling the G * 10.

To get the speed you are moving at you must integrate the acceleration value. That means that you take a time frame, such as 100ms, then you take a acceleration reading every 100ms, you multiply it by 0.1, for the time frame, then you add it to your current speed.

To get your distance traveled you must integrate the speed in the same way. Every 100ms you take your current speed, multiply it by 0.1 and add it to your current distance traveled.

Of course you will have to subtract the down G force from the Z axis before you start.

Also, errors very quickly add up. That is why this type of navigation, expecially with cheap G sensors, can only be used for a few seconds, then you need to reset to a known frame of reference.

This also just gives you direction relative to the G sensor. The G sensor cant detect if you rotate it flat on the desk.

I don’t know what the noise is like on that sensor, but 10 bits gives you an accuracy of 1/256’th of a G where 8 bits gives you 1/64’th of a G.

Forgive my long answer… :slight_smile:

For the more mathematically inclined, there is this document:
[url]http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/APPLICATION_NOTE/CD00268887.pdf[/url]

It describes the calibration of a G sensor, and the method of determining tilt from the G readings.

I can’t remember anything about matrix math so this whole document is over my head… :slight_smile: