在工作时,以为spinonce带有阻塞功能,后测试时发现在回调函数收不到消息的时候依旧可以运行后面的程序。以下是借助gpt的两点说明:
ros::spin() 和 ros::spinOnce() 都是为了处理回调函数的消息,但它们的使用方式和应用场景略有不同。
-
ros::spin():
它会使你的节点持续监听订阅的主题上的消息,直到节点关闭或者ROS被关闭。
当一个新消息到达时,它会自动调用对应的回调函数。
一般在不需要执行其他任务,只需要监听消息并处理的节点中使用。 -
ros::spinOnce():
它会处理消息队列中当前的所有消息,但只处理一次,然后继续执行后面的代码。
通常与定时器或其他循环结构一起使用,允许节点在监听消息的同时执行其他任务。
假设我们有一个节点,它需要不断地监听一个名为 “data” 的主题上的消息,并同时每秒执行一次某种操作。
使用 ros::spin():
void dataCallback(const std_msgs::String::ConstPtr& msg)
{
// 处理"data"主题上的消息
ROS_INFO("Received: %s", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("data", 1000, dataCallback);
ros::spin(); // 这里会一直阻塞,直到节点关闭
return 0;
}
使用上面的代码,你的节点只能处理 “data” 主题上的消息,无法执行其他任务。
使用 ros::spinOnce():
cpp
void dataCallback(const std_msgs::String::ConstPtr& msg)
{
// 处理"data"主题上的消息
ROS_INFO("Received: %s", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("data", 1000, dataCallback);
ros::Rate loop_rate(1); // 1Hz
while (ros::ok())
{
// 每秒执行的操作
ROS_INFO("Performing a task every second.");
ros::spinOnce(); // 处理消息队列中的消息
loop_rate.sleep(); // 等待,直到1秒过去
}
return 0;
}
在这个例子中,通过使用 ros::spinOnce() 和一个循环,我们可以在监听和处理 “data” 主题上的消息的同时,每秒执行其他任务。
想要在收不到消息时候,阻塞程序或者跳过后面程序运行可以采用标志位的方式:
bool receivedMessage = false; // 初始化为false
void dataCallback(const std_msgs::String::ConstPtr& msg)
{
// 处理"data"主题上的消息
ROS_INFO("Received: %s", msg->data.c_str());
receivedMessage = true; // 当收到消息时设置为true
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("data", 1000, dataCallback);
ros::Rate loop_rate(1); // 1Hz
while (ros::ok())
{
receivedMessage = false; // 在每次循环开始时重置标志
ros::spinOnce(); // 处理消息队列中的消息
if (receivedMessage) // 检查是否收到消息
{
// 如果收到消息,则执行以下操作
ROS_INFO("Performing a task because a message was received.");
}
else
{
// 如果未收到消息,您可以在这里执行其他操作或仅跳过
}
loop_rate.sleep(); // 等待,直到1秒过去
}
return 0;
}
再PO一个例子:这里我希望两个回调信息都到达后才run的综合利用了两个回调信息内容的函数
void RosReplayInterface::fcmdCallback(const ppcontroller::PPOUT::ConstPtr& msg)
{
flag_run1=true;
}
void RosReplayInterface:: fESACallback(const noa_msgs::ESAInfo::ConstPtr& msg)
{
flag_run2 =true;
}
void RosReplayInterface:: fRun ()
{
ros::Rate rate(50);
while (ros::ok())
{
static bool flag =false;
ros::spinOnce();
if (flag_run1&&flag_run2)
{
flag=true;
}
if (flag)// only run when
{
pathReplay_.run();
flag_run1 =false;
flag_run2 =false;
flag=false;
//LOG(INFO)<<cmd_STA<<"to x: "<<x_<<" y: "<<y_;
//std::cout<<"run to here"<<cmd_STA<<std::endl;
fPubResult();
}
rate.sleep();
}