3

I am a bit of a novice with the Arduino, and have had to learn a lot for my High Altitude balloon launch. I am getting ready to launch this, but for some reason, my datalogger, printing to an SD card, will work in the setup function but not the loop.

If someone could explain what is wrong with my code, and any improvements that could be made to it, it would be very helpful. I am using SPI, SD, I2C, Wire, Sparkfun BMP, and MPU6050 library.

    #include <SPI.h>
    #include <SD.h>
    #include <math.h>
    #define thermoPin 0

    #include <SFE_BMP180.h>
    SFE_BMP180 pressure;

    #define ALTITUDE 87.8
    #include "I2Cdev.h"

    #include "MPU6050_6Axis_MotionApps20.h"
    #include <Wire.h>

    MPU6050 mpu;
    #define OUTPUT_READABLE_YAWPITCHROLL

    #define OUTPUT_READABLE_REALACCEL

    #define analogInPin 3  // Analog input pin that the potentiometer is attached to

    int sensorValue = 0;        // value read from the sensor




    // MPU control/status vars
    bool dmpReady = false;  // set true if DMP init was successful
    uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
    uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
    uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
    uint16_t fifoCount;     // count of all bytes currently in FIFO
    uint8_t fifoBuffer[64]; // FIFO storage buffer

    // orientation/motion vars
    Quaternion q;           // [w, x, y, z]         quaternion container
    VectorInt16 aa;         // [x, y, z]            accel sensor measurements
    VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
    VectorFloat gravity;    // [x, y, z]            gravity vector
    float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

    volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
    void dmpDataReady() {
        mpuInterrupt = true;
    }



    #define photocellPin 2
    // the cell and 10K pulldown are connected to a9
    int photocellReading;     // the analog reading from the analog resistor divider

    #define chipSelect 4

    void setup() {
      pinMode(A5, OUTPUT);
      pinMode(A4, OUTPUT);
      // Open dataFile communications and wait for port to open:
      if (!SD.begin(chipSelect)) {
        // don't do anything more:
        return;
      }
        File dataFile = SD.open("datalog.txt", FILE_WRITE);
      if(dataFile) {

      // Initialize the sensor (it is important to get calibration values stored on the device).

      if (pressure.begin())
        dataFile.println("BMP180 init success");
      else
      {
        dataFile.println("BMP180 init fail\n\n");
        while(1); // Pause forever.
      } 
      // join I2C bus (I2Cdev library doesn't do this automatically)
        #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
            Wire.begin();
            TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
        #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
            Fastwire::setup(400, true);
        #endif
        dataFile.println(F("Initializing I2C devices..."));
        mpu.initialize();

        dataFile.println(F("Testing device connections..."));
        dataFile.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
        // load and configure the DMP
        dataFile.println(F("Initializing DMP..."));
        devStatus = mpu.dmpInitialize();

        mpu.setXGyroOffset(220);
        mpu.setYGyroOffset(76);
        mpu.setZGyroOffset(-85);
        mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
    mpu.setDMPEnabled(true);
    mpuIntStatus = mpu.getIntStatus(); 
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();
    dataFile.close();
      }

    }

    void loop() {
      // make a string for assembling the data to log:
      int valF, valC;
      valF = analogRead(thermoPin);
      valC = analogRead(thermoPin);
      File dataFile = SD.open("datalog.txt", FILE_WRITE);

      // if the file is available, write to it:
      if (dataFile) {

        dataFile.print(F("Millis since Launch"));
        dataFile.println(millis());
        dataFile.print(F(", Analog Val."));
        dataFile.print(valF);

        photocellReading = analogRead(photocellPin);

        dataFile.print(F("  Analog reading = "));
        dataFile.println(photocellReading);     // the raw analog reading
                                          // We'll have a few threshholds, qualitatively determined
      dataFile.println();
      char status;
      double T,P,p0,a;

        dataFile.print(F("provided altitude: "));
      dataFile.print(ALTITUDE,0);
      dataFile.println(F(" meters, "));


      status = pressure.startTemperature();
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);


        status = pressure.getTemperature(T);
        if (status != 0)
        {
          // Print out the measurement:
          dataFile.print(F("temperature: "));
          dataFile.print(T,2);
          dataFile.println(" deg F");


          status = pressure.startPressure(3);
          if (status != 0)
          {
            // Wait for the measurement to complete:
            delay(status);


            status = pressure.getPressure(P,T);
            if (status != 0)
            {
              // Print out the measurement:
              dataFile.print(F("absolute pressure: "));
              dataFile.print(P,2);
              dataFile.print(F(" mb, "));


              p0 = pressure.sealevel(P,ALTITUDE); // we're at 87.08 meters (Home)
              dataFile.print(F("relative (sea-level) pressure: "));
              dataFile.print(p0,2);
              dataFile.print(F(" mb, "));
              dataFile.print(p0*0.0295333727,2);
              dataFile.println(" inHg");


              a = pressure.altitude(P,p0);
              dataFile.print(F("computed altitude: "));
              dataFile.print(a,0);
              dataFile.print(F(" meters, "));
            }
            else dataFile.println("error retrieving pressure measurement\n");
          }
          else dataFile.println("error starting pressure measurement\n");
        }
        else dataFile.println("error retrieving temperature measurement\n");
      }
      else dataFile.println("error starting temperature measurement\n");
      // if programming failed, don't try to do anything
        if (!dmpReady) return;

        // wait for MPU interrupt or extra packet(s) available
        while (!mpuInterrupt && fifoCount < packetSize) {
        }

        // reset interrupt flag and get INT_STATUS byte
        mpuInterrupt = false;
        mpuIntStatus = mpu.getIntStatus();

        // get current FIFO count
        fifoCount = mpu.getFIFOCount();

        // check for overflow (this should never happen unless our code is too inefficient)
        if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
            // reset so we can continue cleanly
            mpu.resetFIFO();
            dataFile.println(F("FIFO overflow!"));

        // otherwise, check for DMP data ready interrupt (this should happen frequently)
        } else if (mpuIntStatus & 0x02) {
            // wait for correct available data length, should be a VERY short wait
            while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

            // read a packet from FIFO
            mpu.getFIFOBytes(fifoBuffer, packetSize);

            // track FIFO count here in case there is > 1 packet available
            // (this lets us immediately read more without waiting for an interrupt)
            fifoCount -= packetSize;

            #ifdef OUTPUT_READABLE_YAWPITCHROLL
                // display Euler angles in degrees
                mpu.dmpGetQuaternion(&q, fifoBuffer);
                mpu.dmpGetGravity(&gravity, &q);
                mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
                dataFile.print(F("ypr\t"));
                dataFile.print(ypr[0] * 180/M_PI);
                dataFile.print(F("\t"));
                dataFile.print(ypr[1] * 180/M_PI);
                dataFile.print(F("\t"));
                dataFile.println(ypr[2] * 180/M_PI);
            #endif

            #ifdef OUTPUT_READABLE_REALACCEL
                // display real acceleration, adjusted to remove gravity
                mpu.dmpGetQuaternion(&q, fifoBuffer);
                mpu.dmpGetAccel(&aa, fifoBuffer);
                mpu.dmpGetGravity(&gravity, &q);
                mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
                dataFile.print(F("areal\t"));
                dataFile.print(aaReal.x);
                dataFile.print(F("\t"));
                dataFile.print(aaReal.y);
                dataFile.print(F("\t"));
                dataFile.println(aaReal.z);
            #endif
        }
        // read the analog in value:
      sensorValue = analogRead(analogInPin);            
      // print the results to the dataFile monitor:
      dataFile.print(F("  analog Val of OZONE= " ));                       
      dataFile.println(sensorValue);                     
      dataFile.close();
      }
      analogWrite(A4, 168);
      delay(3000);
      analogWrite(A4, 0);
      delay(750);
      analogWrite(A5, 0);
      delay(250);
      analogWrite(A5, 168);
      delay(3000);
        analogWrite(A4, 168);
      delay(2000);
      analogWrite(A4, 0);
      delay(1000);
    }

