Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Netduino Go with MMA7361 Accelerometer


  • Please log in to reply
7 replies to this topic

#1 hoquet

hoquet

    Member

  • Members
  • PipPip
  • 12 posts

Posted 18 July 2012 - 05:00 AM

Hello everyone,

This is my first mini project with the netduinoGo and learning about robotics. I have a programming background, although 10 years ago in .net. I purchased the NetduinoGo starter kit with the button, led, potentiometer, etc.. I got all of it working and was able to make buttons respond, led's blink, etc.. Cool Huh?

I then added the shield base and got that to work. Atleast blink a light and power on. Now I wanted more. So I purchased an LCD, not knowing anything about whether or not it would work or others have used it and if there is some sample code out ther. Then I managed to get an LCD screen connected through various websites and tutuorials. I finally got the Hacktronics LCD Module working with the Netduino. Someone wrote an interface and class along with diagrams on what to connect the digital I/O to the Hacktronics. I can now write out whatever I want to the LCD screen. Although all string manipulations, truncations, etc. I have to handle myself. But it works, I even learned what the heck a resistor is. I also watched a youtube video on how to solder. Hey, it has been 15 years since I took any kind of physics.

Now I thought I would try my hand at an Virtuobotix MMA7361 Accelerometer which I order even before I wrote my first Netduino application. I learned that next time before ordering the hardware, see if there is some code that people have written is readily available for c#. Trying to convert Arduino classes and interfaces is nearly impossible. Anyways, I connected the accelerometer to the shield and followed code that someone else wrote for another accelerometer: Sparkfun ADXL 335

Very basic code:
 // Define our accelerometer inputs
        static AnalogInput accX;
        static AnalogInput accY;
        static AnalogInput accZ;

        public static void Main()
        {
            // Create the Inputs
            accX = new AnalogInput(Pins.GPIO_PIN_A0);
            accY = new AnalogInput(Pins.GPIO_PIN_A1);
            accZ = new AnalogInput(Pins.GPIO_PIN_A2);

            // Keep application alive via loop
            while (true)
            {
                // Read data from the sensor
                double x = (double)(accX.Read());
                double y = (double)(accY.Read());
                double z = (double)(accZ.Read());

                // Output data to screen
                Debug.Print("X: " + x + " Y: " + y + " Z: " + z);
            }
        }
So, what do I get for an output?

X: 0.48815628815628814 Y: 0.526984126984127 Z: 0.67252747252747258
X: 0.48815628815628814 Y: 0.5252747252747253 Z: 0.6676434676434676
X: 0.48986568986568985 Y: 0.52722832722832724 Z: 0.66935286935286931
X: 0.49108669108669106 Y: 0.52576312576312578 Z: 0.66984126984126979
X: 0.48888888888888887 Y: 0.52649572649572651 Z: 0.67130647130647125
X: 0.48766788766788766 Y: 0.52747252747252749 Z: 0.66862026862026858
X: 0.48888888888888887 Y: 0.52771672771672773 Z: 0.67057387057387052
X: 0.48840048840048839 Y: 0.52503052503052505 Z: 0.66935286935286931
X: 0.4879120879120879 Y: 0.5252747252747253 Z: 0.67106227106227101
X: 0.48913308913308912 Y: 0.5252747252747253 Z: 0.66788766788766785
X: 0.48717948717948717 Y: 0.52503052503052505 Z: 0.67057387057387052
X: 0.4879120879120879 Y: 0.52551892551892554 Z: 0.66984126984126979
X: 0.49108669108669106 Y: 0.52722832722832724 Z: 0.66862026862026858
.....

Great, seems like it is working. How the heck do I veryify that it works? Even though the device is sitting on my desk at home, the numbers keep changing. I read some articles about getting the g-force, radians, and using offsets. I just want something like degrees tilt in either of the 3 axis with 2 decimal places. Any resources anyone would recommend would be great. I'll keep posting my progress as well as I add a motor shield and the xbee shield. I'm just learning, so please keep it simple. I am also attaching the work that I have done. For the hacktronics LCD which is a 4 line 20 char, I would be happy to share my code and board configuration.

Thanks

Attached Files


Edited by Chris Walker, 18 July 2012 - 05:53 AM.
added [code][/code] tags


#2 nakchak

