Programming Vex Accelerometer 1.0

I have been trying to use the vex accelerometer 1.0 to find the position of the robot. I programed it to have a 1 millisecond sampling time to find “instantaneous” acceleration, then update the “instantaneous” velocity, then update the position. When I test this method by finding the position of the robot in the z-axis (the axis affected by gravity), it works pretty well. When I record the position at one second, it comes out to 4.2 meters. The calculated value is .5at^2 = .59.81 = 4.9 meters. If I multiply by a constant to account for the error, it is fairly accurate when recording the position at most other times(I tested the position at 1 second to 9 seconds in increments of 500 milliseconds). So the accelerometer works for consistent accelerations like gravity. When I try it on other axis’ however, the value is off by many meters. Doe anyone know how to fix this? Here is my program:


#pragma config(Sensor, in1,    xAxis,               sensorAccelerometer)
#pragma config(Sensor, in2,    yAxis,               sensorAccelerometer)
#pragma config(Sensor, in3,    zAxis,               sensorAccelerometer)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

float accelRatio = 0;
float yPos = 0;
float yVel = 0;
float yAccel = 0;
float posAt1MSec = 0;
float errorFactor = 1.1667;

int zYDif = 0;
int originalY = 0;

task yPosition(){
  while(true){
    wait1Msec(1);//1 millisecond sampling time
    yAccel = (abs(SensorValue[yAxis] - originalY)) > 2 ? (SensorValue[yAxis] - originalY) / accelRatio : 0;
    //check if threshold is passed and set "instantanious" acceleration   
    yVel += (yAccel / 1000);//update "instantainious" velocity
    yPos += (yVel / 1000);//update position
  }
}

task main(){
  wait1Msec(1000);//give sensor time to settle
  originalY = SensorValue[yAxis];//record the y axis value at start
  zYDif = SensorValue[zAxis] - originalY;//find the difference between 0G and 1G
  accelRatio = zYDif / 9.801;//find sensor value of 1m/s^2
  StartTask(yPosition);//start calculating position
  wait1Msec(1000);
  posAt1MSec = yPos * errorFactor;//record yPos at 1 millisecond, and account for error
  while(true){
    wait1Msec(1);
  }
}

Try using a timer to find out how long it has been since the last read, and use that for the delta t. This might be more accurate than your current plan, which is to assume the task runs at 1ms intervals and takes no time itself.

DIYdrones/sparkfun has some discussion on filtering 9DOF intertial trackers, and they talk about needing kamen filtering to get useful data.

Thanks for the info. About using a timer though, since robotC can’t measure in smaller increments than 1 millisecond, how would a timer help? It would just make the program take longer right? I guess that I could see how many while loops execute in a microsecond, but I don’t know how much difference that would make.

try using a simple formula which is updated every millisecond, for instance the velocity formula: v = d/t;
v = velocity
d = distance
t = time
time is a constant (1 millisecond: 0.001 SI units)
velocity is given to you by the accelerometer
distance is the unknown variable
rearrange equation
d = v*t;
d = (accelerometer input) * 0.001;

then just add the calculated distance to the global variable for that axis, the formula works both ways and gives you global displacement instead of total distance travelled because when you go backwards, it will remove the value from the global variable for that axis.
Im not sure if thats what you wanted but I hope it helps!

The accelerometer gives you acceleration, not velocity. What I’m doing in my program is using the acceleration to update the velocity, and then updating the position based on velocity. The problem is that the program is very inaccurate when testing it in realistic scenario instead of a constant acceleration. I wanted to see if anybody had a way to make this more accurate or find the position a different way.

LOL! My bad. How about this:

a = v/t;
a = acceleration
v = velocity
t = time
time is constant (1 millisecond: 0.001 SI units)
acceleration is given by the accelerometer
velocity is the unknown variable
rearrange equation
v = a*t;
v = (acceleration input) * 0.001;

then you just use the previous formula to extract the distance and that should work, I see no reason why it shouldnt.

All you do is create a while loop to check the timer and call the function whenever theres 1 millisecond.


