Problem with multiple files project

Hello everybody!
I just started a new project. This is the first time I’m trying to split my project in several files (but I have already used libraries). I really don’t understand what’s going wrong, because all I do is things I did in my pure C++ programms. I already read a lot on the internet, but nothing was really usefull, so I hope you will be able to find what I’m doing wrong. Finally, I know this is possible to create my own library, but that doesn’t solve my problems…

I’ll begin with my first problem. Here is my code (3 files, 1 class and the .ino file):

/*
 * File: Motors.h
 */

#ifndef MOTORS_H
#define MOTORS_H

#include <Servo.h>

#define STOPVALUE 0

class Motors {
public:
    Motors();
    
    void initAll(int Npin, int Spin, int Wpin, int Epin);
    void StopAll();
    void setN(int usec);
    void setS(int usec);
    void setW(int usec);
    void setE(int usec);
    
private:
    Servo NESC;
    Servo SESC;
    Servo WESC;
    Servo EESC;
};

#endif // MOTORS_H
/*
 * File: Motors.cpp
 */

#include "Motors.h"

Motors::Motors(){
  Servo NESC;
  Servo SESC;
  Servo WESC;
  Servo EESC;
}


void Motors::initAll(int Npin, int Spin, int Wpin, int Epin){
  NESC.attach(Npin);
  SESC.attach(Spin);
  WESC.attach(Wpin);
  EESC.attach(Epin);
}

void Motors::StopAll(){
  setN(STOPVALUE);
  setS(STOPVALUE);
  setW(STOPVALUE);
  setE(STOPVALUE);
}

void Motors::setN(int usec){
  NESC.writeMicroseconds(usec);
}

void Motors::setS(int usec){
  SESC.writeMicroseconds(usec);
}

void Motors::setW(int usec){
  WESC.writeMicroseconds(usec);
}

void Motors::setE(int usec){
  EESC.writeMicroseconds(usec);
}
/*
 * File: QuadCopter.ino
 */

#include "Motors.h"

#define NPIN 3
#define SPIN 5
#define WPIN 7
#define EPIN 9

void setup() {
  //Declare the propellers
  Motors prop;
  prop.initAll(NPIN, SPIN, WPIN, EPIN);
}

void loop() {
  
}

When I verifiy my project with the arduino IDE, here are my errors:

In file included from Motors.cpp:5:
Motors.h:24: error: 'Servo' does not name a type
Motors.h:25: error: 'Servo' does not name a type
Motors.h:26: error: 'Servo' does not name a type
Motors.h:27: error: 'Servo' does not name a type
Motors.cpp: In constructor 'Motors::Motors()':
Motors.cpp:8: error: 'Servo' was not declared in this scope
Motors.cpp:8: error: expected `;' before 'NESC'
Motors.cpp:9: error: expected `;' before 'SESC'
Motors.cpp:10: error: expected `;' before 'WESC'
Motors.cpp:11: error: expected `;' before 'EESC'
Motors.cpp: In member function 'void Motors::initAll(int, int, int, int)':
Motors.cpp:16: error: 'NESC' was not declared in this scope
Motors.cpp:17: error: 'SESC' was not declared in this scope
Motors.cpp:18: error: 'WESC' was not declared in this scope
Motors.cpp:19: error: 'EESC' was not declared in this scope
Motors.cpp: In member function 'void Motors::setN(int)':
Motors.cpp:30: error: 'NESC' was not declared in this scope
Motors.cpp: In member function 'void Motors::setS(int)':
Motors.cpp:34: error: 'SESC' was not declared in this scope
Motors.cpp: In member function 'void Motors::setW(int)':
Motors.cpp:38: error: 'WESC' was not declared in this scope
Motors.cpp: In member function 'void Motors::setE(int)':
Motors.cpp:42: error: 'EESC' was not declared in this scope

The first ones really intrigue me… Does anybody know where this come from ?
I’ll also add I’m using the 1.0.4 version of the IDE, for a Duemilanove Board with ATmega328 chip.

Thanks in advance !

