paparazzi-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Paparazzi-devel] BMP085 sensor temperature wiht large error


From: Helge Walle
Subject: Re: [Paparazzi-devel] BMP085 sensor temperature wiht large error
Date: Thu, 4 Aug 2011 11:36:39 +0200

Hi,
 
To make sure that the sample rate is not set so high that it interferes with the conversion time of the BMP sensor, I would need to check the data flow with my logic analyzer.
I did not do that yesterday evening. However, Increasing freq from "8" to "20" in .../paparazzi/conf/modules/baro_bmp.xml increased the data flow and did not create any problems.
The code I used with my Arduino board that made better results was from Sparkfun. I am quite determined to work through the code since I feel sure that this is the right way to go.

Regards,
Helge.

 
2011/8/4 Prof. Dr.-Ing. Heinrich Warmers <address@hidden>
Hi,
tanks for the information, I think you are one the right way.
I found the second call for the filter with the GPS altitude
in estimator.c in the function EstimatorSetPosXY:

#ifndef USE_BARO_ETS
float falt = gps_alt/100.
EstimatorSetAlt(falt);
#endif

After deleting this sequence  the altitude has only  1..2 m variance after the filter output and the climb rate is low  ( approx.   +-0.2 ..04m/s).
Can you send me your changes to get higher sample rates?
Regards

Heinrich

I found 2 samples of code for the correction.
In the second example  there is the commend to read the temperature twice.

http://code.google.com/p/uavp-mods/
#include "uavx.h"

//From Bosch Sensortec BMP085_SMD500_API
int16 ac1, ac2, ac3, b1, b2, mb, mc, md;
uint16 ac4, ac5, ac6;

void BMP085Calibrate()
{
    ac1 = 408;
    ac2 = -72;
    ac3 = -14383;
    ac4 = 32741;
    ac5 = 32757;
    ac6 = 23153;
    b1 = 6190;
    b2 = 4;
    mb = -32767;
    mc = -8711;
    md = 2868;
}

void BMP085(int32 up, int32 ut)
{
    int32  tval, pval;
    int32  x1, x2, x3, b3, b5, b6, p;
    uint32  b4, b7;
    uint8 oss = 3;

    x1 = (ut - ac6) * ac5 >> 15;
    x2 = ((int32 ) mc << 11) / (x1 + md);
    b5 = x1 + x2;
    tval = (b5 + 8) >> 4;
   
    b6 = b5 - 4000;
    x1 = (b2 * (b6 * b6 >> 12)) >> 11;
    x2 = ac2 * b6 >> 11;
    x3 = x1 + x2;
    b3 = (((int32 ) ac1 * 4 + x3)<<oss + 2) >> 2;
    x1 = ac3 * b6 >> 13;
    x2 = (b1 * (b6 * b6 >> 12)) >> 16;
    x3 = ((x1 + x2) + 2) >> 2;
    b4 = (ac4 * (uint32 ) (x3 + 32768)) >> 15;
    b7 = ((uint32 ) up - b3) * (50000 >> oss);
    p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

    x1 = (p >> 8) * (p >> 8);
    x1 = (x1 * 3038) >> 16;
    x2 = (-7357 * p) >> 16;
    pval = p + ((x1 + x2 + 3791) >> 4);
}


void SMD500Calibrate()
{
    ac1 = 408;
    ac2 = -72;
    ac3 = -14383;
    ac4 = 32741;
    ac5 = 32757;
    ac6 = 23153;
    b1 = 6190;
    b2 = 4;
    mb = -32767;
    mc = -8711;
    md = 2868;
}
/*
void SMD500(int32 up, int32 ut)
{
    int32  tval, pval;
    int32  x1, x2, x3, b3, b5, b6, p;
    uint32  b4, b7;
    uint8 oss = 3;

    x1 = (ut - ac6) * ac5 >> 15;
    x2 = ((int32 ) mc << 11) / (x1 + md);
    b5 = x1 + x2;
    tval = (b5 + 8) >> 4;
   
    b6 = b5 - 4000;
    x1 = (b2 * (b6 * b6 >> 12)) >> 11;
    x2 = ac2 * b6 >> 11;
    x3 = x1 + x2;
    b3 = (((int32 ) ac1 * 4 + x3)<<oss + 2) >> 2;
    x1 = ac3 * b6 >> 13;
    x2 = (b1 * (b6 * b6 >> 12)) >> 16;
    x3 = ((x1 + x2) + 2) >> 2;
    b4 = (ac4 * (uint32 ) (x3 + 32768)) >> 15;
    b7 = ((uint32 ) up - b3) * (50000 >> oss);
    p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

    x1 = (p >> 8) * (p >> 8);
    x1 = (x1 * 3038) >> 16;
    x2 = (-7357 * p) >> 16;
    pval = p + ((x1 + x2 + 3791) >> 4);
}
*/

