0
$\begingroup$

I have a class named UarmControl that inherits the Node class. Inside my UarmControl class, I want to send the node it self to another class named Uarm that I want to create inside my constructor. The constructor of the Uarm class looks like this:

Uarm::Uarm(rclcpp::Node::SharedPtr& node, std::string &robot_ip)

Why is it not working to just put "this" as shown below?

class UarmControl : public rclcpp::Node
{
  public:
    UarmControl() : Node("uarm_control")
    {
        timer_ = this->create_wall_timer(
        10ms, std::bind(&UarmControl::timer_callback, this));

    std::string robot_ip = "192.168.8.167";
    Uarm uarm(this, robot_ip);
    }
}

EDIT: This is the error I'm getting:

error: no matching function for call to ‘Uarm::Uarm(UarmControl*, std::string&)’
   34 |     Uarm uarm(this, robot_ip);

note:   no known conversion for argument 1 from ‘UarmControl*’ to ‘rclcpp::Node::SharedPtr&’ {aka ‘std::shared_ptr<rclcpp::Node>&’}
    6 |     Uarm(rclcpp::Node::SharedPtr& node, std::string &robot_ip);

So it seems that "this" does not refer to the node. I thought it would work because I read this on the ROS2 Humble MinimalPublisher C++ example page: enter image description here

My goal is to replace the following code, so that the Uarm object is created within the node class. In this way I can access the Uarm functions inside my node...

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  std::shared_ptr<rclcpp::Node> node = std::make_shared<UarmControl>();
  std::string robot_ip = "192.168.8.167";
  Uarm uarm(node, robot_ip);
  while(1)
  {
  rclcpp::spin_some(node);
  uarm.set_joint_vel(q_dot);
  }
  rclcpp::shutdown();
  return 0;
}
$\endgroup$
3
  • $\begingroup$ Can you share the error message and explain what you mean by 'not working'? $\endgroup$
    – Robotawi
    Commented Jan 22 at 22:48
  • $\begingroup$ did you really mean to say parsing? $\endgroup$
    – jsotola
    Commented Jan 23 at 1:24
  • $\begingroup$ Sorry for the confusion. Tried to make the post a bit clearer now. $\endgroup$
    – eidetech
    Commented Jan 23 at 8:36

2 Answers 2

0
$\begingroup$

Usually when you pass the instance of a node you do it for specific reasons. If this is the case you can pass the specific node interface, you can define the constructor in a similar way:

void Uarm(                        rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr node_timers,
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source,
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables)

This interfaces can be retrieved with the methods:

this->get_node_base_interface(),
this->get_node_clock_interface(),
this->get_node_graph_interface(),
this->get_node_logging_interface(),
this->get_node_parameters_interface(),
this->get_node_services_interface(),
this->get_node_timers_interface(),
this->get_node_time_source_interface(),
this->get_node_topics_interface(),
 this->get_node_waitables_interface()

In this way you can pass only the instances you really need

$\endgroup$
2
  • $\begingroup$ Ok, but how should I pass that in the UarmControl class? $\endgroup$
    – eidetech
    Commented Jan 23 at 10:03
  • $\begingroup$ In the constructor of the class, I wrote you the declaration $\endgroup$ Commented Feb 5 at 12:42
0
$\begingroup$

From the answer here (rizkymille's answer):

You need to get the node pointer and pass it to another class. But if you do this in the class constructor, a bad_weak_ptr error will always show up. You can prevent this by initiating the class in callback.

I'm gonna use ClassA and ClassB example above, say you want to extend the node to ClassB to use ClassB functions from ClassA. Here's the header code of ClassB:

class ClassB {
public:
   ClassB(rclcpp::Node::SharedPtr node); // constructor

   // your code here

 private:
   rclcpp::Node::SharedPtr node_;

   // your code here

and here's the definition code of ClassB:

// constructor
ClassB::ClassB(rclcpp::Node::SharedPtr node) : node_(node) {

   // your code here
}

Then in ClassA file:

class ClassA : public rclcpp::Node {
  public:
    ClassA() : Node("class_a") {

      // your code here

      // use one-time timer to initiate class B 
      timer = this->create_wall_timer(500ms, std::bind(&ClassA::initialization, this));
    }

  private:

    rclcpp::TimerBase::SharedPtr timer;

    std::shared_ptr<ClassB> class_b;

    void initialization() {
      // get node pointer, pass into Class B
      class_b = std::make_shared<ClassB>(shared_from_this());

      // replace timer with loop callback after initialization finished
      timer = this->create_wall_timer(500ms, std::bind(&UsingLibCpp::timer_callback, this)); 
    }

    void timer_callback() {
      // your code here

      // use Class B function
      class_b->class_b_function();
    }
$\endgroup$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.