0

I'm new to Arduino and Stack Exchange. I've been building a fitness tracker and am receiving a certain error in the serial monitor. The accelerometer seems the work, but it seems to go to sleep after a while. I'm using an Arduino Uno (for the time being), a Bluetooth HC-05 module and an MPU6050 accelerometer. I connect it to an app, Retroband to monitor the steps taken and calories burnt.

I've wired it like this:

Accelerometer:

 SDA-A4
 SCL-A5
 VCC-3.3v
 GND-GND

Bluetooth:

 VCC-3.3v
 GND-GND
 TX-2
 RX-3

Here is the code I'm using:

#include <math.h>
#include <Wire.h>
#include <SoftwareSerial.h>


/* Bluetooth */
SoftwareSerial BTSerial(2, 3); //Connect HC-06. Use your (TX, RX) settings

/* time */
#define SENDING_INTERVAL 1000
#define SENSOR_READ_INTERVAL 50
unsigned long prevSensoredTime = 0;
unsigned long curSensoredTime = 0;

/* Data buffer */
#define ACCEL_BUFFER_COUNT 125
byte aAccelBuffer[ACCEL_BUFFER_COUNT];
int iAccelIndex = 2;

/* MPU-6050 sensor */
#define MPU6050_ACCEL_XOUT_H 0x3B // R
#define MPU6050_PWR_MGMT_1 0x6B // R/W
#define MPU6050_PWR_MGMT_2 0x6C // R/W
#define MPU6050_WHO_AM_I 0x75 // R
#define MPU6050_I2C_ADDRESS 0x68

typedef union accel_t_gyro_union {
  struct {
    uint8_t x_accel_h;
    uint8_t x_accel_l;
    uint8_t y_accel_h;
    uint8_t y_accel_l;
    uint8_t z_accel_h;
    uint8_t z_accel_l;
    uint8_t t_h;
    uint8_t t_l;
    uint8_t x_gyro_h;
    uint8_t x_gyro_l;
    uint8_t y_gyro_h;
    uint8_t y_gyro_l;
    uint8_t z_gyro_h;
    uint8_t z_gyro_l;
  } reg;

  struct {
    int x_accel;
    int y_accel;
    int z_accel;
    int temperature;
    int x_gyro;
    int y_gyro;
    int z_gyro;
  } value;
};



void setup() {
  int error;
  uint8_t c;

  Serial.begin(9600);
  Wire.begin();
  BTSerial.begin(9600);  // set the data rate for the BT port

  // default at power-up:
  // Gyro at 250 degrees second
  // Acceleration at 2g
  // Clock source at internal 8MHz
  // The device is in sleep mode.
  //
  error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);
  Serial.print(F("WHO_AM_I : "));
  Serial.print(c,HEX);
  Serial.print(F(", error = "));
  Serial.println(error,DEC);

  // According to the datasheet, the 'sleep' bit
  // should read a '1'. But I read a '0'.
  // That bit has to be cleared, since the sensor
  // is in sleep mode at power-up. Even if the
  // bit reads '0'.
  error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1);
  Serial.print(F("PWR_MGMT_2 : "));
  Serial.print(c,HEX);
  Serial.print(F(", error = "));
  Serial.println(error,DEC);

  // Clear the 'sleep' bit to start the sensor.
  MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);

  initBuffer();
}

void loop() {
  curSensoredTime = millis();

  // Read from sensor
  if(curSensoredTime - prevSensoredTime > SENSOR_READ_INTERVAL) {
    readFromSensor();  // Read from sensor
    prevSensoredTime = curSensoredTime;

    // Send buffer data to remote
    if(iAccelIndex >= ACCEL_BUFFER_COUNT - 3) {
      sendToRemote();
      initBuffer();
      Serial.println("------------- Send 20 accel data to remote");
    }
  }
}

/**************************************************
 * BT Transaction
 **************************************************/
void sendToRemote() {
  // Write gabage bytes
  BTSerial.write( "accel" );
  // Write accel data
  BTSerial.write( (char*)aAccelBuffer );
  // Flush buffer
  //BTSerial.flush();
}

/**************************************************
 * Read data from sensor and save it
 **************************************************/