You are trying to hide the use of the Servo library from the sketch. That is simply not possible using the IDE, and is a well documented situation.

Ok, sorry, I had never heard about it before.
If I change my IDE (eclipse for example), will I have the same problem?

Your sketch .ino file needs to explicitly refer to each library used by the sketch (including all libraries which are required indirectly by other libraries), by #including the relevant .h file.

This is not obvious, not documented anywhere that I know of, not conventional C++ behaviour and not reported in any intelligible way if you fail to do it correctly, but is required due to the mucking about that the Arduino IDE does with your code before it invokes the compiler.

Ok, thanks a lot, this worked! I don’t really understand why I have to include twice, but it’s working. So, my first problem is solved now.

But I have a second one, maybe linked to the first one, maybe worse… I have an MPU6050 gyro-accelerometer. I found a link in the playground MPU-6050 6-axis accelerometer/gyroscope | I2C Device Library. So I downloaded the files and the examples. As I saw in the readme, I didn’t create a library with all these files, I just included them in the same folder as my project. Then I opened the example (not the one with the raw values, the one with the use of the DMP) and saw that it was a little bit long to have the final measurement. So I decided to create a new class called Imu, which would have only two functions, one for the initialisation and another one for the measure (in order to have a clean main sketch).
But it doesn’t work as I expected… I have a lot of errors and I don’t know where they come from. Again, I did only things I would have done with a pure C++ project, but it doesn’t work here.

I attached my project to this post and I post here the list of my erros:

