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
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
Comments