limon_spb
@limon_spb

Arduino + MPU6050 (библиотека i2cdevlib). Что делать с ошибками «Multiple definition of MPU6050::XXXXXX»?

Здравствуйте, уважаемые знатоки!

Использую i2cdevlib, чтобы упростить "общение" с гироскопом и акселерометром MPU6050.
Их пример скомпилировался и работает без особых проблем:
Я просто скопировал нужные файлы в папку к проекту, сам проект взял из примеров и все заработало.
Вот проект
Сам датчик, очевидно, не нужен, чтобы собрать и залить в Ардуину.

А вот обернуть всю работу с MPU6050 в отдельный класс, который скрыл бы всю инициализацию и т.п. не получилось.
Для этого создал Sensor.cpp и Sensor.h. Из Sensor.h подключил заголовки для работы с MPU6050, как это было раньше сделано в основном проекте.
В основном проекте убрал все, заинклудил там Sensor.h

И понеслись ошибки:
testMPU.cpp.o: In function `MPU6050::dmpGetAccel(long*, unsigned char const*)':
/MPU6050_6Axis_MotionApps20.h:533: multiple definition of `MPU6050::dmpGetAccel(long*, unsigned char const*)'
sensor.cpp.o:/MPU6050_6Axis_MotionApps20.h:533: first defined here


Код файла проекта:
//всякие дефайны

#include "Wire.h"
#include "sensor.h"


void setup() {
  Sensor::getInstance().init();
}

void loop() {
  float y,p,r;
  Sensor::getInstance().getYpr(y,p,r);
}

Код sensor.h:
#ifndef SENSOR_H
#define SENSOR_H

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

class Sensor{
public:
  static Sensor & getInstance(){
    static Sensor instance;
    return instance;
  }
  
  bool init();
  
  bool getYpr(float & y, float & p, float r);
  
protected:
  MPU6050 _mpu;
..............


Вот сам несобирающийся проект вместе с файлами i2cdevlib

Спасибо всем, кто дочитал до конца.
  • Вопрос задан
  • 8662 просмотра
Решения вопроса 1
@osnwt
Проблема - в некорректном написании библиотеки.

По определению заголовочные файлы должны включать только описания функций и переменных, а cpp-файлы - их определения (реализацию). Включаемый файл MPU6050_6Axis_MotionApps20.h не является на самом деле заголовочным, он содержит реализацию функций, которая должна быть только в одном файле проекта. При включении же его дважды все функции будут скомпилированы в каждый объектный модуль, что вызовет ошибку на стадии линковки.

Можно даже предположить, почему было сделано именно так: данный файл должен иметь тип cpp. Однако, в силу ограничений Arduino ВСЕ cpp файлы из каталога будут скомпилированы автоматически при том, что нужен лишь один из них (6Axis или 9Axis). Потому их сделали *.h, не учтя возможность повторного включения. Это можно было сделать корректно, но автор не стал утруждать себя такими "мелочами".

Без правки библиотеки эту проблему не решить. Для этого надо разнести описание класса библиотеки в выбранном варианте в *.h, а его определение - в *.cpp. И неким образом учесть то, какой из вариантов при этом следует собирать. В нормальной среде разработки было бы достаточно добавить в проект лишь один (нужный) *.cpp с реализацией того или иного варианта. В стандартой среде Arduino этого сделать нельзя (оба cpp будут скомпилированы), и надо извращаться, например, разделив библиотеку на две части или по другому. В результате из-за дурацких ограничений среды вместо решения своей задачи приходится думать, как выкрутиться. Увы.

PS. Мое личное мнение об Arduino: признавая достоинства системы в плане популяризации микроконтроллеров в "массах", реализация ее, на мой взгляд, никуда не годная и прививающая навыки плохого стиля программирования. Простейшим примером этого является постоянно повторяемое во всех официальных примерах int led = 13, когда среда уже давным давно определяет его как LED_BUILTIN, всегда правильный для ВЫБРАННОЙ платы. Из таких "мелочей" складывается то, что люди пишут интересные, в целом, вещи, но делают это как попало, что не может не печалить. И сама среда прививает им такой стиль.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы