Передача ссылки на оборудование между методами в пользовательском классе

library accelerometer class magnetometer object-oriented

Я новичок в C++/Arduino и впервые пытаюсь создать пользовательскую библиотеку. Я создал модуль с именем CDSensors.cpp, который имеет два метода: SetupSensor и ReadSensors. Датчик представляет собой акселерометр/магнитометр SparkFun.

При наличии ошибок в настройках датчик возвращает все нули для компаса и акселерометра. Если между методами SetupSensor и ReadSensor нет указателя или другой связи, датчик возвращает все нули, как если бы он не был настроен.

Поэтому я пытаюсь передать ссылку на библиотеку датчиков между методами, как показано с объектом Limu в приведенном ниже коде. Теперь я получаю магнитные данные, но акселерометр возвращает все нули, поэтому что-то в моих ссылках на объекты мешает настройке датчика? (акселерометр нормально работает в демонстрационном коде SparkFun, на котором основан мой код).

Main.ino

#include <CDSensors.h>
#include <Wire.h>
#include <SPI.h>
#include <SparkFunMPU9250-DMP.h>

CDSensors* LSensors = &CDSensors     (0);
CDSerialPrint* LSerialPrint = &CDSerialPrint (0);
MPU9250_DMP Limu = MPU9250_DMP ();
unsigned long LTimeNow = 0;

struct meas {
  int BUx;
  int acc_x
};

struct meas r;

void setup() {
  LSensors->SetupSensors (Limu);
}

void loop() {
  LSensors->ReadSensors  (Limu, LTimeNow, r.BUx, r.acc_x);
  Serial.print((int) (r.BUx) );
  Serial.print((int) (r.acc_x) );
}

CDSensors.h

#ifndef CDSensors_h_h
#define CDSensors_h
#include <Wire.h>
#include <SPI.h>
#include <SparkFunMPU9250-DMP.h>

class CDSensors {
  public:
    CDSensors(int);
    static void SetupSensors(MPU9250_DMP *imu);
    void ReadSensors (MPU9250_DMP *imu, unsigned long& TimeNow, int&     BUx,int& BUy,int& BUz,int& acc_x,int& acc_y,int& acc_z,int& a0,int& a1,int& a2,int& a3 );
  private:
    int value;
};
#endif

CDSensors.cpp

#include <Wire.h>
#include <SPI.h>
#include <SparkFunMPU9250-DMP.h>
#include "CDSensors.h"

//MPU9250_DMP imu;
boolean       MPU9250_found = false;
unsigned long TimeNow = 0;
CDSensors::CDSensors(int givenValue) {
  value = givenValue;
}

static void CDSensors::SetupSensors(MPU9250_DMP imu) {
  if (imu.begin() != INV_SUCCESS) {
    while (1) {
      Serial.println("No MPU-9250 found, Check connections");
      delay(5000);
    }
  }
  imu.setSensors(INV_XYZ_ACCEL | INV_XYZ_GYRO | INV_XYZ_COMPASS);
  imu.setGyroFSR(2000);
  imu.setAccelFSR(2);
  imu.setLPF(188);
  imu.setSampleRate(100);
  imu.setCompassSampleRate(100);
}

void CDSensors::ReadSensors(MPU9250_DMP imu, unsigned long& TimeNow, int& BUx, int& acc_x) {
  TimeNow = millis();
  if (imu.dataReady()) {
    imu.update(UPDATE_ACCEL | UPDATE_GYRO | UPDATE_COMPASS);
  }
  BUx = imu.calcMag(imu.mx);
  acc_x = imu.calcAccel(imu.ax);
}

, 👍0

Обсуждение

Есть ли причина, по которой вы определяете MPU9250_DMP вне вашего класса и в вашем основном скетче? Если вы объявите его внутри класса как переменную-член, вы можете отказаться от обработки ссылок, @chrisl

Попробуйте передать параметр imu по ссылке (вместо копирования), т. е. MPU9250_DMP& imu, в функции-члены SetupSensors и ReadSensors., @Mikael Patel

@ChrisL Когда он был определен только в классе CDSensors, датчик возвращал все нули. Проверил локальным сериалпринтом, полагаю как-то теряется связь между настройками и чтением данных., @Hamish_Fernsby

@Nisse извините, исправил отступы и опечатки, я думаю, ваш комментарий решен., @Hamish_Fernsby

Как вы определяете это в классе? Вы выполнили его конструктор? Если нет, то проблема могла быть в нем, @chrisl

Можете ли вы опубликовать CDSensors.h? Я не могу понять CDSensors* LSensors = &CDSensors (0); CDSerialPrint* LSerialPrint = &CDSerialPrint (0); Как говорится в предупреждении, вы берете адрес временного объекта, который перестает существовать в конце этой строки., @Nick Gammon

Почему вы вообще используете классы? Датчиков будет много? Если это так, то делать функцию-член статической не имеет смысла., @Nick Gammon

@Mikael, новичок в указателях, я попробовал MPU9250_DMP * imu и MPU9250_DMP * imu В любом случае я получаю эту ошибку - неизвестное преобразование для аргумента 1 из «MPU9250_DMP» в «MPU9250_DMP & imu дает ту же проблему с возвратом нулей вспомогательного датчика., @Hamish_Fernsby

@Nick, почему классы - причина для перемещения этого фрагмента кода в отдельный блок .cpp заключается в том, что программа собирается стать намного сложнее, много математики и GPRS-связи, поэтому настройка / чтение датчика казались логичным куском чтобы выйти из main.ino Я предполагаю, что отдельный блок .cpp требует определения класса?, @Hamish_Fernsby

Нет, совсем нет., @Nick Gammon

