SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By emf
#27882
thanutz wrote:Its much more than 1.5 degree im getting im afraid to say. i suspect its just from auto sampling - my code is here: MChip Forum
Microchip must employ an entire team of engineers whose job it is to prevent links from working. Found it, though...
No buffering in the connection.
The big gotcha with the analog accelerometers is that their outputs have a high impedance -- 32k ohms. The type of ADC used on the PIC requires a fairly low impedance input, 2.5k ohms or less. The higher the source impedance, the longer it takes to charge the sampling capacitor in the ADC, meaning for higher impedance sources you need to increase the sampling time (time between selecting the ADC channel and starting the conversion) to allow the capacitor to charge. Past 2.5k ohms, the leakage will start to prevent the sampling capacitor from fully charging, and your readings will be somewhat lower than they should (but fairly stable, if I understand this correctly). The datasheet has the calculations of how long a sampling time you need for a given source impedance.

Without buffering the output, you'll definitely need to switch from auto-sampling to manual to get a long enough sampling time for things to stabilize. Try it and see if it makes the results settle down.

The op-amp just converts the high-impedance output into a low-impedance output suitable for the ADC at high speeds.
Also when the zeroing occurs in the code for the accelrometer, does the Y value take gravity into account so i.e. Y and X have different values subtracted so at rest (when gravity is fully active) they are both set to 0. Looks a bit clearer in my code (look at X and Y values).
We're subtracting the zero-g points for all three axes in our code, so upright, the corrected readings will be 1g for the Z axis, 0g for X and Y. So when it's level, we're calling atan2(0g, 1g).
By thanutz
#27884
I must have edited that post three times to get the link right and still didnt manage it!

Your right the impedance of the accelrometer is 32k, and from my test of giving it a 2.5v from the gyro it was never ever 2047 was always a little less than that.

The accelrometer data sheet states:

""The output has a typical bandwidth of 2.5khz. The user must filter the signal at this point to limit aliasing errors. The analog bandwidth must be no more than hlaf the analog to digital sampling frequency to minimise aliasing."

Seeing as my cap is reducing that to 50hz no more than a 100 samples a sec would be required. So manual it is and a delay poss before resetting the SAMP bit.

By Buffering do u mean the internal ADC buffer used as coded below (in Bold):
Code: Select all
float AccX = 0;
float AccY = 0;
float Gyro = 0;
float roll = 0;
float X = 0;
float Y = 0;
float Angle = 0;


void ADC_Init(void)
{
       
       ADCON1bits.FORM = 0; // Integer Output
       ADCON1bits.SSRC = 7; // Auto Conversion
       ADCON1bits.ASAM = 1; // Auto Sampling ON
       ADCON2bits.ALTS = 0; // Only use MUXA
       ADCON2bits.BUFM = 0; // One word Buffer
       ADCON2bits.SMPI = 2; // Interupt after three S & C
       ADCON2bits.CSCNA = 1; // Scan Input Ports
       ADCON3bits.SAMC = 15; // Auto Sample Bits
       ADCON3bits.ADCS = 31; // Clock Conversion Bits
       ADCHSbits.CH0NA = 0; // Neg Input Pin is Vref-
       ADCSSLbits.CSSL10 =1; // Channel Scanning is Enabled for AN10 (Gyro)
       ADCSSLbits.CSSL11 =1; // Channel Scanning is Enabled for AN11 (Accelerometer X)
       ADCSSLbits.CSSL12 =1; // Channel Scanning is Enabled for AN12 (Accelerometer Y)        
       ADPCFG = 0xFFFF; // Sets all Ports to Digital Mode
       ADPCFGbits.PCFG10 = 0; // AN10 in Analogue Mode
       ADPCFGbits.PCFG11 = 0; // AN11 in Analogue Mode
       ADPCFGbits.PCFG12 = 0; // AN12 in Analogue Mode
       IFS0bits.ADIF = 0;
       IEC0bits.ADIE = 1;
       ADCON1bits.ADON = 1;}

void __attribute__((__interrupt__)) _ADCInterrupt(void)
{
[b]   Gyro = ADCBUF0;
   AccX = ADCBUF1; 
   AccY = ADCBUF2;[/b]
   X = AccX-2048;
   Y = AccY-1930;
   roll = atan2(Y, X);
   Angle = roll* 57.2957795;}