and from Sparkefun
/*
    BMP085 Test Code
    April 7, 2010
    by: Jim Lindblom
   
    Test code for the BMP085 Barometric Pressure Sensor.
    We'll first read all the calibration values from the sensor.
    Then the pressure and temperature readings will be read and calculated.
    Also attempts to calculate altitude (remove comments)
    The sensor is run in ultra low power mode.
    Tested on a 3.3V 8MHz Arduino Pro
    A4 (PC4) -> SDA
    A5 (PC5) -> SCL
    No Connection to EOC or XCLR pins
*/

#include <stdlib.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "types.h"
#include "defs.h"
//#include "math.h"    // To calculate altitude
#include "i2c.h"

#define FOSC 8000000
#define BAUD 9600
#define BMP085_R 0xEF
#define BMP085_W 0xEE
#define OSS 0    // Oversampling Setting (note: code is not set up to use other OSS values)

#define sbi(var, mask)   ((var) |= (uint8_t)(1 << mask))
#define cbi(var, mask)   ((var) &= (uint8_t)~(1 << mask))

///============Function Prototypes=========/////////////////
void BMP085_Calibration(void);

///============I2C Prototypes=============//////////////////
short bmp085ReadShort(unsigned char address);
long bmp085ReadTemp(void);
long bmp085ReadPressure(void);
void bmp085Convert(long * temperature, long * pressure);

///============Initialize Prototypes=====//////////////////
void ioinit(void);
void UART_Init(unsigned int ubrr);
static int uart_putchar(char c, FILE *stream);
void put_char(unsigned char byte);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
void delay_ms(uint16_t x);

/////=========Global Variables======////////////////////
short ac1;
short ac2;
short ac3;
unsigned short ac4;
unsigned short ac5;
unsigned short ac6;
short b1;
short b2;
short mb;
short mc;
short md;

int main(void)
{   
    long temperature = 0;
    long pressure = 0;
    //long altitude = 0;
    //double temp = 0;
   
    ioinit();
    i2cInit();
    delay_ms(100);
   
    BMP085_Calibration();
   
    while(1)
    {
        bmp085Convert(&temperature, &pressure);
       
        printf("Temperature: %ld (in 0.1 deg C)\n", temperature);
        printf("Pressure: %ld Pa\n\n", pressure);
       
        // For fun, lets convert to altitude
        /*temp = (double) pressure/101325;
        temp = 1-pow(temp, 0.19029);
        altitude = round(44330*temp);
        printf("Altitude: %ldm\n\n", altitude);*/
       
        delay_ms(1000);
    }
}

void BMP085_Calibration(void)
{
    printf("\nCalibration Information:\n");
    printf("------------------------\n");
    ac1 = bmp085ReadShort(0xAA);
    ac2 = bmp085ReadShort(0xAC);
    ac3 = bmp085ReadShort(0xAE);
    ac4 = bmp085ReadShort(0xB0);
    ac5 = bmp085ReadShort(0xB2);
    ac6 = bmp085ReadShort(0xB4);
    b1 = bmp085ReadShort(0xB6);
    b2 = bmp085ReadShort(0xB8);
    mb = bmp085ReadShort(0xBA);
    mc = bmp085ReadShort(0xBC);
    md = bmp085ReadShort(0xBE);
   
    printf("\tAC1 = %d\n", ac1);
    printf("\tAC2 = %d\n", ac2);
    printf("\tAC3 = %d\n", ac3);
    printf("\tAC4 = %d\n", ac4);
    printf("\tAC5 = %d\n", ac5);
    printf("\tAC6 = %d\n", ac6);
    printf("\tB1 = %d\n", b1);
    printf("\tB2 = %d\n", b2);
    printf("\tMB = %d\n", mb);
    printf("\tMC = %d\n", mc);
    printf("\tMD = %d\n", md);
    printf("------------------------\n\n");
}