void readFromSensor() {
  int error;
  double dT;
  accel_t_gyro_union accel_t_gyro;

  error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) &accel_t_gyro, sizeof(accel_t_gyro));
  if(error != 0) {
    Serial.print(F("Read accel, temp and gyro, error = "));
    Serial.println(error,DEC);
  }

  // Swap all high and low bytes.
  // After this, the registers values are swapped,
  // so the structure name like x_accel_l does no
  // longer contain the lower byte.
  uint8_t swap;
  #define SWAP(x,y) swap = x; x = y; y = swap
  SWAP (accel_t_gyro.reg.x_accel_h, accel_t_gyro.reg.x_accel_l);
  SWAP (accel_t_gyro.reg.y_accel_h, accel_t_gyro.reg.y_accel_l);
  SWAP (accel_t_gyro.reg.z_accel_h, accel_t_gyro.reg.z_accel_l);
  SWAP (accel_t_gyro.reg.t_h, accel_t_gyro.reg.t_l);
  SWAP (accel_t_gyro.reg.x_gyro_h, accel_t_gyro.reg.x_gyro_l);
  SWAP (accel_t_gyro.reg.y_gyro_h, accel_t_gyro.reg.y_gyro_l);
  SWAP (accel_t_gyro.reg.z_gyro_h, accel_t_gyro.reg.z_gyro_l);

  // Print the raw acceleration values
  Serial.print(F("accel x,y,z: "));
  Serial.print(accel_t_gyro.value.x_accel, DEC);
  Serial.print(F(", "));
  Serial.print(accel_t_gyro.value.y_accel, DEC);
  Serial.print(F(", "));
  Serial.print(accel_t_gyro.value.z_accel, DEC);
  Serial.print(F(", at "));
  Serial.print(iAccelIndex);
  Serial.println(F(""));

  if(iAccelIndex < ACCEL_BUFFER_COUNT && iAccelIndex > 1) {
    int tempX = accel_t_gyro.value.x_accel;
    int tempY = accel_t_gyro.value.y_accel;
    int tempZ = accel_t_gyro.value.z_accel;
    /*
    // Check min, max value
    if(tempX > 16380) tempX = 16380;
    if(tempY > 16380) tempY = 16380;
    if(tempZ > 16380) tempZ = 16380;

    if(tempX < -16380) tempX = -16380;
    if(tempY < -16380) tempY = -16380;
    if(tempZ < -16380) tempZ = -16380;

    // We dont use negative value
    tempX += 16380;
    tempY += 16380;
    tempZ += 16380;
    */
    char temp = (char)(tempX >> 8);
    if(temp == 0x00)
      temp = 0x7f;
    aAccelBuffer[iAccelIndex] = temp;
    iAccelIndex++;
    temp = (char)(tempX);
    if(temp == 0x00)
      temp = 0x01;
    aAccelBuffer[iAccelIndex] = temp;
    iAccelIndex++;

    temp = (char)(tempY >> 8);
    if(temp == 0x00)
      temp = 0x7f;
    aAccelBuffer[iAccelIndex] = temp;
    iAccelIndex++;
    temp = (char)(tempY);
    if(temp == 0x00)
      temp = 0x01;
    aAccelBuffer[iAccelIndex] = temp;
    iAccelIndex++;

    temp = (char)(tempZ >> 8);
    if(temp == 0x00)
      temp = 0x7f;
    aAccelBuffer[iAccelIndex] = temp;
    iAccelIndex++;
    temp = (char)(tempZ);
    if(temp == 0x00)
      temp = 0x01;
    aAccelBuffer[iAccelIndex] = temp;
    iAccelIndex++;
  }

  // The temperature sensor is -40 to +85 degrees Celsius.
  // It is a signed integer.
  // According to the datasheet:
  // 340 per degrees Celsius, -512 at 35 degrees.
  // At 0 degrees: -512 - (340 * 35) = -12412
//  Serial.print(F("temperature: "));
//  dT = ( (double) accel_t_gyro.value.temperature + 12412.0) / 340.0;
//  Serial.print(dT, 3);
//  Serial.print(F(" degrees Celsius"));
//  Serial.println(F(""));

  // Print the raw gyro values.
//  Serial.print(F("gyro x,y,z : "));
//  Serial.print(accel_t_gyro.value.x_gyro, DEC);
//  Serial.print(F(", "));
//  Serial.print(accel_t_gyro.value.y_gyro, DEC);
//  Serial.print(F(", "));
//  Serial.print(accel_t_gyro.value.z_gyro, DEC);
//  Serial.println(F(""));
}

/**************************************************
 * MPU-6050 Sensor read/write
 **************************************************/
int MPU6050_read(int start, uint8_t *buffer, int size)
{
  int i, n, error;

  Wire.beginTransmission(MPU6050_I2C_ADDRESS);

  n = Wire.write(start);
  if (n != 1)
    return (-10);

  n = Wire.endTransmission(false); // hold the I2C-bus
  if (n != 0)
    return (n);

  // Third parameter is true: relase I2C-bus after data is read.
  Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
  i = 0;
  while(Wire.available() && i<size)
  {
    buffer[i++]=Wire.read();
  }
  if ( i != size)
    return (-11);
  return (0); // return : no error
}

