ROS订阅器修改类属性异常:回调修改私有成员变量求助
解决ROS订阅回调修改类私有成员变量的问题
问题分析
你的代码核心问题是没有启动ROS的消息处理循环,导致订阅回调函数从未被正常执行:
- main函数中订阅话题后立刻调用
Print_Variables(),此时还没有任何消息被处理,position.x保持初始值0; - 程序直接
return 0退出,退出前的异常输出并非正常流程下的回调执行结果; - ROS需要通过
ros::spin()或ros::spinOnce()触发消息队列处理,才能让回调函数真正运行。
另外,回调函数在ROS后台线程执行,直接修改类成员变量存在线程安全风险,需要添加互斥锁避免数据竞争。
解决方案
- 启动ROS消息循环:选择阻塞式的
ros::spin()(持续处理消息直到程序退出),或用ros::Rate配合ros::spinOnce()(非阻塞式,可同时执行其他逻辑); - 添加线程安全保护:用
std::mutex保护类的私有成员变量,防止多线程读写冲突; - 数据处理与发布:在类中添加发布者成员,可在回调或主循环中处理数据后发布至目标话题。
修改后的代码示例
#include <ros/ros.h> #include <geometry_msgs/Vector3.h> #include <mavros_msgs/DRONESENSOR.h> #include <iostream> #include <mutex> class MavrosListener { private: geometry_msgs::Vector3 position; std::mutex position_mutex; // 互斥锁保护共享变量 ros::Publisher processed_pub; // 处理后数据的发布者 public: // 构造函数初始化发布者 MavrosListener(ros::NodeHandle& nh) { processed_pub = nh.advertise<geometry_msgs::Vector3>("/processed_position", 10); } void Listen_From_MAVROS_Callback(const mavros_msgs::DRONESENSOR::ConstPtr& dronesensor) { std::lock_guard<std::mutex> lock(position_mutex); // 自动加锁 position.x = dronesensor->position[0]; // 可在此直接处理并发布数据 publishProcessedData(); } void Print_Variables() { std::lock_guard<std::mutex> lock(position_mutex); // 读取时加锁 std::cout << "x position: " << position.x << std::endl; } // 数据处理与发布逻辑 void publishProcessedData() { std::lock_guard<std::mutex> lock(position_mutex); geometry_msgs::Vector3 msg = position; // 此处可添加滤波、坐标转换等处理逻辑 processed_pub.publish(msg); } }; int main(int argc, char **argv) { ros::init(argc, argv, "GeoCtrlListener"); ros::NodeHandle n; MavrosListener listener(n); ros::Subscriber Sub_From_Mavros = n.subscribe("/mavros/odroid/odroid_input", 1, &MavrosListener::Listen_From_MAVROS_Callback, &listener); // 非阻塞式循环,每秒处理10次消息并执行逻辑 ros::Rate rate(10); while (ros::ok()) { listener.Print_Variables(); ros::spinOnce(); // 处理当前消息队列 rate.sleep(); // 控制循环频率 } // 若无需主循环逻辑,也可直接使用阻塞式spin: // ros::spin(); return 0; }
关键说明
- 消息循环选择:
ros::spin()适合仅需处理消息的场景,会一直阻塞;ros::spinOnce()配合循环适合同时执行其他业务逻辑的场景; - 线程安全:
std::lock_guard会自动完成锁的加解锁,避免手动操作遗漏导致的死锁; - 数据发布:可根据需求选择在回调中实时发布,或在主循环中定期批量发布处理后的数据。
内容的提问来源于stack exchange,提问作者Junjie Gao
相关产品推荐
相关产品推荐

