我在学C++。
我需要等待接收一些数据来启动主线程。
这是回调函数,我将在其中接收我需要的数据:
/**
* Robot's initial position (X component).
*/
double init_pos_x = 0.0;
/**
* Robot's initial position (Y component).
*/
double init_pos_y = 0.0;
/**
* Used to get only the robot's initial position.
*/
bool is_init_pos = true;
/**
* Current robot's X position.
*/
double x = 0.0;
/**
* Current robot's Y position.
*/
double y = 0.0;
/**
* Current robot's orientation.
*/
tfScalar theta = 0.0;
/**
* Command velocity topic's name.
*/
const std::string cmdTopic = "/pioneer2dx/mybot/cmd_vel";
/**
* Odometry topic's name.
*/
const std::string odomTopic = "/pioneer2dx/mybot/odom_diffdrive";
/**
* Callback function executes when new topic data comes.
* Task of the callback function is to print data to screen.
*/
void odomCallback(const nav_msgs::Odometry::ConstPtr& msg)
{
// Update robot position (x, y).
x = msg->pose.pose.position.x;
y = msg->pose.pose.position.y;
// If this is the first position given by the odometry topic, then it is the
// initial position of the robot.
if (is_init_pos)
{
is_init_pos = false;
// Set robot's initial position.
init_pos_x = x;
init_pos_y = y;
}这是主线:
int main(int argc, char **argv)
{
ros::init(argc, argv, "astar_controller");
/**
* NodeHandle is the main access point to communications with the ROS system.
* The first NodeHandle constructed will fully initialize this node, and the last
* NodeHandle destructed will close down the node.
*/
ros::NodeHandle n;
/**
* Topic where we are going to publish speed commands.
*/
ros::Publisher cmd_vel_pub = n.advertise<geometry_msgs::Twist>(cmdTopic, 1000);
/**
* Topic where we are going to receive odometry messages.
*/
ros::Subscriber odom_sub = n.subscribe(odomTopic, 1000, odomCallback);
ros::Rate loop_rate(10);
//*********************************************
// I want to wait here.
//*********************************************
// More code...
}我曾经想过使用like循环来检查is_init_pos是否已经更改,然后继续,但是我需要在while循环中执行一些操作(类似于thread.sleep())。
如何等待接收odomCallback中的第一个“消息”?
发布于 2019-07-11 12:59:11
当您运行多线程应用程序时,其他两个答案是正确的,但这是一个单线程应用程序。
ROS使用ros::spinOnce()来:
处理一轮回调。 如果您有自己的循环运行,并且希望处理任何可用的回调,则此方法非常有用。这相当于在全局callAvailable上调用CallbackQueue ()。它将不会处理分配给自定义队列的任何回调。
感谢乔纳森·韦克利给我指明了正确的方向。抱歉,我在学习,但我不知道。
最后,我使用以下代码进行了修正:
//*********************************************
// I want to wait here.
//*********************************************
while (ros::ok)
{
ros::spinOnce();
loop_rate.sleep();
if (!is_init_pos)
break;
}发布于 2019-07-10 11:16:33
全局地,声明一个条件变量和一个在回调线程和main之间共享的互斥体。在互斥锁下的布尔值。
#include <mutex>
#include <condition_variable>
std::condition_variable g_cv;
std::mutex g_mutex;
bool g_isReady = false;在您的odomCallback内部,在它返回之前,执行以下操作,向main发出信号,表示它可以继续运行
g_mutex.lock();
g_isReady = true;
g_mutex.unlock();
g_cv.notify_all();然后,您等待如下:
//*********************************************
// I want to wait here.
//*********************************************
// Wait for odomCallback to signal its done
{
std::unique_lock<std::mutex> lock(g_mutex);
while (g_isReady == false)
{
g_cv.wait(lock);
}
}发布于 2019-07-10 11:18:59
编辑:,我不认为你应该使用多线程。通过在主线程“事件循环” 中运行来等待回调。
//*********************************************
// I want to wait here.
//*********************************************
ros::spin();请参阅http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning
原始答案如下:
首先,需要安全地从多个线程并发访问is_init_pos变量。否则,如果主线程在回调线程写入时读取它,则程序将具有未定义的行为。因此,使用互斥锁来同步对布尔值的访问,并在状态更改时使用条件变量发送通知:
bool is_init_pos = true;
std::mutex init_mutex;
std::condition_variable init_cv;回调函数在访问is_init_pos时应该锁定该互斥对象,并对条件变量发送通知:
std::lock_guard<std::mutex> lock(init_mutex);
if (is_init_pos)
{
is_init_pos = false;
// Set robot's initial position.
init_pos_x = x;
init_pos_y = y;
init_cv.notify_one();
}现在,当状态更改时,主线程可以等待条件变量接收通知:
ros::Rate loop_rate(10);
//*********************************************
// I want to wait here.
//*********************************************
// New nested scope that determines the duration of the mutex lock
{
std::unique_lock<std::mutex> lock(init_mutex);
auto condition = [] { return is_init_pos == false; };
init_cv.wait(lock, condition);
}
// first callback happened, OK to proceed now ...
// More code...线程将在condition_variable::wait调用时阻塞,并且只有在被通知唤醒后才返回,并且它会看到关联条件的真值(定义为测试布尔变量的lambda表达式)。当没有通知或条件为false时,它将继续等待。
编辑: P.S. selbie的类似答案可能会稍微高效一些,因为只有g_isReady变量在两个线程之间共享,所以不需要每次都在回调中锁定互斥对象,只有在第一个调用时:
if (is_init_pos)
{
is_init_pos = false;
// Set robot's initial position.
init_pos_x = x;
init_pos_y = y;
std::lock_guard<std::mutex> lock(init_mutex);
g_isReady = true;
init_cv.notify_one();
}在main线程中,使用[] { return g_isReady; };作为条件。
这使用了一个额外的bool变量,但避免了每次回调时锁定互斥对象。这在实践中可能不会有太大的区别,所以在我的回答中,我只是重用了您已经拥有的现有is_init_pos变量。
https://stackoverflow.com/questions/56968641
复制相似问题