int MPU6050_write(int start, const uint8_t *pData, int size)
{
  int n, error;

  Wire.beginTransmission(MPU6050_I2C_ADDRESS);

  n = Wire.write(start); // write the start address
  if (n != 1)
    return (-20);

  n = Wire.write(pData, size); // write data bytes
  if (n != size)
    return (-21);

  error = Wire.endTransmission(true); // release the I2C-bus
  if (error != 0)
    return (error);
  return (0); // return : no error
}

int MPU6050_write_reg(int reg, uint8_t data)
{
  int error;
  error = MPU6050_write(reg, &data, 1);
  return (error);
}


/**************************************************
 * Utilities
 **************************************************/
void initBuffer() {
  iAccelIndex = 2;
  for(int i=iAccelIndex; i<ACCEL_BUFFER_COUNT; i++) {
    aAccelBuffer[i] = 0x00;
  }
  aAccelBuffer[0] = 0xfe;
  aAccelBuffer[1] = 0xfd;
  aAccelBuffer[122] = 0xfd;
  aAccelBuffer[123] = 0xfe;
  aAccelBuffer[124] = 0x00;
}

This is the error I got in serial monitor:

    WHO_AM_I : 0, error = 2
PWR_MGMT_2 : 0, error = 2
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, -3840, at 2
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 8
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 14
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 20
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 26
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 32
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 38
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 44
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 50
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 56
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 62
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 68
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 74
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 80
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 86
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 92
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 98
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 104
Read accel, temp and gyro, error = 2
accel x,y,z: 2969, 409, 123, at 110
Read accel, temp and gyro, error = 2
accel x,y,z: -26357, -26367, 31488, at 116

I'm not too good at Arduino, and any help will be immensely appreciated.

8
  • What is missing to be able to help you with this? – Mikael Patel Jan 12 '16 at 12:06
  • Function MPU6050_read is never defined. You are obviously using a library, but unless you tell us which one you can't get any support – frarugi87 Jan 12 '16 at 12:11
  • The code is for MPU6050 which is an I2C device but adxl335 is an analog device?!?! – Mikael Patel Jan 12 '16 at 12:15
  • It looks defined to me - it's sat there in the code... By the way, error 2 is "TW_MT_SLA_NACK" which is "error: address send, nack received" – Majenko Jan 12 '16 at 12:15
  • Sorry, I am using the MPU6050. My bad! – user16335 Jan 12 '16 at 12:32
1

You have a problem that you can see (the error 2) and a theory about what might be causing it (the accelerometer going to sleep). That's a great place to start from!

I have a few of suggestions to make:

  • Collect documentation for the components you are using, a data sheet for the accelerometer, tutorials and instructions for the code to drive it, etc.

    A search on:

    MPU6050 accelerometer data sheet

    is likely to get you lots of links to sites hosting data sheets for the accelerometer. With luck you'll be able to find the actual vendor and in addition to the data sheet you may able to find application notes there as well.

    For the library, you may find a tutorial or an API description on the site where you downloaded it. You can also do a search on something like:

    MPU6050 accelerometer tutorial

    to find suggestions for how to get started with the device and the code to use it. Tutorials often have sections on testing and avoiding common pitfalls with the device.

  • Once you have some documentation see what you can learn about the error. Who generates "error 2?" What does it mean? When does it occur? Once you understand the problem, the answer may be obvious.

  • Create minimal test cases. The code sample above is a lot for you, or us, to make sense of and then to test/debug. Pare your code down (or build it up, depending where you are in the process and how you like to work on problems) until you have the minimum code needed to test the accelerometer.

    Do you see the problem in that code? If you do, then you have many fewer possible problems to look at. If you don't, then add the next piece – perhaps in this case, try to exercise the condition that "error 2" is supposed to report (does it still seem likely that "going to sleep" is the problem?

If you're still stumped at this point you've got the resources at hand to post a great question and the evidence that you've worked on it and understand it for yourself will go a long way towards establishing good will with the people who are trying to help you find answers.

Since this is (potentially) a hardware and a software problem, be sure to include an accurate schematic, or photo, of how your project is put together. If you are using someone else's schematic be especially cautious of any potential differences!

0

From examination of the sketch, the error '2' that you are seeing is returned from MPU6050_read(), by the line

n = Wire.endTransmission(false); // hold the I2C-bus

Looking at the reference for the Wire library, endTransmission() returns 2 when

2:received NACK on transmit of address

So, when you transmit to the MPU6050, the MPU6050 appears to be returning a Not Acknowledged (NACK) packet.

Why a NACK is being returned is not too clear. From Mpu6050 - error 2 - endTransmission:

It means the chips is either not connected (or not correctly) or the wrong address was sent.

From the MPU-6050 page on Arduino Playground, it seems that the address should be 0x68 or 0x69

