Accelerometer Memsic MX2125

hi,

I wanted to make sure I used the right values for getting the raw g-force of the accelerometer. as declared in the memsic datasheet (*) T2 (see below) is factory programmable, therefore I want to ask if with Arduino NG, T2 is fixxed at 10 milliseconds?

I used that code for getting the data, simply by using the raw results of the method "getGForce" and transferring them to a x- and y-value, I get an impression of the movement, which means in one case it has to be right. I'm just in doubt as I don't get that raw data as expected and explained in some tutorials (volts & nuts, basic stamp).

int getGForce (int pinNr) { unsigned int long duration; duration = pulseIn(pinNr, HIGH); // A(g) = (T1/T2 - 0.5) / 12.5% return ((duration*8)/5)-4000; }

Thank you for suggestions, corrections and help, bluma


*: http://www.memsic.com/memsic/products/gdxxi.asp?pq=10: MXD2125J.pdf


extracts:

Memsic 2125 GW Duty Cycle/Pulse Output

A (g)= (T1/T2 - 0.5)/12.5% 0g = 50% Duty Cycle T2= 10ms (factory programmable)

The MXD2125J/K has two PWM duty cycle outputs (x,y). The acceleration is proportional to the ratio T1/T2. The zero g output is set to 50% duty cycle and the sensitivity scale factor is set to 12.5% duty cycle change per g. These nominal values are affected by the initial tolerance of the device including zero g offset error and sensitivity error. This device is offered from the factory programmed to a 10ms period (100 Hz).


T1 Length of the “on” portion of the cycle. T2 (Period) Length of the total cycle - FACTORY PROGRAMMABLE Duty Cycle Ratio of the “0n” time (T1) of the cycle to the total cycle (T2). Defined as T1/T2. Pulse width Time period of the “on” pulse. Defined as T1.


I'm doing the same sort of thing and I think the code you put up will only return 1 or 0 * that formula you posted.

Reading the digital value from the pin will give you a single binary number (1 or 0). It is the length of these HIGH/LOW switches that contains the data we want to get at.

The difficult part is getting the timing of a single pulse, which should be what is needed to get an instantaneous measurement. This is (apparently) the advantage to using digital over analog. If we were to do this analog we would get a couple of voltage readings and average them out. As I understand it with a pwm setup this isn't necessary.

The sample cod on the arduino page doesn't make much sense (http://www.arduino.cc/en/Tutorial/AccelerometerMemsic2125). The timing part is screwy. It seems to assume that it takes 18 ms to do the while loop. Basically what the example is doing is taking a high pulse, taking a low pulse, and then taking a high pulse while counting to see how many "loops" it takes before that high pulse changes. Then it multiplies this by the magic number 18. How does one get this number, and if it is fudged, then how do we get accurate measurements....

Once that is solved the rest is relatively simple, I guess. We take the width of the high pulse (represented by the timer variable) and we assume that the non-moving level output (0g) is 50% of the duty cycle. Then we scale on the 12.5% factor. Now that I think about it the time "unit" doesn't matter, as long as it is consistent (I'm still leery of using a loop counter as a timer. If there was a power fluctuation of something your measurements would be off.). So you take the baseline time "unit" and map it to 50%/0g and go from there.

Just for kicks i took a millis reading at the beginning of the HIGH-LOW-HIGH sequence and one after (which should be more accurate ???) and got 8's and 7's with the accelerometer relatively still and flat.

This code is all I've got at the moment:

//tests the 2 axis accelerometer in digital mode

int xval = 11;
int yval = 10;
long millisstartcycle = 0;

long millishistart = 0;
long millishiend = 0;
char sig  = '-';

void setup(){
  beginSerial(9600); 
  pinMode(xval, INPUT);
  pinMode(yval, INPUT);
}

void loop (){
  delay(500);
  Serial.print("x: ");
  Serial.print(getAccelerometerData (xval));
  delay(100);
  Serial.print(" y: ");
  Serial.print(getAccelerometerData (yval));
  Serial.print("\n");
}

long getAccelerometerData (int axis){
  int count = 0;
  millisstartcycle = millis();
  int v = digitalRead(axis);
  while(v == HIGH) {
    v = digitalRead(axis);
  }
  while(v == LOW){
    v = digitalRead(axis);
  }
  millishistart = millis();
  while(v == HIGH){
    v = digitalRead(axis);
  }  
  millishiend = millis();
  long highcycle = millishiend - millishistart;
  long totalcycle = millishistart - millisstartcycle;
  Serial.print("highcycle ");
    Serial.print(highcycle);
      Serial.print("\n");
  Serial.print("totalcycle ");
    Serial.print(totalcycle);
      Serial.print("\n");
  long g = (highcycle/8 - .5)/12.5; //note I am not using totalcycle as T2...
  //I am using 8 because according to the manual a T2 of 8ms is set via a 1MOhm resistor
  //sparkfun uses one of these in their breakout board
  return (g);
}

It checks the T2 and T1 using millis() differences instead of counts. The setup of T2 is really set by sparkfun on their breakout board "Board comes fully assembled and tested with selected sensor, 0.1uF filtering capacitors, and 1MOhm pulse width resistor (where required)." According to the manual for my accelerometer this is equivalent to a T2 of 8ms (T2 = Rset/125MOhm).

In the code I've set it to this hard coded value.

Now on to the next task...Representing floating point decimal numbers in serial output.

I'm getting output that says i have highcycles of 3 and 4 when the device is at rest. The problem, again, is that I can't represent float values so i won't get anything showing up in my output until I violently crash the accelerometer around and get >1g.

Hi all,