Oh and i made an error with my g zeroing which might explain for a few errors...

Kind Regards
Anil
By emf
#27886
thanutz wrote:I must have edited that post three times to get the link right and still didnt manage it!
:-) I'm sure it worked fine for you, it bounced me to a login page and I didn't have one.
By Buffering do u mean the internal ADC buffer used as coded below (in Bold):
Ah, bad choice of words on my part. I was just talking about the op-amp again.
http://en.wikipedia.org/wiki/Buffer_amplifier
The accelrometer data sheet states:

""The output has a typical bandwidth of 2.5khz. The user must filter the signal at this point to limit aliasing errors. The analog bandwidth must be no more than hlaf the analog to digital sampling frequency to minimise aliasing."

Seeing as my cap is reducing that to 50hz no more than a 100 samples a sec would be required. So manual it is and a delay poss before resetting the SAMP bit.
Right. Well, actually no less than 100 samples per second would be required; more than 100 is fine. I've been told on other threads that the simple 50Hz RC filter is pretty poor, and I should either use a better analog filter or do the filtering digitally. I still don't know much about this, so I'm ignoring the aliasing problem for now...
By thanutz
#27888
Right. Well, actually no less than 100 samples per second would be required; more than 100 is fine. I've been told on other threads that the simple 50Hz RC filter is pretty poor, and I should either use a better analog filter or do the filtering digitally. I still don't know much about this, so I'm ignoring the aliasing problem for now...
I intepreted that the wrong way when i read it, what u said makes it much clearer. In that case auto sampling should work ok so long as sufficient time is allowed to charge the S/H amp.

Ahh understand what u mean by the op amp. Ill have a play again tomorrow with manual and auto sampling and see if it makes any difference.

Also can u use channel scanning with manual sampling, or do u simply change ADCHSbits.CH0SA each time before you reset the SAMP bit?

Thanks so so much for all your help
Anil
By JSchwendeman
#28257
All,

I'm trying to implement this code on my wiring board, using the ADXRS401 and ADXL203 IMU from Sparkfun, but the output isn't working well. Does anybody have ideas on tuning it, I'm really having a hard time getting anythign like a reasonable output:

long lastread = 0; //time reading to control dt.
int mydt = 20; //in ms.
int dt = 0.02;

int RATEpin = 2; //IMU pins.
int Y_ACCELpin = 1;
int X_ACCELpin = 0;

int RATEbits; //Bit Conversion
int Y_ACCELbits;
int X_ACCELbits;

float AX; //Value in g's.
float AY;

float angle_m; //Engineering Units in degrees and degrees/sec
float q_m;
float CALC_ANGLE;

//Kalman Filter ShizNITE!
#include <math.h>
static float P[2][2] = {
{ 1, 0 },
{ 0, 1 },
};

float angle;
float q_bias;
float rate;

static const float R_angle = .0034906555555555555556;
static const float Q_angle = 0.001;
static const float Q_gyro = 0.003;

void setup() {
pinMode(RATEpin, INPUT);
pinMode(Y_ACCELpin, INPUT);
pinMode(X_ACCELpin, INPUT);
Serial.begin(115200);
}

void loop() {
if((millis()-lastread) >= mydt) { // sample every dt ms -> 1000/dt hz.
lastread = millis();

//Gyro Measurement
RATEbits = analogRead(RATEpin);
q_m = ((RATEbits - 512)*.0056814055266203703704);

//Accelerometer Measurement
Y_ACCELbits = analogRead(Y_ACCELpin);
X_ACCELbits = analogRead(X_ACCELpin);
AX = (512 - X_ACCELbits)/2.56;
AY = (512 - Y_ACCELbits)/2.56;
angle_m = -(atan2(-AY, AX));

//Kalman Code Goes Here!
const float q = q_m - q_bias;

const float Pdot[2 * 2] = {Q_angle - P[0][1] - P[1][0], - P[1][1], - P[1][1], Q_gyro };

rate = q;

angle += q * dt;

P[0][0] += Pdot[0] * dt;
P[0][1] += Pdot[1] * dt;
P[1][0] += Pdot[2] * dt;
P[1][1] += Pdot[3] * dt;

const float angle_err = angle_m - angle;

const float C_0 = 1;

const float PCt_0 = C_0 * P[0][0];
const float PCt_1 = C_0 * P[1][0];

const float E =R_angle+ C_0 * PCt_0;

const float K_0 = PCt_0 / E;
const float K_1 = PCt_1 / E;

const float t_0 = PCt_0;
const float t_1 = C_0 * P[0][1];

P[0][0] -= K_0 * t_0;
P[0][1] -= K_0 * t_1;
P[1][0] -= K_1 * t_0;
P[1][1] -= K_1 * t_1;

angle += K_0 * angle_err;
q_bias += K_1 * angle_err;

if (angle_m < .78539750000000000001 && angle_m > -.78539750000000000001)
{
Serial.print(int(degrees(angle)));
Serial.print(",");
Serial.print(int(degrees(rate)));
Serial.print(",");
Serial.print(int(degrees(q_bias*100)));
Serial.print(",");
Serial.print("GO");
Serial.println();
}
else
{Serial.print(int(angle_m));
Serial.print(",");
Serial.print(int(q_m));
Serial.print(",");
Serial.print("STOP");
Serial.println();
}
}}