nakchak

    Advanced Member

  • Members
  • PipPipPip
  • 404 posts
  • LocationBristol, UK

Posted 18 July 2012 - 09:23 AM

Hi Hoquet Looks like you have the hard parts sorted :) I would suggest some normalised sampling, i.e. report the average of 5 readings, or take delta's between each reading, the delta should be able to give some indications of magnitude and direction of movement i.e. -ve number indicates movement in one direction, +ve movement in the other and 0 = no movement. If you round your results to fewer decimal places you will see that all the numbers remain static i.e. your X measurement is 0.49 for each of the posted responses which would indicate that it is at rest on a flat surface. Now as for translating the readings into degree's i would imagine that their is details in the datasheet for the accelerometer for translation into standard units... Nak.

#3 hoquet

hoquet

    Member

  • Members
  • PipPip
  • 12 posts

Posted 19 July 2012 - 04:40 AM

I looked over the datasheet on the MMA7361. Everything in it's reference lead me to arduino code and shields with differnt bit chips with values that didn't make sense.

I may have figured out what the values are that I am reading. I was looking for what analoginput.read was actually reading. I tried finding the information on the MMA7361 chip. After some time, I finally came across a good article about NETMF Analog input vs Microsoft SPOT http://www.tinyclr.c...m/topic?id=7832

The value I should see from a 12-bit Shield from the NetDuino Go performing analogInput.read() should be between 0 and 1 for 3.3v. The post helped. Anyways, from there I found an article on someone converting analog input to read values to degrees. http://www.dfrobot.c...1_(SKU:_DFR0143)


I understand most of the code, except for why they are subtracking 1.62, 1.74, and 1.48 from the voltage.




            // read the converted value from the sensor... this returns a double
            // between 0 (0V) and 1 (3.3V)
            analog_x = accX.Read();
            analog_y = accY.Read();
            analog_z = accZ.Read();

            // now, if we want, we can calculate the number of volts by multiplying
            // the converted value by 3.3
            vol_x = analog_x * 3.3;//convert analog_x-->voltage value(v)
            vol_y = analog_y * 3.3;
            vol_z = analog_z * 3.3;

            //range x: 0.83 - 2.41 1.62 
            // y: 0.96 - 2.53 1.74
            // z: 0.72 - 2.23 1.48

            add_x = vol_x - 1.62;//calculate the added x axis voltage value
            add_y = vol_y - 1.74;
            add_z = vol_z - 1.48;

            g_x = add_x / 0.8;//calculate the gram value
            g_y = add_y / 0.8;
            g_z = add_z / 0.8;

            if (g_x <= 1 && g_x >= -1) //We use this condition to prevent the overflow of asin(x).( If x>1 or x<-1, asin(x)=0)
            {
                degree_x = System.Math.Asin(g_x) * 180.0 / System.Math.PI;//calculate the degree value
                degree_y = System.Math.Asin(g_y) * 180.0 / System.Math.PI;
                degree_z = System.Math.Asin(g_z) * 180.0 / System.Math.PI;
            }
            //fix the overflow condition
            if (g_x > 1)
                degree_x = 90;
            if (g_x < -1)
                degree_x = -90;
            if (g_y > 1)
                degree_y = 90;
            if (g_y < -1)
                degree_y = -90;
            if (g_z > 1)
                degree_z = 90;
            if (g_z < -1)
                degree_z = -90;
            //#########################
            //print

Now the output seems a lot more reasonable, when I do tilt the board vertically, the y-axis reads 90. I will do more testing to make sure that it is calculating correctly. I'm excited, I feel like things are working...

Thanks

#4 Geancarlo2

Geancarlo2

    Advanced Member

  • Members
  • PipPipPip
  • 70 posts

Posted 19 July 2012 - 05:18 AM

"I understand most of the code, except for why they are subtracking 1.62, 1.74, and 1.48 from the voltage." I believe those are calibration values for zero-g: http://www.sparkfun....al/MMA7361L.pdf

#5 hoquet

hoquet

    Member

  • Members
  • PipPip
  • 12 posts

Posted 20 July 2012 - 02:16 AM

