Change subscribed topic/subscriber based on condition during runtime
I have a robot with a front and back camera. I've got a callback function in my node that can be used for the topics from either of the cameras. I want the callback to subscribe to one of the two topics depending on a condition.
Something like:
If front mode engaged:
ros::Subscriber subPCL = n.subscribe<PointCloud>("/front_cloud", 10, pclCallback);
If back mode engaged:
ros::Subscriber subPCL = n.subscribe<PointCloud>("/back_cloud", 10, pclCallback);
During runtime, the operation mode can change from front to back depending on which direction the robot is driving. So the topic the callback subscribes to should change.
Currently, I just initialise one subscriber in my main function when starting the node but this will create conflicts if I want to do the same for two.
I have a service callback in the same node that receives the direction the robot is going, which I thought I could use.
bool startrowCallback(row_follower::start_row_mode::Request &req, row_follower::start_row_mode::Response &res){
if (!rowMode){
rowMode = true;
drivingDirection = req.direction;
if (drivingDirection = "front") {
ros::Subscriber subPCL = n.subscribe<PointCloud>("/front_cloud", 10, pclCallback);
}
if (drivingDirection = "back"){
ros::Subscriber subPCL = n.subscribe<PointCloud>("/back_cloud", 10, pclCallback);
}
res.done = true;
}
else{
res.done = false;
}
return res.done;
}
But I'm not sure that is the right place to initialise a subscriber and if it the callback will get called with ros::spin in the main function. As I'm not passing the node handle from the main function I imagine what I wrote above won't compile. What would be the best way of doing this?
Asked by jorgemia on 2021-04-13 10:30:57 UTC
Answers
The node handle should work even if it is described in a service function. If you don't unsubscribe an existing one before subscribing a new one, it may continue to subscribe to the existing one.
ros::Subscriber subPCL; // added
bool startrowCallback(row_follower::start_row_mode::Request &req, row_follower::start_row_mode::Response &res){
ros::NodeHandle n; // added
if (!rowMode){
rowMode = true;
drivingDirection = req.direction;
if (drivingDirection == "front") {
subPCL.shutdown(); // added
subPCL = n.subscribe<PointCloud>("/front_cloud", 10, pclCallback); // changed
}
if (drivingDirection == "back"){
subPCL.shutdown(); // added
subPCL = n.subscribe<PointCloud>("/back_cloud", 10, pclCallback); // changed
}
res.done = true;
}
else{
res.done = false;
}
return res.done;
}
Asked by miura on 2021-04-14 08:15:42 UTC
Comments
Thanks for the answer. I already have a node handle that initialises some publishers/subscribers and gets parameters in the main function. Shouldn't I use the same node handle for these subscribers? Also, are you defining subPCL as a global subscriber?
Asked by jorgemia on 2021-04-14 14:08:51 UTC
I am going to try and pass the nodehandle as a parameter to the service using boost::bind and see if that works:
This is what I wrote and it seems to have compiled correctly. In my main function:
ros::NodeHandle n;
ros::ServiceServer StartRowModeService = n.advertiseService<row_follower::start_row_mode::Request, row_follower::start_row_mode::Response>("start_row_mode",boost::bind(startrowCallback, _1, _2, boost::ref(n)));
In my callback definition:
bool startrowCallback(row_follower::start_row_mode::Request &req, row_follower::start_row_mode::Response &res, ros::NodeHandle &n)
Asked by jorgemia on 2021-04-15 04:54:45 UTC
Shouldn't I use the same node handle for these subscribers?
I don't understand the detailed mechanism, but it seems to work fine with different node handles.
Also, are you defining subPCL as a global subscriber?
I think if you declare the subscriber in the service callback function, the subscriber will be released when the service callback function exits and finishes subscribing. Therefore, I think it needs to be declared as a global variable.
Asked by miura on 2021-04-15 11:28:08 UTC
Comments