Thanks!
.jim
By sharana
#28262
JSchwendeman wrote:All,

I'm trying to implement this code on my wiring board, using the ADXRS401 and ADXL203 IMU from Sparkfun, but the output isn't working well. Does anybody have ideas on tuning it, I'm really having a hard time getting anythign like a reasonable output:
Hey buddy,

You got to let the group know what specifically you are expecting it to look at.

- sharan
By thanutz
#28265
JSchwendeman wrote:All,

I'm trying to implement this code on my wiring board, using the ADXRS401 and ADXL203 IMU from Sparkfun, but the output isn't working
What microcontroller are u using? Ive basically ripped all the code to shreads, read a crap loads of kalman papers and understand roughly whats going on now - ive nearly finished implementing all my bits just waiting for my PCB.

The kalman filter is generic, it will take in the 2 inputs in radians and will filter them correctly on the proviso that you are actually trying to estimate the bias of a gyro.

The main value u need to tweak is dt imo, i.e. the time between samples. ull need to work this out based on experiments and sampling configuration to work this out.
By JSchwendeman
#28266
I'm using the Wiring board (Atmega128). In regards to the previous poster, I am attempting to duplicate the tilt.c code.

Does the is the dt affected by the covariance matrix, or any other values? My thought was that a variable dt should have no affect on the operation of the rest of the code (though i see where it's used to approximate gyro delta position).

I was under the impression that all I'd need to really modify in this code was:

a.) the gyro noise
b.) the covariance matrix

Thoughts?

.jim
By icecube
#28737
JSchwendeman wrote:All,

I'm trying to implement this code on my wiring board, using the ADXRS401 and ADXL203 IMU from Sparkfun, but the output isn't working well. ...
Thanks!
.jim
Could you please specify what isn't working, and what you expect? Wiring board was one of the paths I was thinking about, but I am currently playing with ARM7.
By JSchwendeman
#28834
DOH, it was a stupid syntax error. Still have to fine tune the covariance matrix.
By Daniel Wee
#30062
I just found this thread and echo the sentiments of many others here - this is godsent!

I have a few questions about this project:-

1. It has been raised - the question about the systems reliability when it goes into a coordinated turn for a period of time (or the example of the unit hanging on a string and going in a circle). Has anyone done tests to see how the system holds up under lateral acceleration?

2. I have the 5DOF sparkfun IMU and was hoping to implement this with the dsPIC30F4012 which has the ADCs required. Will it be beneficial to encode at least part of the algorithm in assembly or is there enough processing power to produce the constant 10Hz output data stream?

3. In the hardware (can we see the schematic?) are there any additional low-pass filters being implemented, particularly active filters? Or is the basic RC filter sufficient for the task? If so, will this still be sufficient when exposed to a high frequency vibration environment (say the presence of a running motor)?

Thanks. I really appreciate all the details of this project, having lost many sleepless nights poring over documents explaining (purportedly) in simple terms the implementation of various Kalman filters.

Daniel
By emf
#30066
Daniel Wee wrote:1. It has been raised - the question about the systems reliability when it goes into a coordinated turn for a period of time (or the example of the unit hanging on a string and going in a circle). Has anyone done tests to see how the system holds up under lateral acceleration?
I still haven't gotten my setup tuned to work in the face of some fairly basic trickery like lateral acceleration, so I'm sure mine would fall flat on its face during an extended coordinated turn.

