Ros2 service client call from non-ros class

asked 2023-04-28 14:13:09 -0500

Kaloyan gravatar image

Hi there,

My ROS2 knowledge is not sufficient to get over a problem, and I'm in need of some guidance.

I'm trying to one-shot a service call to a Ros2 service server using the c++ client code via not ros2-related c++ code, and (maybe I'm wrong) i see no use of having a running and spinning node in main() , instead I'd like to have the service client initialize , construct the request and send it (waiting for the feedback) and then continue with the rest of the C++ program. At some (unknown) time in the future that same class will shoot another request to the same service . There's no way that i know when the class will be called again so i can't use timers , and for my use case an event-driven service call would fit perfectly.

I checked quite literally every single post that pops up as result in google/ros answers / most if not all the documentation available on the topic, getting a shared_from_this() outside of the constructor, casting pointer between my custom class that inherits :node from the shared ptr, and a whole lot of random attempts of combinations and i can't get it working. I wrote a simple example to paint the issue i have that i can't resolve.

P.s. last resort option that I'd very much like to avoid is just fork a thread and go std::system(ros2 service call etc);

The example is purely to visualize what i am trying to achieve, and it's not meant to be used as actual working code.

Using the latest Ros2 Foxy 0.9.2-1focal.20230317.211418 amd64 on Ubuntu 20.04.6. Thanks to everyone who's willing to help.

class ProblemExampleClassA : public rclcpp::Node {
  public:
  explicit ProblemExampleClassA() : Node("problem_example") {
    client_ = this->create_client<std_srvs::srv::Empty>("/service_target");
  };

  std::shared_ptr<ProblemExampleClassA> ptr = std::static_pointer_cast<ProblemExampleClassA>(shared_from_this()); // currently bashing my head with this

  void something_to_call(std::string asd, std::string dsa) {
    std::cout << asd << dsa << std::endl;
    //i have two std:strings that i need to send via the request, but for the purpose of this i'm using the empty srv
    auto client_future = this->client_->async_send_request(); //etc service logics
  };

  private:
  rclcpp::Client<std_srvs::srv::Empty>::SharedPtr client_;
  void callback(rclcpp::Client<std_srvs::srv::Empty>::SharedFuture future) {
    auto status = future.wait_for(1s);
      if ( status == std::future_status::ready ) {
        RCLCPP_INFO(this->get_logger(), "Callback called back!");
      };
  };
};

class ProblemExampleNonRosClassB { // non-ros class
  public:
  explicit ProblemExampleNonRosClassB() {};

  //whatever 
  void random_func() {
    ProblemExampleClassA classa;
    //how to call classa.something_to_call();
    //continue with the program from here onwards, but return to this class in the future if needed
  };
};
edit retag flag offensive close merge delete