You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ROS订阅器修改类属性异常:回调修改私有成员变量求助

解决ROS订阅回调修改类私有成员变量的问题

问题分析

你的代码核心问题是没有启动ROS的消息处理循环,导致订阅回调函数从未被正常执行:

  • main函数中订阅话题后立刻调用Print_Variables(),此时还没有任何消息被处理,position.x保持初始值0;
  • 程序直接return 0退出,退出前的异常输出并非正常流程下的回调执行结果;
  • ROS需要通过ros::spin()或ros::spinOnce()触发消息队列处理,才能让回调函数真正运行。

另外,回调函数在ROS后台线程执行,直接修改类成员变量存在线程安全风险,需要添加互斥锁避免数据竞争。

解决方案

  1. 启动ROS消息循环:选择阻塞式的ros::spin()(持续处理消息直到程序退出),或用ros::Rate配合ros::spinOnce()(非阻塞式,可同时执行其他逻辑);
  2. 添加线程安全保护:用std::mutex保护类的私有成员变量,防止多线程读写冲突;
  3. 数据处理与发布:在类中添加发布者成员,可在回调或主循环中处理数据后发布至目标话题。

修改后的代码示例

#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 09:22:19