Different Results when Global and Local Variables?

Hi,
I am creating a sketch for a UAV data logging platform. I am using a Kalman filter to combine gyro and accelerometer readings in order to gain more accurate Pitch and Role Values. When declaring the Kalman variables as global the code behaves as expected (180, 180 on flat surface), however when I define them locally in the function they are used within I get unexpected values(0, 0 and climbing indefinitely past 360 each time a reading is taken). Ideally I would like to have them declared locally as it saves me a significant amount of SRAM.

This is the library I am using for the Kalman filter : GitHub - TKJElectronics/KalmanFilter: This is a Kalman filter used to calculate the angle, rate and bias from from the input of an accelerometer/magnetometer and a gyroscope.

#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <SdFat.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_L3GD20.h>
#include <Adafruit_BMP085.h>
#include <Kalman.h>
TinyGPS gps;
SoftwareSerial ss(8, 7);
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(54321);
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);
Adafruit_L3GD20 gyro;
Adafruit_BMP085 bmp;
Kalman kalmanX, kalmanY;
float Ground_pressure;
SdFat sd;
SdFile file;

void setup() {      // put your setup code here, to run once:
Serial.begin(9600);
  !sd.begin(10);
  !file.open("data.txt", FILE_WRITE);
  file.println(F("Satallites  Latitude(deg)  Longitude(deg)  Altitude(m)  Time      Pitch(deg)  Roll(deg)  Yaw(deg)  Altitude(m)"));
  file.println(F("--------------------------------------------------------------------------------------------------------------"));
  file.close();
  mag.enableAutoRange(true);
  !gyro.begin(gyro.L3DS20_RANGE_250DPS);
  !accel.begin();
  !mag.begin();
  !bmp.begin();
  Ground_pressure = bmp.readPressure();
  ss.begin(9600);
}

void loop() {
   //put your main code here, to run repeatedly:
  !file.open("data.txt", FILE_WRITE);
  GPS_Data();
  file.print(pitch());  file.print("         ");
  file.print(roll()); file.print("        ");
  file.print(yaw());  file.print("       ");
  file.println(real_altitude());
  file.close();
}

void GPS_Data() {
  int year;
  float flat, flon;
  byte month, day, hour, minute, second;
  unsigned long start = millis();
  gps.f_get_position(&flat, &flon);
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second);
  if (flat == TinyGPS::GPS_INVALID_F_ANGLE)
    file.print(F("*           *********      *********       *****        ********  "));
  else
    {
    file.print(gps.satellites());
    file.print("           ");
    file.print(flat, 6);
    file.print("      ");
    file.print(flon, 6);
    file.print("       ");
    file.print(gps.f_altitude());
    file.print("        ");
    file.print(hour);
    file.print(":");
    file.print(minute);
    file.print(":");
    file.print(second);
    file.print("   ");
    }
 do 
  {
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < 1000);
}

float acceleration_roll() {
  sensors_event_t event;
  accel.getEvent(&event);
  float ROLL = atan2(event.acceleration.y, event.acceleration.z)+PI;
  return ROLL;
}

float acceleration_pitch() {
  sensors_event_t event;
  accel.getEvent(&event);
  float PITCH = atan2(event.acceleration.x, event.acceleration.z)+PI;
  return PITCH;
}

int yaw() {
  sensors_event_t event; 
  mag.getEvent(&event);
  float mag_x = event.magnetic.x;
  float mag_y = event.magnetic.y;
  float mag_z = event.magnetic.z;
  float Xh = mag_x * cos(acceleration_pitch()) + mag_z * sin(acceleration_pitch());
  float Yh = mag_x * sin(acceleration_roll())*sin(acceleration_pitch()) + mag_y * cos(acceleration_roll()) -  mag_z * sin(acceleration_roll()) * cos(acceleration_pitch());
  int Heading = atan2(Yh, Xh) * (180 / M_PI);
  if(Heading < 0)
    Heading = Heading + 360;
  return Heading;
}

double real_altitude()  {
  double Altitude = bmp.readAltitude(Ground_pressure);
  return Altitude;
}

int roll() {
  //Kalman kalmanY; // Doesn't Work
  uint8_t timer = micros();
  float dt = (float)(micros() - timer) / 1000000;
  float kalAngle;
  gyro.read();
  kalAngle = ((kalmanY.getAngle(acceleration_roll(), gyro.data.y, dt)) * (180 / M_PI));
  return kalAngle;
}

int pitch() {
  //Kalman kalmanX; // Doesn't Work
  uint8_t timer = micros();
  float dt = (float)(micros() - timer) / 1000000;
  float kalAngle;
  gyro.read();
  kalAngle = ((kalmanX.getAngle(acceleration_pitch(), gyro.data.x, dt)) * (180 / M_PI));
  return kalAngle;
}

Any ideas?

Any other code optimisation (Program or SRAM) would be welcome if there is any suggestions.
Thanks

So about which variable are we talking?

And if you get a different result from two different sketches, why only post one?

Hi, Sorry it wasn't clear. I'm talking about the line of code near the top

Kalman kalmanX, kalmanY;

compared to

Kalman kalmanY;

and

Kalman kalmanX;

in the pitch and roll functions at the bottom respectively, these have been commented in the sketch.

Ideally I would like to have them declared locally as it saves me a significant amount of SRAM.

If they are local to a function, they go out of scope, and are deleted, when the function ends, losing any data.

Making then local and static prevents them from being destroyed, but then you might as well make them global.

So, you can't really save SRAM with local variables that are objects.

static Kalman kalmanX;

And now?

Declaring them as static obtains the correct results but increases SRAM usage compared to defining globally

Makes a a lot clearer.

But okay, it's a filter. And a filter cannot work on a single piece of information. So the Kalman object wants to store some information so it can do a filter operation. But by declaring the object local you create and destroy (together with the info) the object every call of the function!

If pitch is indeed the only function that uses kalmanX then it's indeed a good idea to make it a local variable (declare a variable as local as you need it). And to fix the amnesia of the filter, declare it as a static ;)

@samreeve196, can you explain why static would take up more RAM?

PaulS: So, you can't really save SRAM with local variables that are objects.

Mm, as long as they don't need to remember stuff between two calls you can. Then there is no problem in destroying them after the call.

I’m not sure why declaring static takes up more SRAM, but when compiled it takes the usage up 1% compared to defining globally, according to the Arduino IDE atleast.

Because declaring them static essentially makes the compiler treat them like globals, and allocates them in the global data area. They exist all the time whether or not the function is being run. The compiler just limits the scope. Non-static variables are allocated on the stack and only exist when the function is called.

Makes more sense now. Thanks for all your help

@Keith, yes, that's what I thought. But Sam says it takes more ram when they are static then when they are global. Which makes no sens to me...

Some kind of gcc quirk, though 1% is not much. It might need an extra pointer for something.