While working with the Accelerometer, I noticed that the Hacktronics LCD is slow to write. It is like watching a typewriter type left to write. I am not sure if that has to do with the library I download and the code/settings, but it is slowing down my reads from the accelerometer. The code was used from here: http://10rem.net/blo...th-the-netduino Has anyone worked with an LCD using this library? Also, how is it working with the nwazet display with the Netduino Go? Thanks

#6 Dan T

Dan T

    Advanced Member

  • Members
  • PipPipPip
  • 91 posts
  • LocationBoston (Greater)

Posted 20 July 2012 - 02:44 AM

I'll start with the easiest answer:

Great, seems like it is working. How the heck do I verify that it works?

That's easy! Just gently lift your fixture and slowly move a different axis into the gravity field.
If you move slowly, you'll see your Z axis values go down and whichever axis you are lifting go up.
You have to move slowly because these XL's are very sensitive to movement and vibration...and they have terrible noise, too. That's why your numbers keep changing.
Don't bump the table. Or DO bump the table and watch all your numbers jump around.


I found an article on someone converting analog input to read values to degrees. http://www.dfrobot.c...1_(SKU:_DFR0143)

I understand most of the code, except for why they are subtracking 1.62, 1.74, and 1.48 from the voltage.

            //range x: 0.83 - 2.41 1.62 
            // y: 0.96 - 2.53 1.74
            // z: 0.72 - 2.23 1.48

            add_x = vol_x - 1.62;//calculate the added x axis voltage value
            add_y = vol_y - 1.74;
            add_z = vol_z - 1.48;


The article you quote covers the reason for the subtraction. Zero g (no acceleration) is nominally halfscale at 1.65V, half of 3.3V fullscale. But the author found HIS part's actual performance was quite different so he calibrated his part -- he TUNED his program to match his part, by measuring the part's actual output repeatedly (and shaking the part?) to find it's extremes and averaging the limits to find the particular centers for each axis. He even put his tuning data in the comment. You should ignore this and subtract 1.65V, since YOUR part is different. (You can calibrate your part later. These XL's have terrible "offset" specs.)

Better yet, don't subtract volts - just skip the volts completely. Since your ADC (via Netduino) is fullscale 3.3V *and* your XL is fullscale 3.3V, your ADC conversion is conveniently eliminating the middle man (voltage) and going right to ratio of fullscale. In other words, subtract 0.5 from your readings (the "0g" value) and then multiply by 3.0g (the part's fullscale range, also expressed as +/- 1.5g) to get your accel in g's.

Using your values:

X axis: (0.49-0.5)*3.0g = -0.03g (or -30mg. This is very close to zero. Nice.)
Y axis: (0.53-0.5)*3.0g = 0.09g (or +90mg. Not great, but still reasonable.)
Z axis: (0.67-0.5)*3.0g = 0.51g (Oops! This was supposed to be 1g. Must be off by a factor of two somewhere. This ALWAYS happens to me.)

OK, So multiply by 6g, instead, and I'll leave you to figure out why... (I think the part have a choice of fullscale?)
Note that this makes the X and Y offsets twice as bad.

