0

I am trying to pass some function for testing, into a main() node as shown below. However, I am getting the following non static member reference must be relative to a specific object. I was doing a good amount of research about this probelm, like for example I found this that had a similar problem, also this is useful that was explaining how to access and understand the relationship with the "parent" instance. I applied what was advised here and thanks to passing madgwick::MADGWICK_reader obj(std::string file); on the main I was partially able to access to the class MADGWICK_reader that has the function void filter_function(const sensor_msgs::Imu &msg); that I am trying to access from main but still something is not totally correct.

I know that it is not correct to make the members static by simply adding the "static" keyword, and that I need to define them as well, and that is the reason why the function is specifically set as void filter_function(const sensor_msgs::Imu &msg); I am passing ampersend & on purpose to pass it by reference to main but it seems that the function is never received.

This is the madgwick_filter.h, notice the void filter_function(const sensor_msgs::Imu &msg); function that is having the issue in the main:

namespace madgwick
{
    using timestamp_t = uint64_t;
    using timestampToDouble_t = double;

    struct IMU_MADGWICK_DATA
    {
        double magz;
        double magy;
        double magx;
        float accelz;
        float accelx;
        float accely;
        unsigned long timestamp;
        double phi;   // orientation
        double psi;   // orientation
        double theta; // orientation
        double gyrox; // angular velocity x
        double gyroy; // angular velocity y
        double gyroz; // angular velocity z
    };


    class Madgwick
    {
    public:
      Madgwick();

    };

    class MADGWICK_reader
    {
    public:
        MADGWICK_reader(std::string filename);
        bool nextLine();
        bool nextLineWithSupport();

        IMU_MADGWICK_DATA madgwick_data;

        sensor_msgs::Imu imuMadgwickMsg;
        sensor_msgs::MagneticField magMedgwickMsg;

        geometry_msgs::QuaternionStamped q;
        geometry_msgs::Vector3Stamped v;
        geometry_msgs::TransformStamped q_trans;
        float sampleFreq;
        double beta;
        double q0=1.0, q1=0.0, q2=0.0, q3=0.0;
        std_msgs::Header header;
        float ax, ay, az, gx, gy, gz;
        ros::Duration dtime;
        float dt;

        float invSqrt();
        void qua2Euler(geometry_msgs::QuaternionStamped);
        void madgwickIMU(float gx, float gy, float gz, float ax, float ay, float az);
        void filter_function(const sensor_msgs::Imu &msg);

    private:
        io::CSVReader<13> madg_imu_reader;
        unsigned int imuMadgNum;
        unsigned int magMadgNum;
        void packMadgMagMsg();
        void pack_Imu_Madgwick_Msg();
        void pack_Mag_Madgwick_Msg();
    };
}

madgwick_filter.cpp

namespace madgwick
{
    Madgwick::Madgwick()
    {

    }

    MADGWICK_reader::MADGWICK_reader(std::string filename):
        madg_imu_reader(filename)
    {
        // operations ...
    }

    void MADGWICK_reader::filter_function(const sensor_msgs::Imu &msg)
    {
        timestampToDouble_t currentTime = (madgwick_data.timestamp)/1e6;
        ros::Time stamp(currentTime);
        header = msg.header;
        ax = float(msg.linear_acceleration.x);
        ay = float(msg.linear_acceleration.y);
        az = float(msg.linear_acceleration.z);

        // more operations ...
    }
}

and finally this is the madgwick_filter_node.cpp

#include "imu_filter_madgwick/madgwick_filter.h"
#include <iostream>

    int main(int argc, char** argv)
    {
        ros::init(argc, argv, "madgwick_filter_node");
        madgwick::MADGWICK_reader reader(std::string filename);

        ros::NodeHandle n;
        ros::Publisher pub1 = n.advertise<geometry_msgs::QuaternionStamped>("quaternion", 1);
        ros::Publisher pub2 = n.advertise<geometry_msgs::Vector3Stamped>("ypr", 1);

        tf::TransformBroadcaster q_brodecaster;

        madgwick::MADGWICK_reader obj(std::string file);

        ros::Subscriber sub = n.subscribe("imu0", 10, obj.filter_function); // <-- Error Here

        ros::spin();
    }

Can anyone point to the right direction or provide an explanation on why it is still not possible to access to the function contained in the class from the main? Thanks for shedding light on this.

Emanuele
  • 2,194
  • 6
  • 32
  • 71
  • Usually you cannot pass a member function as a callback because you need an instance of that class in order to call it. I don't have any experience with ros here, but I'm guessing that's your issue. You may be able to pass a lambda that captures your instance like so: `[&obj](){return obj.filter_function();` – AndyG May 22 '19 at 19:52
  • 2
    Please post the declaration of `ross::NodeHandle::subscribe`. Member function pointers cannot be converted to ordinary function pointers. – Quimby May 22 '19 at 19:53
  • Remember the hidden `this`. You must somehow pass an instance into `subscribe`. `obj.filter_function` won't do this for you. see if a lambda expression or `std::bind` can help. – user4581301 May 22 '19 at 19:53
  • I think you can pass member functions using bind statement so it should be like "auto f = std::bind(&madgwick::MADGWICK_reader,obj,filter_function" and then passing f to n.subscribe. – PapaDiHatti May 22 '19 at 19:54
  • For those suggesting `std::bind`, it's all but deprecated. Use a lambda instead. It reads clearer. – AndyG May 22 '19 at 19:54
  • I disagree with lambda being a an easier read than `std::bind`, but lambda brings several indisputable advantages (faster being a big one) over `std::bind` to the table, so prefer lambda. – user4581301 May 22 '19 at 19:57
  • Thanks all for the time in reading the question. Can you please provide the answer you are suggesting with the part that I should edit on the `main` using lambda function? – Emanuele May 22 '19 at 19:58
  • We can only do that if you answer Quimby's question. – Paul Sanders May 22 '19 at 20:01

1 Answers1

1

Since you have not provided declaration of subscribe but it seems your problem is related to passing class member functions to other function so below solution provide two ways of achieving that one by lambdas and other by bind.

#include <iostream>
#include <functional>
class Test{
    public:
    void fun(int x)
    {
        std::cout<<"I am having fun in Test with number "<<x<<std::endl;
    }
};
void sampleFunction(std::function<void(int)> sf,int x)
{
    sf(x);
}
int main()
{
    Test obj;
    auto objf = std::bind(&Test::fun,&obj,std::placeholders::_1);
    sampleFunction(objf,5);

    auto lf = [&obj](int y) { return obj.fun(y); };
    sampleFunction(lf,6);
    return 0;
}
PapaDiHatti
  • 1,841
  • 19
  • 26