// bmp085ReadShort will read two sequential 8-bit registers, and return a 16-bit value
// the MSB register is read first
// Input: First register to read
// Output: 16-bit value of (first register value << 8) | (sequential register value)
short bmp085ReadShort(unsigned char address)
{
    char msb, lsb;
    short data;
   
    i2cSendStart();
    i2cWaitForComplete();
   
    i2cSendByte(BMP085_W);    // write 0xEE
    i2cWaitForComplete();
   
    i2cSendByte(address);    // write register address
    i2cWaitForComplete();
   
    i2cSendStart();
   
    i2cSendByte(BMP085_R);    // write 0xEF
    i2cWaitForComplete();
   
    i2cReceiveByte(TRUE);
    i2cWaitForComplete();
    msb = i2cGetReceivedByte();    // Get MSB result
    i2cWaitForComplete();
   
    i2cReceiveByte(FALSE);
    i2cWaitForComplete();
    lsb = i2cGetReceivedByte();    // Get LSB result
    i2cWaitForComplete();
   
    i2cSendStop();
   
    data = "" << 8;
    data |= lsb;
   
    return data;
}

long bmp085ReadTemp(void)
{
    i2cSendStart();
    i2cWaitForComplete();
   
    i2cSendByte(BMP085_W);    // write 0xEE
    i2cWaitForComplete();
   
    i2cSendByte(0xF4);    // write register address
    i2cWaitForComplete();
   
    i2cSendByte(0x2E);    // write register data for temp
    i2cWaitForComplete();
   
    i2cSendStop();
   
    delay_ms(10);    // max time is 4.5ms
   
    return (long) bmp085ReadShort(0xF6);
}

long bmp085ReadPressure(void)
{
    long pressure = 0;
   
    i2cSendStart();
    i2cWaitForComplete();
   
    i2cSendByte(BMP085_W);    // write 0xEE
    i2cWaitForComplete();
   
    i2cSendByte(0xF4);    // write register address
    i2cWaitForComplete();
   
    i2cSendByte(0x34);    // write register data for temp
    i2cWaitForComplete();
   
    i2cSendStop();
   
    delay_ms(10);    // max time is 4.5ms
   
    pressure = bmp085ReadShort(0xF6);
    pressure &= 0x0000FFFF;
   
    return pressure;
   
    //return (long) bmp085ReadShort(0xF6);
}

void bmp085Convert(long* temperature, long* pressure)
{
    long ut;
    long up;
    long x1, x2, b5, b6, x3, b3, p;
    unsigned long b4, b7;
   
    ut = bmp085ReadTemp();
    ut = bmp085ReadTemp();    // some bug here, have to read twice to get good data
    up = bmp085ReadPressure();
    up = bmp085ReadPressure();
   
    x1 = ((long)ut - ac6) * ac5 >> 15;
    x2 = ((long) mc << 11) / (x1 + md);
    b5 = x1 + x2;
    *temperature = (b5 + 8) >> 4;
   
    b6 = b5 - 4000;
    x1 = (b2 * (b6 * b6 >> 12)) >> 11;
    x2 = ac2 * b6 >> 11;
    x3 = x1 + x2;
    b3 = (((int32_t) ac1 * 4 + x3) + 2)/4;
    x1 = ac3 * b6 >> 13;
    x2 = (b1 * (b6 * b6 >> 12)) >> 16;
    x3 = ((x1 + x2) + 2) >> 2;
    b4 = (ac4 * (unsigned long) (x3 + 32768)) >> 15;
    b7 = ((unsigned long) up - b3) * (50000 >> OSS);
    p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
    x1 = (p >> 8) * (p >> 8);
    x1 = (x1 * 3038) >> 16;
    x2 = (-7357 * p) >> 16;
    *pressure = p + ((x1 + x2 + 3791) >> 4);
}

/*********************
 ****Initialize****
 *********************/
 
void ioinit (void)
{
    //1 = output, 0 = input
    DDRB = 0b01100000; //PORTB4, B5 output
    DDRC = 0b00010000; //PORTC4 (SDA), PORTC5 (SCL), PORTC all others are inputs
    DDRD = 0b11111110; //PORTD (RX on PD0), PD2 is status output
    PORTC = 0b00110000; //pullups on the I2C bus
   
    UART_Init((unsigned int)(FOSC/16/BAUD-1));        // ocillator fq/16/baud rate -1   
}

void UART_Init( unsigned int ubrr)
{
    // Set baud rate
    UBRR0H = ubrr>>8;
    UBRR0L = ubrr;
   
    // Enable receiver and transmitter
    UCSR0A = (0<<U2X0);
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
   
    // Set frame format: 8 bit, no parity, 1 stop bit,  
    UCSR0C = (1<<UCSZ00)|(1<<UCSZ01);
   
    stdout = &mystdout; //Required for printf init
}

static int uart_putchar(char c, FILE *stream)
{
    if (c == '\n') uart_putchar('\r', stream);
 
    loop_until_bit_is_set(UCSR0A, UDRE0);
    UDR0 = c;
   
    return 0;
}