Finally, some bad news. Trigonometry tells us that the first 1 degree of tilt angle will result in 17.5 mg on the "zero g" axis that is tilting up toward gravity (Sine 1 deg = 0.0175).
Your Y axis offset is 180 mg which is ~10 degrees. And the darn things are noisy. If you calibrate out your offset, and if you average like crazy, and if your environment is very very quiet, you might get to a resolution of 0.1 degrees, but 0.01 degrees is out of reach, I think. (And we're talking resolution -- angle changes -- not absolute accuracy.)

But to focus on the positive... Nice job! You're measuring the pull of the Earth!!! Cool!

#7 hoquet

hoquet

    Member

  • Members
  • PipPip
  • 12 posts

Posted 24 July 2012 - 04:11 PM

Dan T, thank you for the response and the logic.

It seems if I skip the voltage calculation and go straight to the g calculation, then convert to angle, I get quite a bit of difference in the angle of x, y, z.

With the voltage step and offsets, I get the following on angles:

X: 0.041974933800873783 Y: -0.41450604992784712 Z: 65.376588015735521
X: -0.59290646870709129 Y: 0.50895272001477965 Z: 62.864042500339835
X: -1.7474773687631002 Y: -1.107157680696504 Z: 63.763641727439321
X: -0.30431967368129509 Y: 0.39351806301346776 Z: 63.503725175255653
X: 0.44598813546831534 Y: -0.29907273468431761 Z: 63.763641727439321
X: -0.65062539850273071 Y: -0.010493732570229987 Z: 63.763641727439321
X: -0.015740598965353455 Y: 0.22036892606078706 Z: 62.864042500339835
X: 0.15740618567488954 Y: 0.047221801648020693 Z: 62.990856852350745

Without the voltage step and offsets and using 6.0g instead of 3, I get the following:
X: -2.8975050412313226 Y: 7.9588318815438672 Z: 90
X: -2.8975050412313226 Y: 9.6579297791642684 Z: 74.444248900961227
X: -2.8134508092914667 Y: 9.0623482723407758 Z: 90
X: -3.4019678954538319 Y: 10.254566768819068 Z: 82.397076755629371
X: -3.1497059167086494 Y: 10.169265624836738 Z: 85.612598169987365
X: -2.8975050412313226 Y: 10.083987254504757 Z: 80.684933454463348
X: -3.4019678954538319 Y: 7.9588318815438672 Z: 90

Without the voltage step and no offsets and using 3.0g I get the following:
X: -1.5322675849620377 Y: 4.7275420628731126 Z: 30.242639723333181
X: -1.6582412247915879 Y: 4.4327759196193295 Z: 29.275597460743235
X: -1.7842228834621141 Y: 4.6433107105722939 Z: 29.951543350138909
X: -2.0362127006474937 Y: 5.0645717506580912 Z: 28.795508763249902
X: -1.6162491506822376 Y: 4.7696615680989565 Z: 29.516487394448284
X: -1.3643141506658361 Y: 5.106712577007734 Z: 28.891348373149537
X: -1.7002341898803937 Y: 5.0645717506580912 Z: 29.323729867577644

First, I don't think I should be converting Z to an angle since it is the measure of gravity. The XL does have multiple settings to be able to switch it to 6g instead of 1.5g. I can change it, but I'm running out of digital ports. I am using most of the digital ports for the lcd.

Noob question:
How do I get more digital I/O ports?

Thanks

#8 Dan T

Dan T

    Advanced Member

  • Members
  • PipPipPip
  • 91 posts
  • LocationBoston (Greater)

Posted 25 July 2012 - 10:49 PM

One way to get more ports is to use the [nwazet Touch Display LCD module for Netduino Go. It uses a Go Port instead of digital IO. I have one. It is very easy to use.

Back to your tilt sensor...

Instead of trying to figure out angles - first get your g's working. The 1g of gravity is a VERY nice standard by which you can "test" your code.

Once your code is generating ~1.0g on any axis that is pointing up, and all the other two axes are "near zero" (which could be very noisy and as high as 0.1g!), and you can change the orientation of your chip/board and the axes with 1g on it changes... only THEN should you worry about angles.

Until then, your angle calculation is garbage-in, garbage-out.


Next, you have to decide how to handle offset of each axis. All 3 axes will have a different offset, and your tilt measurements won't make any absolute sense until you compensate for these offsets. As I said somewhere above, one of your axes has an offset so big it looks like 10 degrees of tilt when your fixture is flat. To measure offset in the simplest way, lay your fixture down flat on a known level surface and average a lot of samples (100's or even 1000's) to eliminate the noise. (You'll need to average for all your measurements.) For the two axes not exposed to gravity, that average # is your offset. The 3rd axis doesn't matter much for a tilt sensor, unless you plan to "tilt" 90 degrees. If you want to measure offset on the 3rd axis, you have to get it "flat" by flipping your fixture EXACTLY 90 degrees. Another method is to flip your fixture EXACTLY 180 degrees (which might be easier) and averaging both readings for +1g and -1g. (This is an average of two readings, each itself an average of 100's or 1000's of readings.) That's your 3rd channel offset. Subtract these channel-specific (and device-specific) offsets from the raw readings in your code (before or after averaging samples). This is referred to as "calibrating for offset" or "offset calibration".


Only after doing all of that should you worry about tilt.


You didn't post your code for tilt, but it's simple trig. SOHCAHTOA. For small angles, for measurements in g's, and assuming the z-axis is pointing up, tilt of the x axis is arcsin(y) and tilt of the y axis is arcsin(x).


Keep us posted on your progress.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.