0

I have the following very basic program that reads MPU6050(accelerometer and gyroscope) sensor using the I2C library, and prints the sensor information. This program works as expected.

#include <Arduino.h>
#include <MPU6050_6Axis_MotionApps20.h>

inline void printToSerial(bool, bool) attribute((always_inline));

MPU6050 imu; int16_t ax, ay, az, gx, gy, gz;

void setup() { imu.initialize();

imu.setFullScaleGyroRange(MPU6050_GYRO_FS_250); imu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);

imu.setXAccelOffset(-1451); imu.setYAccelOffset(-682); imu.setZAccelOffset(1448); imu.setXGyroOffset(69); imu.setYGyroOffset(-16); imu.setZGyroOffset(29); Serial.begin(9600); }

void loop() {
imu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); printToSerial(false, true); delay(50); }

void printToSerial(bool a, bool g){ if(a){ Serial.print(ax); Serial.print("\t"); Serial.print(ay); Serial.print("\t"); Serial.println(az); }

if(g){ Serial.print(gx); Serial.print("\t"); Serial.print(gy); Serial.print("\t"); Serial.println(gz); } }

But as I want to add more functionality to the main program - I want to move MPU6050 specific code to separate file.

So, I created Sensor.h with the following content,

#ifndef SENSOR_H
#define SENSOR_H

#include <MPU6050_6Axis_MotionApps20.h>

extern MPU6050 imu; extern int16_t ax, ay, az, gx, gy, gz;

void sensorInit(); void sensorUpdate();

#endif

And placed the implementation in the Sensor.cpp file.

# include "Sensor.h"

void sensorInit(){ imu.initialize();

imu.setFullScaleGyroRange(MPU6050_GYRO_FS_250); imu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);

imu.setXAccelOffset(-1451); imu.setYAccelOffset(-682); imu.setZAccelOffset(1448); imu.setXGyroOffset(69); imu.setYGyroOffset(-16); imu.setZGyroOffset(29); }

void sensorUpdate(){ imu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); }

And finally, modified the main.cpp file in the following way,

#include "Sensor.h"
#include <Arduino.h>

inline void printToSerial(bool, bool) attribute((always_inline));

