Problems with rclcpp executor as class member.
The Problem (in short)
I am trying to write a large piece of code that needs to set up subscribers, look up transforms, and call spin_some, spin_once etc in the body of code. I am encountering a number of very vague and inconsistent crashes that I suspect are all tied back to the executor and how I'm using it. So, I am trying to establish the correct use of the executor as a class member, using the minimal compiling example below.
I'm using ROS2 Foxy for reference.
The Problem (in full)
Node executors are, in most examples I have found, used outside the body of the node, like so (from the ROS2 C++ subscriber tutorial):
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalNode>());
rclcpp::shutdown();
return 0;
}
I know that spin works under the hood by calling up an executor, assigning the node to it, and then spinning it. However I want to be able to call functions like spin
, spin_once
etc from within the body of the node. In the process of looking for a solution, I came up with this method:
#include <string>
#include "rclcpp/rclcpp.hpp"
class MinimalNode : public rclcpp::Node
{
rclcpp::executors::SingleThreadedExecutor executor;
public:
MinimalNode() : Node("minimal_node")
{
executor.add_node(this->get_node_base_interface());
executor.spin_some();
printf("Hello world\n");
executor.spin();
}
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
auto node_ptr = std::make_shared<MinimalNode>();
rclcpp::shutdown();
return 0;
}
Where the executor exists as a class member, the constructor adds the node interface, calls node spin_some
, spin
etc. This works, it compiles, runs, prints "Hello world" and then spins quietly until I kill it with Ctrl+C. However things go sideways from here. Remember, this minimal example roughly replicates a large body of code which I cannot share publically.
My questions are:
- Is this a legitimate way to use the executor and achieve the goal of having the node be able to call things like
spin
internally? I haven't seen this use case in any of the example ROS2 code I can find. If not, what is the proper way to do this? - If I comment out the
executor.add_node
line in this example, everything still works. But I'm not sure if it should, because how does the executor know what node it is supposed to spin? - In my larger body of code, this doesn't even work. I get a crash at the
executor.add_node
line, and the error message: "Node has already been added to an executor." Why don't I get that error with the minimal example? - In my larger body of code, it will compile and run ONLY if I comment out the
executor.add_node
line. But again, I don'tknow if this should work, and it only partially seems to work, because my node exists normally and doesn't stop atexecutor.spin();
- In my larger body of code, if I launch the node via launch file rather than via
ros2 run...
again ...
Hello M@t! I seem to be having a very similar problem to question 3. Did you manage to solve this?