while (1)
{
  if (time1[T1] == 1)
  {
    execute_function();
    time1[T1] = 0;
  }
}

I don’t know if you read the code that I posted, but that is exactly what I’m doing. I don’t see many other ways to do it though.

Yes but for some reason it just doesn’t look right, it is probably correct, it just looks different to the way I would do it, it should work, maybe the units being outputted by the accelerometer is different to what you are using.

I do the conversion of Accelerometer units to meters/sec^2 by comparing the z-Axis to the y-axis. The difference between them should be equal to 9.8m/s^2. That gives me the conversion ratio.

The output of the Accelerometer is in g-force, you shouldnt need to include the Z-axis in your calculations.

Anyway this basically works the same as your code but doesn’t use the z-axis, it just doesn’t seem right, anyway I have suggestion code:


task UpdateY()
{
  wait10Msec(100);
  
  // variables:
  float yGforce = 0;
  float yAccel = 0;
  float yVel = 0;
  float yDist = 0;
  
  // constants:
  const float Time = 0.001;
  const float yBias = SensorValue[in1];
  const float Gravity = 9.80665
  while(true)
  {
    wait1Msec(1);
    yGforce = SensorValue[in1];
    yGforce = yGforce - yBias;
    yAccel = yGforce * Gravity
    yVel = (yVel * Time) + (0.5 * yAccel * Time);
    yDist = yVel * Time;
  }
}

try it and see if that works!

Thanks for thinking this out. But your code assumes that all playing fields are completely level. I include the z-Axis to find the difference between the z-Axis and y-Axis at the beginning. So if the difference is 300, then the conversion ratio from accelerometer counts to acceleration in m/s^2 is 30.612. This is so that the value of 1G does not have to be found experimentally, it works if the playing field is not level, and it works wit or without the jumper.

Does the Y axis code work as its supposed to? Because you say that it works for constants like gravity, I dont quite understand what you are trying to say by that, also an accelerometer measures acceleration in g-force, note the keyword “acceleration”, so if you try to find a difference between z-axis and y-axis, you are only going to get a difference other than 1 because of the offset on the axis, values are (y)0 (x)0 (z)+1 at rest, also I am unsure whether the output is in G or mG, so I will assume G. To get the acceleration you just multiply the output by the gravity constant (9.8), and it doesn’t matter if the playing field is level because you use the bias value to correct issues so as long as the sensor is parallel to the field then your fine. You should try to avoid inter-axis calculations as they are a lot harder to program and a lot easier to stuff up.

Please explain some more on what currently works and what doesn’t, I will leave it at this point because is is late (2:36am) and I have my first day of school tomorrow :^/ so david if im asleep in your office tomorrow you’ll know why :^D

The accelerometer does not return values in terms of gravity. The y and x axis’ at rest give a reading of about 980 (I haven’t used a balancing tool to get the robot completely straight yet) and the z axis returns about 1300. So to find what the accelerometer thinks is 1G, I use the difference between the two axis and divide it by 9.8.

Well what does the accelerometer output then? Because what you are saying there describes an output of g-force in mili-G’s, as for the x and y axis outputting 980, it looks like an offset of 20 mG but I did not think that all axis would use the standard 1G rule, I learnt something, so then you have to compensate for the offsets and negate the one G in order to get relative acceleration. This is because their are two ways of looking at things, relative and global, global is more complicated because all your calculations are done from a global point of view, while relative is done from a relative point of view so you can easily do calculations for the one object. Using relative is good for keeping track of how you are calculating because its much easier to rotate an object by its relative axis than by its global axis. I probably didn’t explain that very well but its the best I can do.
basically what im trying to say is use bias values to negate the 1G and compensate for offsets, thus allowing you to calculate from a relative point of view which should work because your on the ground and the globals dont really matter when you are calculating for something simple on land.
okay iv probably lost you by now but what im trying to say is that the axis will read 1G because of some rules in physics, iv checked the chip specs and it states that the output is in mG which is fine but you will have to remember to compensate for that in your calculations. I will test out the accelerometer on wednesday which is when we next have the robotics club meeting. I haven’t really used it at this point because I have been busy but ill let you know what I find out.