void put_char(unsigned char byte)
{
    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1<<UDRE0)) );
    /* Put data into buffer, sends the data */
    UDR0 = byte;
}



Helge Walle schrieb:
Hi,

The temperature reading of my BMP sensor agrees with another thermometer I have in the same room. I know, however, that this is no proof of its accuracy.

I did some testing with the BMP this evening while continously comparing with the weather station at the local university (published on internet). It revealed that my pressure sensor seems accurate enough on average, but the noise is far too high. I tweaked up the periodic frequency and made every message an average of 5 readings. This reduced the noise to approx half of what it was, that is I got +/- 2m expressed in altitude noise.
 
I think I will check the code (learning some more C at the same time), but this will take some time unfortunately. Any findings will be reported.
Regards,
Helge.
 

 
2011/8/3 Prof. Dr.-Ing. Heinrich Warmers <address@hidden>
Hi,
We have used the BMP and  a humidity sensor and found that the temperature of the BMP is always 3 to 4 degree wrong.
In the data sheet the noise of the pressure is given lower than 0.4m and the maximum rate is 128/s.
Since same other projects use the same sensor  for quadrorotors i think the error is in the software.
First i will give out the raw data without correction.
 
Regards
Heinrich.




Helge Walle schrieb:
Got it, thanks for the correction!

Helge.

2011/8/3 Gautier Hattenberger <address@hidden>
I think you're not correct actually.
The main loop is written like this:

init calls
while (true) {
 if (1/60s since last periodic call) { periodic calls }
 event calls
}

So, the event calls are as fast as possible. Only the periodic functions are called with a fixed period.

Gautier

On 03/08/2011 13:50, Helge Walle wrote:
Thanks a lot for your help Gautier!

I did a few trial compilations with different frequencies between 1 and 60, and modules.h was generated in the way I expected.
Please correct me if I am wrong, but I assume that in the case of my TWOG based fixed wing aircraft the continuous polling of event functions always happen at 60hz.

Helge.


2011/8/3 Gautier Hattenberger <address@hidden>
Hi,

i7 is a prescaler mechanism that calls a function (here baro_bmp_periodic) with the correct frequency (specified in the xml file) based on the main loop frequency (60Hz for fixed wing, 512Hz for rotorcraft). You can specify any frequency lower or equal to the main loop, but if it's not a divider of it, the module's periodic function will not be called with the exact frequency.
The event functions are polled continuously when the periodic functions are not called (here, probably much more than 8 times as often as the baro_bmp_periodic...).

Gautier

On 03/08/2011 10:37, Helge Walle wrote:

Hi,

I have studied baro_bmp.c trying to find the reason why readings from the BMP085 sensor seems to wander in steps of up to +/- 0.5 hPa around “center”. This amounts to approx +/- 4m at sea level. No luck so far, however.

The program selects a high resolution setting of the sensor. As far as the BMP085 datasheet goes I would expect values in the SENSOR_SYNC_SEND message to have a higher resolution. I want to look more at this, but a few questions arise.

In .../var/<my_aircraft>/generated/modules.h there is this code:

…..
static inline void modules_init(void) {
   baro_bmp_init();
}
static inline void modules_periodic_task(void) {
   static uint8_t i7; i7++; if (i7>=7) i7=0;
   if (i7 == 0) {
      baro_bmp_periodic();
   }
}
static inline void modules_event_task(void) {
   baro_bmp_event();
}
…..

I suppose this code is based on .../conf/modules/baro_bmp.xml. But what is the effect of i7 and how/where is it generated?
It looks to me as if baro_bmp_event() is run 8 times as often as baro_bmp_periodic(). Is this correct?

Could someone please explain a little about this?

Thanks for any help,

Helge.




_______________________________________________ Paparazzi-devel mailing list address@hidden https://lists.nongnu.org/mailman/listinfo/paparazzi-devel

_______________________________________________
Paparazzi-devel mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/paparazzi-devel


_______________________________________________ Paparazzi-devel mailing list address@hidden https://lists.nongnu.org/mailman/listinfo/paparazzi-devel

_______________________________________________
Paparazzi-devel mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/paparazzi-devel



_______________________________________________ Paparazzi-devel mailing list address@hidden https://lists.nongnu.org/mailman/listinfo/paparazzi-devel

_______________________________________________
Paparazzi-devel mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/paparazzi-devel



_______________________________________________ Paparazzi-devel mailing list address@hidden https://lists.nongnu.org/mailman/listinfo/paparazzi-devel

_______________________________________________
Paparazzi-devel mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/paparazzi-devel



reply via email to

[Prev in Thread] Current Thread [Next in Thread]