Has anyone made any more progress on this topic? I have been trying for a couple days now to get the chip to work with my arduino board, and have had little success. Below is a copy of the code I have, which is primarily an attempt at converting Parallax’s basic stamp example ( pg.3 of this pdf: http://www.parallax.com/dl/docs/prod/acc/memsickit.pdf ) into arduino code. I’m new at this, so maybe that’s why it’s not working, but it seems like no one else has an entirely successful attempt, either.

Any advice would be helpful. Thanks in advance.

Cheers,
Bill Goodrich

 /*
*/

#include <math.h>

int ledPin = 13;
int xaccPin = 3;
int yaccPin = 2;
float xRaw;
float yRaw;
float xmG;
float ymG;
int Scale = 18; //value to multiply pulse width by to convert to microseconds for particular chip, in this case the atmega168
float disp;
int angle;
int xTilt;
int yTilt;


void setup() {
Serial.begin(9600); // Sets the baud rate to 9600
pinMode(ledPin, OUTPUT);
pinMode(xaccPin, INPUT);
pinMode(yaccPin, INPUT);
Serial.println("Hello World");
}

void loop() {

/* Read G Force on X and Y axis */
xRaw = pulseIn(xaccPin, HIGH);   //read the duration of a high pulse on the x pin
Serial.println(xRaw, DEC);
xRaw = xRaw * Scale;  //convert to microseconds. need to find conversion factor for arduino
Serial.println(xRaw, DEC);
xmG = ((xRaw / 10) - 500) * 8;  // calc milli-g's
Serial.println(xmG, DEC);
yRaw = pulseIn(yaccPin, HIGH);
Serial.println(yRaw, DEC);
yRaw = yRaw * Scale;
Serial.println(yRaw, DEC);
ymG = ((yRaw / 10) - 500) * 8;
Serial.println(ymG, DEC);
Serial.println("end of g force calc");

/* Convert G force to Tilt on X and Y axis */
Serial.println("begin tilt calc");
disp = constrain ((abs(xmG) / 10), 0, 99);
Serial.println(disp, DEC);
Arcsine(disp);
Serial.println(angle, DEC);
xTilt = angle * (-2 * xmG + 1);  //fix sign
disp = constrain ((abs(ymG) / 10), 0, 99);
Arcsine(disp);
yTilt = angle * (-2 * ymG + 1);

/* Print results to serial port */
printByte('X');
printInteger(xTilt);
printByte(10);
printByte('Y');
printInteger(yTilt);
printByte(10);

}

/* Arcsine function */
void Arcsine(float disp){
  disp = disp * 0.574 ; //normalize input to 127. value should be 0.574 or 3.84
  Serial.println("arcsine step 1");
  Serial.println(disp, DEC);
  angle = 63 - (disp / 2);  //approximate angle
  Serial.println("arcsine step 2");
  Serial.println(angle, DEC);
  do  //find angle
  {
    angle = angle + 1;
    Serial.println(angle, DEC);
  } while (cos(angle) <= disp);  //problem with program seems to occur here.  gets caught in loop. seems to be a number prior to getting here that causes it, though.
  angle = angle / 360;  //is this right?
}

/* Arccosine function */
//void Arccosine(int angle){
//  angle = Arcsine(angle);
//  angle = 90 - angle;
//}

I am having very good results with the following code:

int pinX = 3;
int pinY = 2;
unsigned long serialTimer = millis();
unsigned long xAcc = 0;
unsigned long yAcc = 0;
boolean flipflop;

void setup()
{
  pinMode(pinX, INPUT);
  pinMode(pinY, INPUT);
  Serial.begin(115200);
}

void loop()
{
    if (flipflop == true) {
     xAcc = pulseIn(pinX, HIGH);
     flipflop = false;
    } else {
       yAcc = pulseIn(pinY, HIGH);
       flipflop = true;
    }

  if ((millis() - serialTimer) > 50 ) {
    Serial.print("X ");
    Serial.println(xAcc);
    Serial.print("Y ");
    Serial.println(yAcc);
  }
}

This code updates the values “as quick as possible”. Also, without the “flipflop” boolean, I would get errors for the Y axis.

Here is the Processing code to match/test

import processing.serial.*;

Serial port;  // Create object from Serial class
int val;      // Data received from the serial port
int xAngle;
int yAngle;


void setup() 
{
  println ( Serial.list());
  size(200, 200,P3D);
  frameRate(10);
  // Open the port that the board is connected to and use the same speed (9600 bps)
  port = new Serial(this, Serial.list()[0],115200);
  port.bufferUntil(13);
  lights();
  
  
}

void draw()
{
  background(0);
  directionalLight(51, 102, 126, 0, 0, -1);
  translate(100,100,0);
  rotateX(map(xAngle,3800,6300,-1 * HALF_PI,HALF_PI));
  rotateY(map(yAngle,3800,6300,-1 * HALF_PI,HALF_PI));
  translate(-50,-50,0);
  rect(0,0,100,100);
  
  
  
 
  
}

void serialEvent(Serial p) { 
  String msg = port.readStringUntil(13);
  if (msg != null) readMsg(msg); 
  
}

void readMsg(String msg) {
  
  //remove non printing chars
  int badChars = 0;
  for (int i = msg.length() -1; i >= 0; i--) {
    char c = msg.charAt(i);
    if ( c == 10 || c ==13) {
      badChars++;
    }
  }
  if (badChars > 0) msg = msg.substring(0,msg.length()-badChars+1);
  
  String[] words = splitTokens(msg);
  if (words[0].equals("X")) {
    xAngle = int( words[1]);
  }
  if (words[0].equals("Y")) {
    yAngle = int( words[1]);
  }
  
}

Thanks man, just used your code to finish up my obstacle detection system for my autonomous rover