Calling a service on the same node which it's advertised

asked 2018-06-01 19:08:25 -0600

lkwatson gravatar image

I'm trying to write a subclass of a node in order to dynamically test some publishers and services. I'd like to be able to verify that certain members of the node are correctly modified upon calling services and publishing certain messages.

However, when I try to do this with a service, I always get false returned upon calling it.

Is what I'm trying to do possible? Is there some conflict occurring in trying to advertise and call a server on the same node?

Here is the relevant portion of my main node main.cpp

MainNode::MainNode() {
  nh_ = ros::NodeHandle("~");
  ...
  my_service_ = nh_.advertiseService("source", &MainNode::myServiceCb, this);
  ROS_INFO("Main is up");
}
...
bool MainNode::myServiceCb(my_msgs::TestService::Request& req,
                          my_msgs::TestService::Response& res) {
  ROS_INFO("Callback called");
  res.status = 1;
  return true;
}

subclass.cpp

int main(int argc, char** argv) {
  ros::init(argc, argv, kNodeName);

  TestMainNode test_main;
  test_main.runTests();
  test_main.run();

  return 0;
}

TestMainNode::TestMainNode() : MainNode() {
  ROS_INFO("TEST launched");
}

void TestCommandNode::runTests() {
  //This was originally omitted, tried adding to see if there was some conflict with using the same node handler
  nh2_ = ros::NodeHandle("~");

  if(ros::service::waitForService("test_node/source",-1)) {
    ROS_WARN("Service available, initiating tests");
    serv_client_ = nh2_.serviceClient<my_msgs::TestService>("test_node/source");

    if(!testService()) {
      ROS_ERROR("[TEST] Source switching test failed");
    }
  }
}

bool TestCommandNode::testSourceSwitching() {
  // Test for all inputs that should return SUCCESS
  int types[] = {0,1,2,3};
  for(int sour: types) {
    ROS_INFO("Yup its %d", sour);
    my_msgs::TestService srv_call;
    srv_call.request.type = (int) sour;

    //Tried both of the following within "if", both return same result
    //ros::service::call("source", srv_call)
    //serv_client_.call(srv_call)
    if(ros::service::call("source", srv_call)) {
      ROS_INFO("Call success!");
      if(srv_call.response.status == my_msgs::TestService::Response::FAILURE) {
        ROS_ERROR("[TEST] Tried %d but failed!", sour);
      }else{
        ROS_INFO("[TEST] Tried %d, success", sour);
      }
    }else{
      ROS_ERROR("[TEST] Service call failed for unknown reason, %d",srv_call.response.status);
    }
  }
}

TestService.srv

# Request
int32 type

# Request type constants
int32 ZERO=0
int32 ONE=1
int32 TWO=2
int32 THREE=3

---

# Response
int32 status

# Response status constants
int32 FAILURE=0
int32 SUCCESS=1

Here is the output I get

[ INFO] [1527897132.736164872]: TEST launched
[ INFO] [1527897132.736205987]: Main is up
[ WARN] [1527897132.737292582]: Service available, initiating tests
[ INFO] [1527897132.737314987]: Yup its 0
[ERROR] [1527897132.737641323]: [TEST] Service call failed for unknown reason, 0
[ INFO] [1527897132.737652149]: Yup its 1
[ERROR] [1527897132.737926956]: [TEST] Service call failed for unknown reason, 0
[ INFO] [1527897132.737937159]: Yup its 2
[ERROR] [1527897132.738307667]: [TEST] Service call failed for unknown reason, 0
[ INFO] [1527897132.738317346]: Yup its 3

Indicating the call is returning false each time. I've tried all permutations of ros::service:call and serv_client_ using topic source and test_node/source. With ros::service::call the call never returns if the topic is test_node/source, but returns false if it's source. The opposite is the case using serv_client_.

Any help is appreciated. If there's a better way I could be testing this, do let me know.

edit retag flag offensive close merge delete

Comments

Not an answer, but a question: why do you make your test inherit from the cut? I realise that is a common approach in some contexts / testing workflows, but I've not seen it done often in ROS node (ie: rostest) tests. A more typical approach would be to keep your regular node as-is, and write an ..

gvdhoorn gravatar imagegvdhoorn ( 2018-06-02 01:39:29 -0600 )edit

.. additional node that is your test node. That node only gets used in the rostest you then setup, which will take care of starting up a roscore, your nodes, etc.

gvdhoorn gravatar imagegvdhoorn ( 2018-06-02 01:40:16 -0600 )edit

There are some private members of the main node I'd like to be able to poke around at, but yes it's looking like the two node solution is what I'll have to use. Half of the question is just curiosity into whether this kind of thing is possible.

lkwatson gravatar imagelkwatson ( 2018-06-02 01:47:40 -0600 )edit
1

Well, as I wrote, it's definitely not an answer, and I don't like avoiding a problem by using a different approach (ie: work-around).

Who is doing the spinning in your setup?

gvdhoorn gravatar imagegvdhoorn ( 2018-06-02 01:49:09 -0600 )edit

The main node is doing the spinning, with the test node (or hopefully subclass) just running once.

lkwatson gravatar imagelkwatson ( 2018-06-04 16:18:16 -0600 )edit