И если вы изменили код, пожалуйста, опубликуйте измененный код. Мы не можем отлаживать код, который не видим., @Nick Gammon

Измените «static void SetupSensors (MPU9250_DMP * imu)» на «static void SetupSensors (MPU9250_DMP & imu)» как в исходном, так и в заголовочном файле. Внесите те же изменения в «ReadSensors». BW, почему вы используете static для SetupSensors., @Mikael Patel


1 ответ


1

Я не думаю, что вы правильно создаете экземпляры этих классов. Вместо:

CDSensors*     LSensors      = &CDSensors     (0);
CDSerialPrint* LSerialPrint  = &CDSerialPrint (0);            
MPU9250_DMP   Limu = MPU9250_DMP ();

Как насчет:

CDSensors LSensors (0);
CDSerialPrint LSerialPrint (0);
MPU9250_DMP Limu;

Я не могу заставить ваш код скомпилироваться, но то, что я предлагаю, выглядит намного проще.


Ваше намерение здесь:

if (imu.begin() != INV_SUCCESS)
  imu.setSensors(INV_XYZ_ACCEL | INV_XYZ_GYRO | INV_XYZ_COMPASS); 
  imu.setGyroFSR(2000); 
  imu.setAccelFSR(2); 
  imu.setLPF(188); 
  imu.setSampleRate(100); 
  imu.setCompassSampleRate(100); 

.. быть на самом деле:

if (imu.begin() != INV_SUCCESS)
  {
  imu.setSensors(INV_XYZ_ACCEL | INV_XYZ_GYRO | INV_XYZ_COMPASS); 
  imu.setGyroFSR(2000); 
  imu.setAccelFSR(2); 
  imu.setLPF(188); 
  imu.setSampleRate(100); 
  imu.setCompassSampleRate(100);
  }

На это указывает отступ.


если я правильно понял, класс создается при запуске с помощью

       CDSensors* LSensors = &CDSensors (0); 

и затем сохраняется.

LSensors — это постоянный указатель, а CDSensors (0) — это временный объект, созданный для выполнения присваивания. Например:

int foo = 2 + 3;

Теперь компилятор вычисляет 2 + 3 (давая 5), присваивает это значение foo, а затем отбрасывает временно вычисленное 5, используемое для выполнения присваивания.

В вашем случае CDSensors (0) вызывает конструктор для CDSensors, создавая временный объект. Затем "&" оператор берет свой адрес (где-то в стеке, я думаю). Этот адрес копируется в LSensors. Затем объект уничтожается, потому что его время жизни закончилось. Компилятор даже предупреждает вас об этом:

 CDSensors*     LSensors      = &CDSensors     (0);
                                                 ^
sketch_may07a:5: error: taking address of temporary [-fpermissive]

Это означает, что указатель теперь недействителен, поскольку базовый объект (на который он указывает) теперь отброшен.


Я даже видел, как люди довольно часто делают что-то подобное:

     CDSensors LSensors = CDSensors (0);

Это не так уж плохо, потому что указатели не задействованы, но все равно нужно создать временный экземпляр класса, затем копировать его в LSensors и отбросить исходный экземпляр.

Вот как создать новый экземпляр класса:

 CDSensors LSensors (0);   // фактический класс, а не указатель

Или, если вам нужен указатель:

 CDSensors * pLSensors;  // указатель на класс (изначально NULL)

Затем в setup вы создаете экземпляр:

pLSensors = new CDSensors (0);
,

Спасибо, Ник, я попробовал этот вариант, он также компилируется нормально, но все еще имеет ту же проблему с вспомогательным датчиком accl, возвращающим нули., @Hamish_Fernsby

Добавьте несколько отладочных отпечатков, не мучайтесь добавлением указателей в надежде, что это исправит ситуацию., @Nick Gammon

Также см. мой измененный ответ., @Nick Gammon

Re if (imu.begin() != INV_SUCCESS) извините опечатка в коде вверху, которая теперь исправлена., @Hamish_Fernsby

Я задавался вопросом, может ли это быть связано с конструкторами, но, если я правильно понял, класс создается при запуске с помощью CDSensors* LSensors = &CDSensors (0); а потом настойчиво. (в отличие от того, к чему я привык в Delphi, где вы можете везде набирать create/destroy)., @Hamish_Fernsby

Указатели - правильно - я полагаю, что добавление указателей экономит ресурсы, но вряд ли исправит ошибку времени выполнения., @Hamish_Fernsby

Смотрите измененный ответ., @Nick Gammon

Третья часть вводит в заблуждение. Говорить о "недопустимом указателе" нет смысла, так как сам код просто недействителен: язык не позволяет применять встроенный & к временному. Это не компилируется. Я не знаю, почему ОП продолжает угадывать, является ли объект постоянным или нет. Нет смысла в том, что когда код просто не компилируется., @AnT

Четвертая часть также вводит в заблуждение. Даже в старом «классическом» C++ синтаксис инициализации копированием немедленно интерпретируется как прямая инициализация, когда типы в левой и правой частях совпадают. Временный объект не создается, копирование не выполняется. Аргументы конструктора немедленно передаются объекту LHS. Синтаксис инициализации копирования в этом случае является повторяющимся, громоздким и ненужным, но он не страдает от неэффективности, которую вы описываете в своем ответе. Он полностью эквивалентен «короткой» версии., @AnT

Я бы добавил к комментарию AnT таким образом, зачем передавать Limu в качестве параметра обеим функциям, когда сконструированный объект уже является глобальным. Просто используйте Limu и удалите параметр в обоих методах. Если бы вы действительно хотели быть "OO", вы бы передали "Limu" конструктору. Так как вы передаете int, который выглядит так, как будто никогда не используется, чего я не понимаю, если код отсутствует или не планируется на потом., @Kelly S. French