ROS订阅回调缺少消息

4
总结:我有一个节点以大约300hz的频率发布消息,但是另一个节点中订阅该主题的回调只以大约25hz的频率被调用。订阅者节点中的spinOnce被调用的频率为~700hz,因此我不知道为什么会丢失消息。
发布者节点:
#include <ros/ros.h>
#include <ros/console.h>
#include <nav_msgs/Odometry.h>

...

int main(int argc, char** argv)
{
    ros::init(argc, argv, "sim_node");
    ros::NodeHandle nh;

    ...

    // Publishers
    tf::TransformBroadcaster tfbr;
    ros::Publisher odomPub = nh.advertise<nav_msgs::Odometry>("pose",10);

   ...

    ros::Rate r(300); // loop rate
    while(ros::ok())
    {
        ...

        // Publish pose and velocity
            ...
        odomPub.publish(msg);

        ros::spinOnce();
        r.sleep();
    }
    
    ros::waitForShutdown();
    return 0;
}

订阅节点:

#include <ros/ros.h>
#include <ros/console.h>
#include <nav_msgs/Odometry.h>

...

std::mutex mtx1, mtx2;

class DataHandler
{
private:
    ros::NodeHandle nh;
    ros::Publisher odomPub;
    double lastTime;
    int lastSeq;
    
public:
    Eigen::Vector3d x, xDot, w;
    Eigen::Vector3d xDes, xDesDot, xDesDotDot, b1Des, b1DesDot;
    Eigen::Matrix3d R;
    
    DataHandler()
    {
        // Initialize data
        xDes = Eigen::Vector3d(1,0,1);
        xDesDot = Eigen::Vector3d::Zero();
        xDesDotDot = Eigen::Vector3d::Zero();
        b1Des = Eigen::Vector3d(1,0,0);
        b1DesDot = Eigen::Vector3d::Zero();
        x = Eigen::Vector3d::Zero();
        xDot = Eigen::Vector3d::Zero();
        R = Eigen::Matrix3d::Identity();

        odomPub = nh.advertise<nav_msgs::Odometry>("controller_pose",10);
        trajPub = nh.advertise<asap_control::DesiredTrajectory>("controller_desTraj",10);
        lastTime = ros::Time::now().toSec();
        lastSeq = 0;
    }
    
    // Get current pose and velocity
    void odomCB(const nav_msgs::OdometryConstPtr& odomMsg)
    {

        mtx1.lock();
        // Get data
        double time1 = ros::Time::now().toSec();
        x << odomMsg->pose.pose.position.x, odomMsg->pose.pose.position.y, ...;
        xDot << odomMsg->twist.twist.linear.x, odomMsg->twist.twist.linear.y, ...;
        R = Eigen::Quaterniond(odomMsg->pose.pose.orientation.w, odomMsg->pose.pose.orientation.x,...;
        w << odomMsg->twist.twist.angular.x, odomMsg->twist.twist.angular.y, ...;
        double time2 = ros::Time::now().toSec();
            
        // Time to extract data, < 1ms
        double delTproc = time2 - time1;
        std::cout << "\n\n";
        std::cout << "proc elapsed time: " << delTproc << "\n";
        std::cout << "proc frequency: " << 1.0/delTproc << "\n";

        odomPub.publish(odomMsg); // rostopic hz says this is publishing at ~25Hz
           
        // Time between callback calls, ~25Hz
        double timeNow = ros::Time::now().toSec();
        double delT = timeNow - lastTime;
        lastTime = timeNow;
        std::cout << "elapsed time: " << delT << "\n";
        std::cout << "frequency: " << 1.0/delT << "\n";
            
        // Message sequence IDs, shows 12 msgs skipped every call
        int seqNow = odomMsg->header.seq;
        int delSeq = seqNow - lastSeq;
        lastSeq = seqNow;
        std::cout << "delta seq: " << delSeq << "\n";
        mtx1.unlock();
    }
    
};

...

int main(int argc, char** argv)
{
    ros::init(argc, argv, "asap_control");
    ros::NodeHandle nh;

    ...

    // Publishers
    ros::Publisher outputPub = nh.advertise<geometry_msgs::WrenchStamped>("wrench_command",10);
    ros::Publisher debugPub = nh.advertise<control::ControllerSignals>("controller_debug",10);
    tf::TransformBroadcaster tfbr;

    // Subscribers
    DataHandler callbacks;
    ros::Subscriber poseSub = nh.subscribe("pose",10,&DataHandler::odomCB,&callbacks);

    // Asynchronous threads for callback handling
    //ros::AsyncSpinner spinner(2);
    //spinner.start();

    double lastTime = ros::Time::now().toSec();

    
    // Main loop
    ros::Rate r(700); // loop rate
    while(ros::ok())
    {
        // Data (extracted for cleanliness further down, and thread safety)
        mtx1.lock();
        Eigen::Vector3d x = callbacks.x;
        Eigen::Vector3d xDot = callbacks.xDot;
        Eigen::Matrix3d R = callbacks.R;
        Eigen::Vector3d w = callbacks.w;
        mtx1.unlock();
        
            ...
        
        // Publish
            ...
        outputPub.publish(msg);
            
        // Publish debug signals
        control::ControllerSignals debugMsg;
        debugMsg.x[0] = x(0);
        ...
        debugPub.publish(debugMsg);
            
        //double timeNow = ros::Time::now().toSec();
        //double delT = timeNow - lastTime;
        //lastTime = timeNow;
        //std::cout << "\n\n";
        //std::cout << "elapsed time: " << delT << "\n";
        //std::cout << "frequency: " << 1.0/delT << "\n";
        
        ros::spinOnce();
        r.sleep();
    }
    
    ros::waitForShutdown();
    return 0;
}

附加信息:

  1. 发布者以大约300Hz的频率(由“pose”主题的rostopic hz确认)发布。
  2. 订阅节点中的主循环以大约700Hz的频率运行(通过在循环中发布到“wrench_command”主题的rostopic hz以及通过ros::Time::now()的循环计时进行确认),因此,spinOnce 以相同的速率被调用。
  3. 姿态主题的回调以大约25 Hz的频率被调用(通过在回调中发布到“controller_pose”主题的rostopic hz以及通过ros::Time::now()的循环计时进行确认)。
  4. 即使使用AsyncSpinner而不是spinOnce,我也得到相同的行为,但只能使用rostopic hz进行确认。计时会产生不规则输出,这是预期的。
  5. 将订阅者队列长度增加到例如10会将回调速率增加到约250Hz,但我想保持队列长度为1,以获取最新的数据。
  6. Ubuntu中的系统监视器显示CPU利用率不到50%,所以我认为这不是CPU瓶颈问题。
1个回答

6

我曾经解决过一个类似的问题,即在传输里程计数据时,里程计数据以100Hz的速率传输,但只以25Hz的速率接收。原来是底层的TCP套接字在缓冲数据,将4个消息合并成一个TCP数据包以节省传输成本。我相信您需要在TransportHints()中将tcpNoDelay设置为true:

node.subscribe(...,ros::TransportHints().tcpNoDelay(true));

请注意,这发生在订阅方

http://wiki.ros.org/roscpp/Overview/Publishers%20and%20Subscribers#Transport_Hints


是的,我可以确认这就是问题所在。谢谢! - Anup

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接