ros2 subscriber callback blocking one another
Hello,
I am using ROS2 galactic on Ubuntu 20.04. I have 2 callbacks, one which subscribes to the movement message and another which subscribes to a custom path message. In the first call I can see that both these callbacks get data and are updated but however my second call back has a function which moves the robot on that particular path. When this line executes, I stop getting data in my first callback because it is blocking it I guess?? I tried callback groups but it didn't work. Here is my code:
1st callback
void Robot::moveStatusCb(const fleet_msgs::msg::MoveStatus &msg) {
moveable = msg.movestatus[robotId - 1];
std::cout << "MOVABLE CALLBACK: " << moveable << std::endl;
}
2nd callback
void Robot::robotPathCb(const fleet_msgs::msg::RobotPath &msg) {
std::cout << "Entered path callback" << std::endl;
for (int i = 0; i < msg.paths.size(); ++i)
{
if (robotId == msg.paths[i].robotid)
{
robotPath = msg.paths[i];
task = 1;
robotInstructions();
assigned = true;
break;
}
else {
task = 0;
robotInstructions();
robotStatus.robotid = robotId;
robotStatus.orderid = -1;
robotStatus.toteid = -1;
robotStatus.state = state;
robotStatPub->publish(robotStatus);
}
}
robotMovement();
}
The robotMovement function is the one which makes the robot move. However when the code enters this function, I stop getting data on movementStatusCb. Can anyone please tell me how to solve this??
Thanks.
Asked by cjoshi17 on 2022-07-21 06:14:50 UTC
Answers
What kind of executor are you using? If you are using the default rclcpp::spin() I think that uses a single threaded executor by default, which will call only one callback at a time. I would suggest trying a multithreaded executor, something like this:
rclcpp::executors::MultiThreadedExecutor executor;
executor.add_node(node);
executor.spin();
See the docs for more information
Asked by Pepis on 2022-07-21 14:16:15 UTC
Comments
I tried this but it did not work for me:
rclcpp::init(argc, argv);
rclcpp::executors::MultiThreadedExecutor executor;
executor.add_node(std::make_shared<Robot>());
executor.spin();
rclcpp::shutdown();
When I did this, I wasn't getting any data in my callbacks.
Asked by cjoshi17 on 2022-07-21 23:43:27 UTC
Hey, you are right. The default callback group for nodes is a mutually exclusive callback group, which as the docs state prevents callbacks from running concurrently. While keeping the multithreaded executor, try adding your subscriptions to a reentrant callback group. Inside your node's constructor:
auto my_callback_group = this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
rclcpp::SubscriptionOptions options;
options.callback_group = my_callback_group;
my_sub1 = this->create_subscription<fleet_msgs::msg::MoveStatus>(/my_topic1, my_qos, std::bind(&Robot::moveStatusCb, this, _1), options);
my_sub2= this->create_subscription<fleet_msgs::msg::RobotPath>(/my_topic2, my_qos, std::bind(&Robot::robotPathCb, this, _1), options);
Asked by Pepis on 2022-07-22 09:39:45 UTC
If theRobotMovement()
method takes a long time to run, or it shouldn't be called multiple times concurrently, you may consider re-architecting this a bit in conjunction with a MultiThreaded executor, or a second Thread.
Instead of calling RobotMovement()
inside your topic callback, you could put the data into a queue, and read that queue from a dedicated timer or thread. This way you've got the subscriptions getting handled by an executor, and the RobotMovement thread/timer can take as much time as it needs to push the robot through all the data in the queue without blocking the subscriptions.
If you use a timer for the RobotMovement, you'll need to put it in it's own callback group (type doesn't matter), and use a MultiThreaded Executor. In both cases, be sure to use mutexes to ensure that only one thread/callback is modifying the queue at a time.
Asked by ChuiV on 2022-08-09 19:10:49 UTC
Comments