Possible problems (correct me if I'm wrong):

  • I noticed that the MPU6050 stops transmitting if delays are put into it

EDIT: I have now tried the script but commented out the accelerometer (MPU6050) portion, and it successfully writes to the SD card. could someone explain why the accelerometer portion messes up the rest of the code?

1 Answer 1

1

I haven't followed all the details of your code, nor looked into all of the libraries being used, so you may need to ignore some of the following comments.

  1. You write “my datalogger, printing to an sd card, will work in the setup function but not the loop”. However, you don't say what you mean by “work”, nor how you tell if it works.

  2. It looks like your code in loop() uses the same filename as in setup(). If so, there's no reason to write a file insetup() because it will just be overwritten later. (If you have a reason, use a different file name.)

  3. Sequences like status = pressure.startTemperature(); if (status != 0) {... delay(status); ... } look suspect. The parameter to Arduino's delay() function is a number of milliseconds, in an unsigned long; is your startTemperature() supposed to return a status that's usable as the number of milliseconds to delay?

  4. Your status is declared via char status; and char is a signed type. If status is negative, the call delay(status); will first convert status to a signed long by sign-extension. Then it will convert the signed long to an unsigned long with the same bit pattern. This will ensure a delay of at least 7 weeks, which presumably is longer than you mean to wait. [Ref: See the “Conversions from Signed Integral Types” table in microsoft.com/en-us/library's Conversions from Signed Integral Types webpage.]

  5. To avoid those long and tedious sequences of dataFile.print(...); statements, you can #include Streaming.h, which is a contributed library that adds some “syntactic sugar” to Arduino C. At compile time it converts C++-like << stream operators to .print() calls, without increasing code size. If you don't have Streaming.h installed, install it via Streaming5.zip from arduiniana.org. Then, for example, in place of

    dataFile.print(F("areal\t")); dataFile.print(aaReal.x); dataFile.print(F("\t")); dataFile.print(aaReal.y); dataFile.print(F("\t")); dataFile.println(aaReal.z);

write

  dataFile << F("areal\t") << aaReal.x << '\t' << aaReal.y << '\t' << aaReal.z << endl;
  1. Whether using Streaming.h or not, writing F("\t") instead of '\t' uses half a dozen bytes of program memory where one will do, and uses the same amount or more of RAM. That is, while F() saves on RAM usage for long strings, it's of negative value for single characters and short strings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.