The pin "AD0" selects between I2C address 0x68 and 0x69. That makes it possible to have two of these sensors in a project. Most breakout boards have a pullup or pulldown resistor to make AD0 default low or high. Connect AD0 to GND or 3.3V for the other I2C address.

What is AD0 connected to? You do not mention that, in your wiring list for the MPU-6050. If you connect AD0 to GND then address 0x68 is used, if it is to 3.3V then the address is 0x69. From MPU6050 SparkFun Breakout to Arduino Uno - No Communication.

AD0 must be connected to ground or 3.3V (with solder jumper). Connect it to ground for I2C address 0x68. SCL and SDA are connected directly to the Arduino, but you could add extra pull-up resistors to the 3.3V. The resistors could be 4k7 or 10k (the board already has 10k pull-up resistors, but I prefer 4k7). You don't need the INT, you could leave it open. The CLKIN and FSYNC can be tied to ground, because they are not used.

I would suggest checking your wiring, and look for any loose contacts on the MPU6050 board.

0

I have got same problem and you can solve it in minutes! Firstly check all your I2C addresses with same code:

#include "Wire.h"

byte start_address = 0;
byte end_address = 127;

void setup()
{
  byte rc;
  Wire.begin();

  Serial.begin(9600);
  Serial.println("\nI2C Scanner");

  Serial.print("Scanning I2C bus from ");
  Serial.print(start_address,DEC);  Serial.print(" to ");  Serial.print(end_address,DEC);
  Serial.println("...");

  for( byte addr  = start_address;
            addr <= end_address;
            addr++ ) {
      Wire.beginTransmission(addr);
      rc = Wire.endTransmission();

      if (addr<16) Serial.print("0");
      Serial.print(addr,HEX);
      if (rc==0) {
        Serial.print(" found!");
      } else {
        Serial.print(" "); Serial.print(rc); Serial.print("     ");
      }
      Serial.print( (addr%8)==7 ? "\n":" ");
  }

  Serial.println("\n-------------------------------\nPossible devices:");

  for( byte addr  = start_address;
            addr <= end_address;
            addr++ ) {
      Wire.beginTransmission(addr);
      rc = Wire.endTransmission();
      if (rc == 0) {
        Serial.print(addr,HEX); Serial.print(" = ");
        switch (addr) {
          case 0x50: Serial.println("AT24C32/AT24C64 - EEPROM"); break;
          case 0x68: Serial.println("DS1307"); break;
          default: Serial.println("Unknown"); break;
        }
      }
  }

  Serial.println("\ndone");
}

// standard Arduino loop()
void loop()
{
    // Nothing to do here, so we'll just blink the built-in LED
    digitalWrite(13,HIGH); delay(300);
    digitalWrite(13,LOW);  delay(300);
}

And you will get something like this:

I2C Scanner
Scanning I2C bus from 0 to 127...
00 2      01 2      02 2      03 2      04 2      05 2      06 2      07 2     
08 2      09 2      0A 2      0B 2      0C 2      0D 2      0E 2      0F 2     
10 2      11 2      12 2      13 2      14 2      15 2      16 2      17 2     
18 2      19 2      1A 2      1B 2      1C 2      1D 2      1E 2      1F 2     
20 2      21 2      22 2      23 2      24 2      25 2      26 2      27 2     
28 2      29 2      2A 2      2B 2      2C 2      2D 2      2E 2      2F 2     
30 2      31 2      32 2      33 2      34 2      35 2      36 2      37 2     
38 2      39 2      3A 2      3B 2      3C 2      3D 2      3E 2      3F 2     
40 2      41 2      42 2      43 2      44 2      45 2      46 2      47 2     
48 2      49 2      4A 2      4B 2      4C 2      4D 2      4E 2      4F 2     
50 2      51 2      52 2      53 2      54 2      55 2      56 2      57 2     
58 2      59 2      5A 2      5B 2      5C 2      5D 2      5E 2      5F 2     
60 2      61 2      62 2      63 2      64 2      65 2      66 2      67 2     
68 2      69 found! 6A 2      6B 2      6C 2      6D 2      6E 2      6F 2     
70 2      71 2      72 2      73 2      74 2      75 2      76 2      77 2     
78 2      79 2      7A 2      7B 2      7C 2      7D 2      7E 2      7F 2     

-------------------------------
Possible devices:
69 = Unknown

done

The address 69 is your device, MPU-6050! Now check your code and you can see that you use:

#define MPU6050_I2C_ADDRESS 0x68

But you must use the correct address of MPU, change it:

#define MPU6050_I2C_ADDRESS 0x69

Code source.

1
  • I have added a link to the original author and removed the bold – RSM Jun 13 '16 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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