QuadCopter3.cpp.o: In function `MPU6050::dmpGetAccel(long*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:577: multiple definition of `MPU6050::dmpGetAccel(long*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:577: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetAccel(int*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:585: multiple definition of `MPU6050::dmpGetAccel(int*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:585: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetAccel(VectorInt16*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:593: multiple definition of `MPU6050::dmpGetAccel(VectorInt16*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:593: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetQuaternion(long*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:601: multiple definition of `MPU6050::dmpGetQuaternion(long*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:601: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetQuaternion(int*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:610: multiple definition of `MPU6050::dmpGetQuaternion(int*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:610: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetQuaternion(Quaternion*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:619: multiple definition of `MPU6050::dmpGetQuaternion(Quaternion*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:619: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetGyro(long*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:634: multiple definition of `MPU6050::dmpGetGyro(long*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:634: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetGyro(int*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:642: multiple definition of `MPU6050::dmpGetGyro(int*, unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:642: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetLinearAccel(VectorInt16*, VectorInt16*, VectorFloat*)':
/MPU6050_6Axis_MotionApps20.h:652: multiple definition of `MPU6050::dmpGetLinearAccel(VectorInt16*, VectorInt16*, VectorFloat*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:652: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetGravity(VectorFloat*, Quaternion*)':
/MPU6050_6Axis_MotionApps20.h:672: multiple definition of `MPU6050::dmpGetGravity(VectorFloat*, Quaternion*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:672: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpProcessFIFOPacket(unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:711: multiple definition of `MPU6050::dmpProcessFIFOPacket(unsigned char const*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:711: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetFIFOPacketSize()':
/MPU6050_6Axis_MotionApps20.h:737: multiple definition of `MPU6050::dmpGetFIFOPacketSize()'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:737: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpReadAndProcessFIFOPacket(unsigned char, unsigned char*)':
/MPU6050_6Axis_MotionApps20.h:712: multiple definition of `MPU6050::dmpReadAndProcessFIFOPacket(unsigned char, unsigned char*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:712: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetYawPitchRoll(float*, Quaternion*, VectorFloat*)':
/MPU6050_6Axis_MotionApps20.h:689: multiple definition of `MPU6050::dmpGetYawPitchRoll(float*, Quaternion*, VectorFloat*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:689: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetEuler(float*, Quaternion*)':
/MPU6050_6Axis_MotionApps20.h:683: multiple definition of `MPU6050::dmpGetEuler(float*, Quaternion*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:683: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpGetLinearAccelInWorld(VectorInt16*, VectorInt16*, Quaternion*)':
/MPU6050_6Axis_MotionApps20.h:660: multiple definition of `MPU6050::dmpGetLinearAccelInWorld(VectorInt16*, VectorInt16*, Quaternion*)'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:660: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpPacketAvailable()':
/MPU6050_6Axis_MotionApps20.h:550: multiple definition of `MPU6050::dmpPacketAvailable()'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:550: first defined here
QuadCopter3.cpp.o: In function `MPU6050::dmpInitialize()':
/MPU6050_6Axis_MotionApps20.h:325: multiple definition of `MPU6050::dmpInitialize()'
Imu.cpp.o:/MPU6050_6Axis_MotionApps20.h:325: first defined here

Do you know what is the problem? Or maybe do you know a better way to be able to put all this stuff in only two or three functions?

Thanks in advance.

QuadCopter3.zip (68.2 KB)

I don't really understand why I have to include twice

The IDE copies files to a build directory. It copies files from the sketch directory and from the two libraries directories. Which files? All the files in the sketch directory and all the files in directories that are referenced in the sketch.

So, it copied your sketch and the files in the Motors library (Motors.h and Motors.cpp). Since the sketch didn't reference Servo.h, the Servo.h and Servo.cpp files were not copied. Therefore, the Servo.h file could not be opened. Therefore, the Servo class was not defined.

Ok, great, I understand now!

But unfortunately this doesn't solve my second problem...

Does anyone have an idea, because I really don't know what to try now... ?

Don' t put implementations in a .h file, put them in a .cpp file.

They are being compiled twice, hence the error message.

eg,

uint8_t MPU6050::dmpGetAccel(int32_t *data, const uint8_t* packet) {
    // TODO: accommodate different arrangements of sent data (ONLY default supported now)
    if (packet == 0) packet = dmpPacketBuffer;
    data[0] = ((packet[28] << 24) + (packet[29] << 16) + (packet[30] << 8) + packet[31]);
    data[1] = ((packet[32] << 24) + (packet[33] << 16) + (packet[34] << 8) + packet[35]);
    data[2] = ((packet[36] << 24) + (packet[37] << 16) + (packet[38] << 8) + packet[39]);
    return 0;
}

Put that into a .cpp file, along with the other ones.

Ok, thanks a lot, it worked!

Finally, if I was using another IDE (like Eclipse), would I have had all those problems ? (Because it is only compilation problems in fact...)

Finally, if I was using another IDE (like Eclipse), would I have had all those problems ?

All? No. Some? Oh, yes.

Ok, I see :wink:

Thanks a lot for everything !

Your problems with multiple definitions because you put code in a .h file would be likely to happen under any development environment.

Hi there…

I have similar problem…

My project is quite big (~1k lines), so I need to split it for a few modules/files…

In main sketch I have lcd declared:

LiquidCrystal lcd(12, 11, 6, 5, 4, 3);

also some functions using lcd… it works well…

I try to have a piece of code stored in another file, have empty logbook.h and logbook.cpp as follows:

#include <LiquidCrystal.h>

void logbook() {
lcd.clear();
}

It doesn’t work :frowning:

logbook.cpp: In function ‘void logbook()’:
logbook.cpp:5: error: ‘lcd’ was not declared in this scope

If I try to declare lcd again in logbook.cpp the error is:

it will not work with multiple definitions

How to simply split code?

How to have

How to simply split code?

Name them .ino, so that the IDE sews them altogether. Do not name them .cpp files.

What you are doing is creating a library, and that's a completely different process.

Thanks PaulS :slight_smile:

Hi minimoy, could you please help i am trying to do exactly the thing you are doing and somehow i am stuck for hours with this error, i already checked and i have no implementations on my .h files.

what exactly did you change that helped you solve the error?

I tried this solution and it works with the Arduino IDE but when I use Stino with Sublime text 2, the same “multiple definition” errors appear again. Do you have any idea why?

when I use Stino with Sublime text 2, the same "multiple definition" errors appear again. Do you have any idea why?

No, but it isn't an Arduino problem.