Using a BMP180 sensor on a rocket

Hello.

I am building a vector control rocket, and need to have a relatively precise altitude reading using the BMP180 sensor. I need it so that there is little noise in the center so that I can start the decent code when it begins to fall. What is a good way to limit noise on the pressure sensor, and what is relatively simple way to reliably detect apogee.

Thank you.

Normal electrical causion using decoupling capacitors, safe connections etc. You probably know about already.
Every sensor is noicy, more, or hopefully, less.
Knowing that about Your sensor often makes it possible to get a good accurazy out of it.
What You can apply is mathematical means like filtering. The usual statistics calculating a mean value and checking deviation might be useful. Look for better methods if needed.
Do You know what the noice looks like for the sensor You intend to use? Any data, any tests performed?

Thank you

No I have not done many tests. I am repetitively new to coding and the arduino platform. Are their any mechanical fixes? I am only a ninth grader so the math needed may be beyond me. Do you know of any exsisting filters?

Thank you

What are you classifying as noise? The communication is I2C, so it is data, bytes, you are receiving. Give us an example.

Paul

when the sensor is sitting still the altitude reading from the sparkfun example code moves randomly between -2 feet and +16 feet w/o me moving it. Im not sure why this is happening. Does it have to do with the pressure sensor being inside? Also is their a way that instead of eliminating this"noise" that I could just use several readings from the loop to be sure that the rocket has reached apogee?

Thank you for your help.

Okey, no tests done.
What about assembling the controller, the sensor and some display unit, PC or LCD? Then choose a high building and join the lift/elevator up and down, and collect readings? Analyze the readings, plot curves, and see what it looks like.

The sensor reads air preassure. Did You make Your try indoors or outdoors? Choose a place free from wind, climate, ventilation fans etc. Look att the data from that test.

" Then choose a high building and join the lift/elevator up and down"

What do you mean by this? My apologies I am not very Knowledgeable about electrical engineering or coding.

Nicolo3martinez:
" Then choose a high building and join the lift/elevator up and down"

What do you mean by this? My apologies I am not very Knowledgeable about electrical engineering or coding.

But you do know about elevators going up and down.

You have not told us about how you are powering the sensor and how stable that voltage is.

Paul

No I tried the sensor in doors. I will test it as soon as possible in the conditions you listed above.

Do you know how I could a non faulty way to detect the apogee of my rocket even if the sensor has several off readings? Is there a way to save and integer from several past loops? Here is my Code so far. The sensor is in a breakout board and is powered by 5 volt logic from a genuine Arduino Nano. I apologize I did not read the elevator sentence clearly and I was confused.

Thank you for all your help

bmppyrocode.ino (1.39 KB)

A project in Electronics Australia some (many) years back was a door annunciator which was nowhere near the shop or home door, but just sat on a bench or table and chimed when the door was opened or closed.

It used an electret microphone as a sensor of pressure surges. Such surges from door or wind movement would easily equate to a few metres in altitude. You are unlikely to suppress or average them easily, particularly in a travelling rocket. Whatever reading you get is always going to be within a modest range of error as a result. :astonished:

The sensor is within the rocket so there should be no moving air around the sensor. I do not need a super accurate reading i just need to detect when the rocket has changed from going up to falling (apogee).

Thank you for all the information.

Does anyone have any ideas?

Does the rocket have fins, or other means, that will tilt it from nose up to nose down when it has reached the top height?

It is extremely difficult to measure external air pressure from within a rocket (or any moving vehicle), because air moving over a surface exerts lower pressure on the surface, and distorts the readings. Look up the Bernoulli effect.

Even when in still air, to get reasonably stable air pressure readings with that sensor, you need to average hundreds of measurements.

what is relatively simple way to reliably detect apogee.

Unfortunately, there isn't a simple way.

Could I use an accelerometer on board to tell when the rocket has reached apogee? To answer your question RailRoader, the rocket has two sets of fins on set for stability and the other for guidance. Thank you all for your help. Is there any other sensors that i could use to figure out when my rocket starts to fall?

Is there any pre exsisting filters for the bmp180 or could i use an altimeter?

Could I use an accelerometer on board to tell when the rocket has reached apogee?

No, because in ballistic flight or free fall, the acceleration due to gravity as measured by an on board accelerometer is zero.