As it exists right now, the filter 'erects' itself using the accelerometer, so it should eventually wind up reading wings-level in a coordinated turn (correct me if I'm wrong -- I initially thought mechanical gyros would have the same problem, but apparently they don't). I guess the usual approach is to tune it to erect slow enough to make the error that creeps in during a normal-duration turn insignificant, and then design the flight regime to avoid longer turns.

If it turns out to be a problem for me, I've been planning on a different approach. You should be able to tell the bank angle in a coordinated turn if you know how many 'gs' you're pulling.. I think it's arccos(1/x). If the software detects you're in a steady turn, it can choose to correct your gyro drift towards the nearest bank angle that matches what the accelerometer predicts (since the accelerometer can't tell you whether 2gs is +60 or -60 degrees). This could get pretty complicated because you now need to keep the accelerometer calibrated so you know what 1g is, instead of just needing to know which direction gravity was tugging you. It feels like it could work, though.
2. I have the 5DOF sparkfun IMU and was hoping to implement this with the dsPIC30F4012 which has the ADCs required. Will it be beneficial to encode at least part of the algorithm in assembly or is there enough processing power to produce the constant 10Hz output data stream?
It should be able to handle 10Hz as-is, in unoptimized C, unless you're doing a lot of other stuff at the same time. If that's all you need, great. If not, I'd spend my time optimizing the trig lookup tables and converting parts or all of the code to use fixed-point arithmetic instead of jumping into assembly.
3. In the hardware (can we see the schematic?) are there any additional low-pass filters being implemented, particularly active filters? Or is the basic RC filter sufficient for the task? If so, will this still be sufficient when exposed to a high frequency vibration environment (say the presence of a running motor)?
I think the schematic is on the product page. From what I remember, there's a 50Hz RC filter on the accelerometer and a 2kHz filter on the gyro. I'd guess you'll wind up wanting more filtering, but I don't really know. I'm planning on doing most of my filtering in software.
By Daniel Wee
#30073
Thanks for the quick reply.

Can you elaborate on what you mean by "extended" coordinated turn. How long would "extended" constitute?

Would the code in the current state, in your estimation, be sufficient to go on a plane and be able to function as the artificial horizon? I am guessing that even if it may not be terribly accurate in a coordinated turn, it should be accurate over time - right?

Concerning the schematic - am I to understand that the 5DOF unit connects to the ADC inputs without other intervening circuitry (additional signal conditioning etc.) Would it not be easier to actually build an analog filter and put less burden on the processor? (unless space is a major constraint, even then ...)

Daniel
By emf
#30078
Daniel Wee wrote:Can you elaborate on what you mean by "extended" coordinated turn. How long would "extended" constitute?
I guess that depends on what you're using it on. A small R/C model can probably do most of the turns it would need to do in 20-30 seconds. Full-size planes usually make two minute turns, so I'd think you would want to shoot for having no significant error for at least one minute.
Would the code in the current state, in your estimation, be sufficient to go on a plane and be able to function as the artificial horizon? I am guessing that even if it may not be terribly accurate in a coordinated turn, it should be accurate over time - right?
I've never gotten this code giving me any results I was pleased with. If you tried to use it in a cloud, you'd be dead within a minute. It smooths out the accelerometer readings pretty well, but it does poorly when it's under any acceleration.

I tried messing around with the constants a bit without understanding what I was doing, but I didn't make any progress. I put it aside for a while, but recently I've started playing with it again. This time I'm going back to square one, using FlightGear to give me simulated IMU readings and scilab to try out some equations.

Maybe others have had better luck with it, I'd love to hear some success stories if anyone has theirs working.
By Daniel Wee
#30079
Thanks - so I take it that the code is not quite up to speed yet in that there is some work to be done on the accelerometer side of things.

On an earlier issue, the additional benefit of slapping on some active filtering (op-amps) is that you automatically buffer the sensor output (which is pretty high impedance as I understand it). This should, in theory, result in more accuracy.

I wonder if Ghint's project does any better under acceleration. I guess I'll have to give it a try myself once my module comes in. Again, thanks for your inputs - let's keep this thread alive.

Daniel