ROS2 Humble类内注册message_filters非静态同步回调问题
ROS2 Humble中message_filters同步器注册非静态类成员回调的解决方案
问题描述
在ROS2 Humble中使用message_filters的Synchronizer结合Approximate Time Policy实现消息同步时,类外注册回调功能正常,但类内注册非静态成员函数作为回调时编译报错,提示无法匹配回调函数类型。
现有代码
回调函数
void performNDT(const sensor_msgs::msg::LaserScan &lidar_msg, const nav_msgs::msg::Odometry &odom_msg) { std::cout << "Hello sync world" << std::endl; }
同步策略与同步器定义
typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::msg::LaserScan, nav_msgs::msg::Odometry> approximate_time_sync_policy; message_filters::Synchronizer<approximate_time_sync_policy> synchronizer;
类构造函数
LandmarkExtractor() : Node("landmark_extractor"), synchronizer(approximate_time_sync_policy(10), lidar_sub, odom_sub) { /******* QOS SETTINGS *******/ custom_qos_profile.depth = 1; custom_qos_profile.reliability = rmw_qos_reliability_policy_t::RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; custom_qos_profile.history = rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_LAST; custom_qos_profile.durability = rmw_qos_durability_policy_t::RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT; // Subscribing to Odometry and LaserScan msg topics lidar_sub.subscribe(this, "scan", custom_qos_profile); odom_sub.subscribe(this, "odom", custom_qos_profile); // Registering synced callback synchronizer.registerCallback(std::bind(&LandmarkExtractor::performNDT,this, _1, _2)); ... }
订阅器定义
// Subscribers message_filters::Subscriber<sensor_msgs::msg::LaserScan> lidar_sub; message_filters::Subscriber<nav_msgs::msg::Odometry> odom_sub;
编译错误
error: no matching function for call to ‘message_filters::Signal9<std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > >, std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > >, message_filters::NullType, message_filters::NullType, message_filters::NullType, message_filters::NullType, message_filters::NullType, message_filters::NullType, message_filters::NullType>::addCallback<const M0ConstPtr&, const M1ConstPtr&, const M2ConstPtr&, const M3ConstPtr&, const M4ConstPtr&, const M5ConstPtr&, const M6ConstPtr&, const M7ConstPtr&, const M8ConstPtr&>(std::_Bind_helper<false, const std::_Bind<void (LandmarkExtractor::*(LandmarkExtractor*, std::_Placeholder<1>, std::_Placeholder<2>))(const std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > >&, const std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > >&)>&, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&, const std::_Placeholder<4>&, const std::_Placeholder<5>&, const std::_Placeholder<6>&, const std::_Placeholder<7>&, const std::_Placeholder<8>&, const std::_Placeholder<9>&>::type)’ 272 | return addCallback<const M0ConstPtr&, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 273 | const M1ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 274 | const M2ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 275 | const M3ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 276 | const M4ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 277 | const M5ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 278 | const M6ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 279 | const M7ConstPtr&, | ~~~~~~~~~~~~~~~~~~ 280 | const M8ConstPtr&>(std::bind(callback, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9)); | ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /opt/ros/humble/include/message_filters/message_filters/synchronizer.h:47, from /opt/ros/humble/include/message_filters/message_filters/time_synchronizer.h:41, from /home/jan/ros_ws/src/shamanbot/src/landmark_extraction.cpp:8: /opt/ros/humble/include/message_filters/message_filters/signal9.h:170:14: note: candidate: ‘message_filters::Connection message_filters::Signal9<M0, M1, M2, M3, M4, M5, M6, M7, M8>::addCallback(const std::function<void(P0, P1, P2, P3, P4, P5, P6, P7, P8)>&) [with P0 = const std::shared_ptr<const std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > > >&; P1 = const std::shared_ptr<const std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > > >&; P2 = const std::shared_ptr<const message_filters::NullType>&; P3 = const std::shared_ptr<const message_filters::NullType>&; P4 = const std::shared_ptr<const message_filters::NullType>&; P5 = const std::shared_ptr<const message_filters::NullType>&; P6 = const std::shared_ptr<const message_filters::NullType>&; P7 = const std::shared_ptr<const message_filters::NullType>&; P8 = const std::shared_ptr<const message_filters::NullType>&; M0 = std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > >; M1 = std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > >; M2 = message_filters::NullType; M3 = message_filters::NullType; M4 = message_filters::NullType; M5 = message_filters::NullType; M6 = message_filters::NullType; M7 = message_filters::NullType; M8 = message_filters::NullType]’ 170 | Connection addCallback(const std::function<void(P0, P1, P2, P3, P4, P5, P6, P7, P8)>& callback) | ^~~~~~~~~~~ /opt/ros/humble/include/message_filters/message_filters/signal9.h:170:89: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, const std::_Bind<void (LandmarkExtractor::*(LandmarkExtractor*, std::_Placeholder<1>, std::_Placeholder<2>))(const std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > >&, const std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > >&)>&, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&, const std::_Placeholder<4>&, const std::_Placeholder<5>&, const std::_Placeholder<6>&, const std::_Placeholder<7>&, const std::_Placeholder<8>&, const std::_Placeholder<9>&>::type’ to ‘const std::function<void(const std::shared_ptr<const std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > > >&, const std::shared_ptr<const std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > > >&, const std::shared_ptr<const message_filters::NullType>&, const std::shared_ptr<const message_filters::NullType>&, const std::shared_ptr<const message_filters::NullType>&, const std::shared_ptr<const message_filters::NullType>&, const std::shared_ptr<const message_filters::NullType>&, const std::shared_ptr<const message_filters::NullType>&, const std::shared_ptr<const message_filters::NullType>&)>&’ 170 | Connection addCallback(const std::function<void(P0, P1, P2, P3, P4, P5, P6, P7, P8)>& callback) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~ /opt/ros/humble/include/message_filters/message_filters/signal9.h:180:14: note: candidate: ‘template<class P0, class P1> message_filters::Connection message_filters::Signal9<M0, M1, M2, M3, M4, M5, M6, M7, M8>::addCallback(void (*)(P0, P1)) [with P0 = P0; P1 = P1; M0 = std::shared_ptr<sensor_msgs::msg::LaserScan_<std::allocator<void> > >; M1 = std::shared_ptr<nav_msgs::msg::Odometry_<std::allocator<void> > >; M2 = message_filters::NullType; M3 = message_filters::NullType; M4 = message_filters::NullType; M5 = message_filters::NullType; M6 = message_filters::NullType; M7 = message_filters::NullType; M8 = message_filters::NullType]’ 180 | Connection addCallback(void(*callback)(P0, P1))
解决方法
1. 修正回调函数参数类型
message_filters的同步回调默认传递std::shared_ptr<const MsgType>类型,而非原始消息引用,需调整回调参数类型:
void performNDT(const std::shared_ptr<const sensor_msgs::msg::LaserScan>& lidar_msg, const std::shared_ptr<const nav_msgs::msg::Odometry>& odom_msg) { std::cout << "Hello sync world" << std::endl; // 访问消息内容使用->操作符,例如 lidar_msg->header.stamp }
2. 正确注册回调(两种方式)
方式一:Lambda表达式(推荐)
Lambda可直接捕获this指针,语法直观,避免std::bind的类型匹配问题:
// 替换构造函数中原registerCallback代码 synchronizer.registerCallback( [this](const std::shared_ptr<const sensor_msgs::msg::LaserScan>& lidar_msg, const std::shared_ptr<const nav_msgs::msg::Odometry>& odom_msg) { this->performNDT(lidar_msg, odom_msg); } );
方式二:std::bind
若坚持使用std::bind,需确保绑定函数参数与回调期望类型完全匹配:
synchronizer.registerCallback( std::bind(&LandmarkExtractor::performNDT, this, std::placeholders::_1, std::placeholders::_2) );
3. 调整同步器初始化顺序(可选)
原代码在初始化列表创建同步器时,订阅器尚未完成订阅,存在潜在风险。可将同步器改为智能指针,在构造函数中完成订阅后再初始化:
// 类内同步器定义修改为 std::unique_ptr<message_filters::Synchronizer<approximate_time_sync_policy>> synchronizer; // 构造函数内调整逻辑 LandmarkExtractor() : Node("landmark_extractor") { // ... QOS配置代码 ... // 先完成订阅 lidar_sub.subscribe(this, "scan", custom_qos_profile); odom_sub.subscribe(this, "odom", custom_qos_profile); // 再初始化同步器 synchronizer = std::make_unique<message_filters::Synchronizer<approximate_time_sync_policy>>( approximate_time_sync_policy(10), lidar_sub, odom_sub ); // 注册回调 synchronizer->registerCallback(/* 上述Lambda或bind代码 */); }
验证编译
修改完成后执行colcon build即可正常编译,运行节点后同步回调会被正确触发。
内容的提问来源于stack exchange,提问作者JanSam
相关产品推荐
相关产品推荐