You can read about an advanced technique here (PDF copy of http://home.earthlink.net/~david.schultz/rnd/2004/KalmanApogeeII.pdf, no longer available on the web).

Thank you for that document, I will read through it thoroughly. If accelerometer measurements are skewed by vertical acceleration does that mean my gyroscope measurements will be off? I have put my code below (w/o the apogee part). PS i did not write the entire code myself.

/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
// Source: https://github.com/TKJElectronics/KalmanFilter
 Kristian Lauszus, TKJ Electronics
 Web      :  http://www.tkjelectronics.com
 e-mail   :  kristianl@tkjelectronics.com
 */
#include <SPI.h>
#include <SD.h>
#include <Servo.h>
#include <Wire.h>
#include <Kalman.h> 

//#define RESTRICT_PITCH // Comment out to restrict roll to ±90deg instead - please read: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf

Kalman kalmanX; // Create the Kalman instances
Kalman kalmanY;

/* IMU Data */
double accX, accY, accZ;
double gyroX, gyroY, gyroZ;
int16_t tempRaw;

double gyroXangle, gyroYangle; // Angle calculate using the gyro only
double compAngleX, compAngleY; // Calculated angle using a complementary filter
double kalAngleX, kalAngleY; // Calculated angle using a Kalman filter

uint32_t timer;
uint8_t i2cData[14]; // Buffer for I2C data

const float CorrectInt = -1.5;

const int Ser1up = 88;
const int Ser2up = 77;
const int Ser3up = 82;
const int Ser4up = 88;

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;

int LEDred = 13;
int LEDwht = 6;
const int chipSelect = 10;
// TODO: Make calibration routine
File ANTAREZ;



void setup() {

  pinMode(LEDred, OUTPUT);
  pinMode(LEDwht, OUTPUT);
  digitalWrite(LEDred, HIGH);
  delay(200);
  digitalWrite(LEDred, LOW);
  delay(100);
  digitalWrite(LEDred, HIGH);
  delay(200);
  digitalWrite(LEDred, LOW);
  delay(100);
  digitalWrite(LEDred, HIGH);
  delay(200);
  digitalWrite(LEDred, LOW);
  
  servo1.attach(2);
  servo2.attach(3);
  servo3.attach(4);
  servo4.attach(5);
  
  Serial.begin(115200);
  Wire.begin();
#if ARDUINO >= 157
  Wire.setClock(400000UL); // Set I2C frequency to 400kHz
#else
  TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
#endif

  i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
  i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
  i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
  i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
  while (i2cWrite(0x19, i2cData, 4, false)); // Write to all four registers at once
  while (i2cWrite(0x6B, 0x01, true)); // PLL with X axis gyroscope reference and disable sleep mode

  while (i2cRead(0x75, i2cData, 1));
  if (i2cData[0] != 0x68) { // Read "WHO_AM_I" register
    Serial.print(F("Error reading sensor"));
    while (1);
  }

  delay(100); // Wait for sensor to stabilize

  /* Set kalman and gyro starting angle */
  while (i2cRead(0x3B, i2cData, 6));
  accX = (int16_t)((i2cData[0] << 8) | i2cData[1]);
  accY = (int16_t)((i2cData[2] << 8) | i2cData[3]);
  accZ = (int16_t)((i2cData[4] << 8) | i2cData[5]);

  // It is then converted from radians to degrees
#ifdef RESTRICT_PITCH // Eq. 25 and 26
  double roll  = atan2(accY, accZ) * RAD_TO_DEG;
  double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
  double roll  = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
  double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif

  kalmanX.setAngle(roll); // Set starting angle
  kalmanY.setAngle(pitch);
  gyroXangle = roll;
  gyroYangle = pitch;
  compAngleX = roll;
  compAngleY = pitch;
  
Serial.print("Initializing SD card...");

if(!SD.begin(chipSelect))
{
   digitalWrite(LEDred, HIGH);
  delay(200);
  digitalWrite(LEDred, LOW);
  delay(100);
  digitalWrite(LEDred, HIGH);
  delay(200);
  digitalWrite(LEDred, LOW);
  delay(100);
  digitalWrite(LEDred, HIGH);
  delay(200);
  digitalWrite(LEDred, LOW);
}
servo1.write(45);
servo2.write(135);
servo3.write(135);
servo4.write(45);
delay(2000);

servo1.write(135);
servo2.write(45);
servo3.write(45);
servo4.write(135);
delay(2000);
servo1.write(Ser1up);
servo2.write(Ser2up);
servo3.write(Ser3up);
servo4.write(Ser4up);
delay(2000);

  timer = micros();
}

void loop() {
  /* Update all the values */

  digitalWrite(LEDwht, HIGH);
  while (i2cRead(0x3B, i2cData, 14));
  accX = (int16_t)((i2cData[0] << 8) | i2cData[1]);
  accY = (int16_t)((i2cData[2] << 8) | i2cData[3]);
  accZ = (int16_t)((i2cData[4] << 8) | i2cData[5]);
  tempRaw = (int16_t)((i2cData[6] << 8) | i2cData[7]);
  gyroX = (int16_t)((i2cData[8] << 8) | i2cData[9]);
  gyroY = (int16_t)((i2cData[10] << 8) | i2cData[11]);
  gyroZ = (int16_t)((i2cData[12] << 8) | i2cData[13]);;

  double dt = (double)(micros() - timer) / 1000000; // Calculate delta time
  timer = micros();

 
  // It is then converted from radians to degrees
#ifdef RESTRICT_PITCH // Eq. 25 and 26
  double roll  = atan2(accY, accZ) * RAD_TO_DEG;
  double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
  double roll  = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
  double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif

  double gyroXrate = gyroX / 131.0; // Convert to deg/s
  double gyroYrate = gyroY / 131.0; // Convert to deg/s

#ifdef RESTRICT_PITCH
  // This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees
  if ((roll < -90 && kalAngleX > 90) || (roll > 90 && kalAngleX < -90)) {
    kalmanX.setAngle(roll);
    compAngleX = roll;
    kalAngleX = roll;
    gyroXangle = roll;
  } else
    kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter

  if (abs(kalAngleX) > 90)
    gyroYrate = -gyroYrate; // Invert rate, so it fits the restriced accelerometer reading
  kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt);
#else
  // This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees
  if ((pitch < -90 && kalAngleY > 90) || (pitch > 90 && kalAngleY < -90)) {
    kalmanY.setAngle(pitch);
    compAngleY = pitch;
    kalAngleY = pitch;
    gyroYangle = pitch;
  } else
    kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt); // Calculate the angle using a Kalman filter

  if (abs(kalAngleY) > 90)
    gyroXrate = -gyroXrate; // Invert rate, so it fits the restriced accelerometer reading
  kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
