Robotics StackExchange | Archived questions

Ros2, message_filters::Synchronizer callback not called

Hello,

I have a node that need to process two different images: one is the image from the camera, the other one is the depth map of the image (extrapolated through a neural network). The two images are published by 2 different topics, one just after the other (minimal difference).

This is the implementation of the node, relevant parts only:

node.hpp:

using ImageMsg = sensor_msgs::msg::Image;

class MonocularSlamNode : public rclcpp::Node
{

public:

    MonocularSlamNode(ORB_SLAM2::System* pSLAM, const string &strVocFile, const string &strSettingsFile, const string &strSensor);
~MonocularSlamNode();

message_filters::Subscriber<ImageMsg> image_sub_;
message_filters::Subscriber<ImageMsg> depth_sub_;              

private: 

    void GrabRGBD(const sensor_msgs::msg::Image::SharedPtr msgIm, const sensor_msgs::msg::Image::SharedPtr msgD);

node.cpp:

MonocularSlamNode::MonocularSlamNode(ORB_SLAM2::System* pSLAM, const string &strVocFile, const string &strSettingsFile, const string &strSensor)
:   Node("orbslam"),
m_SLAM(pSLAM)
{

image_sub_.subscribe(this, "camera");
depth_sub_.subscribe(this, "depth_map");

typedef message_filters::sync_policies::ApproximateTime<ImageMsg, ImageMsg> approximate_policy;
message_filters::Synchronizer<approximate_policy>syncApproximate(approximate_policy(10), image_sub_, depth_sub_);
syncApproximate.setMaxIntervalDuration(rclcpp::Duration(100,0)); 
syncApproximate.registerCallback(&MonocularSlamNode::GrabRGBD,this);
}

void MonocularSlamNode::GrabRGBD(const ImageMsg::SharedPtr msgIm, const ImageMsg::SharedPtr msgD)
{
    cout << "I'm here" << endl;
}

The problem is, the callback is never executed.

The two topics are published correctly, and if I use ros2 topic info I see they are both correctly subscribed - and if I use echo, I see their timestamps differ only by a fraction of a second (so by using the large value I'm using to test, 100, in setMaxIntervalDuration should work? Before I tried smaller values, like 1 and 3 seconds, but nothing works).

Just for reference, this is how the two topics are created in my node.py file:

    self.pub_image_raw = self.node.create_publisher(Image, 'camera', 1)
    self.pub_depth_map = self.node.create_publisher(Image, 'depth_map', 1)

and then published:

        msg = self.bridge.cv2_to_imgmsg(numpy.array(frame), 'bgr8')
        msg.header.frame_id = self.tf_drone
        msg.header.stamp = self.node.get_clock().now().to_msg()
        self.pub_image_raw.publish(msg)

        msg = self.bridge.cv2_to_imgmsg(numpy.array(depth_map), 'mono8')
        msg.header.frame_id = self.tf_drone
        msg.header.stamp = self.node.get_clock().now().to_msg()
        self.pub_depth_map.publish(msg)

Both of them work fine, as I can visualize the camera image and the depth map as well.

Can someone help me understand why my callback is never called? Thank you!

EDIT: I also tried to rewrite my node.py as follows:

        timestamp = self.node.get_clock().now().to_msg()

        # Publish opencv frame using CV bridge
        msg.header.frame_id = self.tf_drone
        msg.header.stamp = timestamp
        self.pub_image_raw.publish(msg)

        msg = self.bridge.cv2_to_imgmsg(numpy.array(depth_map), 'mono8')
        msg.header.frame_id = self.tf_drone
        msg.header.stamp = timestamp
        self.pub_depth_map.publish(msg)

So that the images published by the 2 topics have exactly the same timestamp. Hence, I changed the implementation of the node as follows:

image_sub_.subscribe(this, "camera");
depth_sub_.subscribe(this, "depth_map");

typedef message_filters::sync_policies::ExactTime<ImageMsg, ImageMsg> exact_policy;
message_filters::Synchronizer<exact_policy>syncExact(exact_policy(1000), image_sub_, depth_sub_);
syncExact.registerCallback(&MonocularSlamNode::GrabRGBD,this);

Nevertheless, when I run it, it never enters the callback. How is this possible? The two messages have the exact same timestamp...

Asked by damiano on 2022-11-28 01:34:55 UTC

Comments

Answers

Can someone help me understand why my callback is never called?

You have this in your ctor (I've simplified it a bit to improve readability):

MonocularSlamNode::MonocularSlamNode(...) ...
{

    image_sub_.subscribe(this, "camera");
    depth_sub_.subscribe(this, "depth_map");

    typedef message_filters::sync_policies::ApproximateTime<...> approximate_policy;
    message_filters::Synchronizer<approximate_policy>syncApproximate(...);
    ...
}

The underscore suffix on image_sub_ and depth_sub_ imply they're class members, so they are stored in a scope which 'outlives' the ctor.

But the syncApproximate object appears to be an object local to the ctor.

In other words: as soon as the ctor ends, your syncApproximate is destructed.

No syncApproximate -> no callbacks.

You'll want/need to make syncApproximate a class member as well.

PS: this exact question has been posted quite a few times to ROS Answers. I know the search isn't very good, so I'd recommend using Google. Append site:answers.ros.org to your search query. With this query I get lots of results with answers that deal with the same problem. One example would be #q370858 (which I apparently also answered).

Asked by gvdhoorn on 2022-11-28 03:34:27 UTC

Comments

Thank you, that makes perfectly sense!

Finally after some tribulation I implemented it like this:

node.hpp:

using exact_policy = message_filters::sync_policies::ExactTime<ImageMsg,ImageMsg>;
typedef message_filters::Synchronizer<exact_policy> Synchronizer;
std::unique_ptr<Synchronizer> syncExact_;

node.cpp:

syncExact_.reset(new message_filters::Synchronizer<exact_policy>(exact_policy(10), image_sub_, depth_sub_));
syncExact_->registerCallback(&MonocularSlamNode::GrabRGBD,this);

So now syncExact is a class member. However, the callback is still not called. Any other suggestion?

(please note the EDIT of my original post, I switched to ExactPolicy instead of approximate since now the two topics publish with same timestamp.)

Asked by damiano on 2022-11-28 04:17:26 UTC