void setup() { sensorInit(); // replaced few lines of codes Serial.begin(9600); }

void loop() {
sensorUpdate(); // replaced few lines of codes printToSerial(false, true); delay(50); }

void printToSerial(bool a, bool g){ if(a){ Serial.print(ax); Serial.print("\t"); Serial.print(ay); Serial.print("\t"); Serial.println(az); }

if(g){ Serial.print(gx); Serial.print("\t"); Serial.print(gy); Serial.print("\t"); Serial.println(gz); } }

But when I try to build the code, I get the following error in the linking step,

.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpInitialize()'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':   
(.text+0x0): multiple definition of `MPU6050::dmpPacketAvailable()'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':   
(.text+0x0): multiple definition of `MPU6050::dmpGetAccel(long*, unsigned char const*)'       
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':   
(.text+0x0): multiple definition of `MPU6050::dmpGetAccel(int*, unsigned char const*)'        
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':   
(.text+0x0): multiple definition of `MPU6050::dmpGetAccel(VectorInt16*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':   
(.text+0x0): multiple definition of `MPU6050::dmpGetQuaternion(long*, unsigned char const*)'  
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetQuaternion(int*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetQuaternion(Quaternion*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetGyro(long*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetGyro(int*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetGyro(VectorInt16*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetLinearAccel(VectorInt16*, VectorInt16*, VectorFloat*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetLinearAccelInWorld(VectorInt16*, VectorInt16*, Quaternion*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetGravity(int*, unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetGravity(VectorFloat*, Quaternion*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetEuler(float*, Quaternion*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetYawPitchRoll(float*, Quaternion*, VectorFloat*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpProcessFIFOPacket(unsigned char const*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpReadAndProcessFIFOPacket(unsigned char, unsigned char*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetFIFOPacketSize()'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\build\uno\src\main.cpp.o (symbol from plugin): In function `MPU6050::dmpInitialize()':
(.text+0x0): multiple definition of `MPU6050::dmpGetCurrentFIFOPacket(unsigned char*)'
.pio\build\uno\src\Sensor.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pio\libdeps\uno\I2Cdevlib-MPU6050/MPU6050.h:436:7: warning: type 'struct MPU6050' violates one definition rule [-Wodr]
 class MPU6050 {
       ^
.pio\libdeps\uno\I2Cdevlib-MPU6050\MPU6050.h:436:7: note: a different type is defined in another translation unit
 class MPU6050 {
       ^
.pio\libdeps\uno\I2Cdevlib-MPU6050/MPU6050.h:1036:18: note: the first difference of corresponding definitions is field 'dmpPacketBuffer'
         uint8_t *dmpPacketBuffer;
                  ^
.pio\libdeps\uno\I2Cdevlib-MPU6050\MPU6050.h:436:7: note: a type with different number of fields is defined in another translation unit
 class MPU6050 {
       ^
C:\Users\iamcr\AppData\Local\Temp\cc1jV0kL.ltrans0.ltrans.o: In function `MPU6050::getDeviceID() [clone .constprop.29]':
<artificial>:(.text+0xbba): undefined reference to `imu'
<artificial>:(.text+0xbd0): undefined reference to `imu'
<artificial>:(.text+0xbd4): undefined reference to `imu'
C:\Users\iamcr\AppData\Local\Temp\cc1jV0kL.ltrans0.ltrans.o: In function `main':
<artificial>:(.text.startup+0x10c): undefined reference to `imu'
<artificial>:(.text.startup+0x11c): undefined reference to `imu'
C:\Users\iamcr\AppData\Local\Temp\cc1jV0kL.ltrans0.ltrans.o:<artificial>:(.text.startup+0x12a): more undefined references to `imu' follow
C:\Users\iamcr\AppData\Local\Temp\cc1jV0kL.ltrans0.ltrans.o: In function `main':
<artificial>:(.text.startup+0x282): undefined reference to `ax'
<artificial>:(.text.startup+0x286): undefined reference to `ax'
<artificial>:(.text.startup+0x28a): undefined reference to `imu'
<artificial>:(.text.startup+0x28e): undefined reference to `imu'
<artificial>:(.text.startup+0x298): undefined reference to `ay'
<artificial>:(.text.startup+0x29c): undefined reference to `ay'
<artificial>:(.text.startup+0x2a0): undefined reference to `imu'
<artificial>:(.text.startup+0x2a4): undefined reference to `imu'
<artificial>:(.text.startup+0x2ae): undefined reference to `az'
<artificial>:(.text.startup+0x2b2): undefined reference to `az'
<artificial>:(.text.startup+0x2b6): undefined reference to `imu'
<artificial>:(.text.startup+0x2ba): undefined reference to `imu'
<artificial>:(.text.startup+0x2c4): undefined reference to `gx'
<artificial>:(.text.startup+0x2c8): undefined reference to `gx'
<artificial>:(.text.startup+0x2cc): undefined reference to `imu'
<artificial>:(.text.startup+0x2d0): undefined reference to `imu'
<artificial>:(.text.startup+0x2da): undefined reference to `gy'
<artificial>:(.text.startup+0x2de): undefined reference to `gy'
<artificial>:(.text.startup+0x2e2): undefined reference to `imu'
<artificial>:(.text.startup+0x2e6): undefined reference to `imu'
<artificial>:(.text.startup+0x2f0): undefined reference to `gz'
<artificial>:(.text.startup+0x2f4): undefined reference to `gz'
<artificial>:(.text.startup+0x30c): undefined reference to `gy'
<artificial>:(.text.startup+0x310): undefined reference to `gy'
<artificial>:(.text.startup+0x328): undefined reference to `gz'
<artificial>:(.text.startup+0x32c): undefined reference to `gz'

Main.cpp, Sensor.cpp and Sensor.h files are in the same directory. I am using PlatformIO to build and deploy the code on an Arduino Uno and the platformio.ini file content is the following,

[env:uno]
platform = atmelavr
board = uno
framework = arduino
lib_deps = jrowberg/I2Cdevlib-MPU6050@0.0.0-alpha+sha.fbde122cc5

I am wondering what is causing the linking errors.

Quazi Irfan
  • 156
  • 1
  • 10

1 Answers1

3

The failing is not with your code. The failing is with the MPU6050_6Axis_MotionApps20.h library. It erroneously has code in the header rather than in a separate CPP file.

You have done everything right. The author of that library could do well in taking a leaf out of your book.

To get it working you will have to move the code out of the header file into the .cpp file - or move it to reside inside the class definition and make it inline.

Majenko
  • 105,851
  • 5
  • 82
  • 139