#endif

  gyroXangle += gyroXrate * dt; // Calculate gyro angle without any filter
  gyroYangle += gyroYrate * dt;
  //gyroXangle += kalmanX.getRate() * dt; // Calculate gyro angle using the unbiased rate
  //gyroYangle += kalmanY.getRate() * dt;

  compAngleX = 0.93 * (compAngleX + gyroXrate * dt) + 0.07 * roll; // Calculate the angle using a Complimentary filter
  compAngleY = 0.93 * (compAngleY + gyroYrate * dt) + 0.07 * pitch;

  // Reset the gyro angle when it has drifted too much
  if (gyroXangle < -180 || gyroXangle > 180)
    gyroXangle = kalAngleX;
  if (gyroYangle < -180 || gyroYangle > 180)
    gyroYangle = kalAngleY;

  /* Print Data */
#if 0 // Set to 1 to activate
  Serial.print(accX); Serial.print("\t");
  Serial.print(accY); Serial.print("\t");
  Serial.print(accZ); Serial.print("\t");

  Serial.print(gyroX); Serial.print("\t");
  Serial.print(gyroY); Serial.print("\t");
  Serial.print(gyroZ); Serial.print("\t");

  Serial.print("\t");
#endif
  Serial.print(kalAngleX); Serial.print("\t");
  Serial.println(kalAngleY); Serial.print("\t");

  servo1.write((kalAngleY * CorrectInt) + Ser1up);
  servo2.write(((kalAngleY * CorrectInt) - Ser2up) * -1);
  servo3.write((kalAngleX * CorrectInt) + Ser3up);
  servo4.write(((kalAngleX * CorrectInt) - Ser4up) * -1);
  //int Time = micros();
  ANTAREZ = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (ANTAREZ) {
    //ANTAREZ.print(Time);
    ANTAREZ.print(",  ");
    ANTAREZ.print(kalAngleY);
    ANTAREZ.print(",   ");
    ANTAREZ.println(kalAngleX);
    ANTAREZ.close();
  }
  else {
    Serial.println("error opening datalog.txt");
  }

  

  delay(2);

}

The code you posted is not a Kalman filter, despite the author's pretensions, and doesn't work very well. Don't bother with it.