ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

Change subscribed topic/subscriber based on condition during runtime

asked 2021-04-13 10:30:57 -0600

jorgemia gravatar image

updated 2021-04-13 10:33:47 -0600

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?

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2021-04-14 08:15:42 -0600

miura gravatar image

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;
}
edit flag offensive delete link more

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?

jorgemia gravatar image jorgemia  ( 2021-04-14 14:08:51 -0600 )edit

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)
jorgemia gravatar image jorgemia  ( 2021-04-15 04:54:45 -0600 )edit

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.

miura gravatar image miura  ( 2021-04-15 11:28:08 -0600 )edit

Question Tools

3 followers

Stats

Asked: 2021-04-13 10:30:57 -0600

Seen: 976 times

Last updated: Apr 14 '21