ros2
ros2 copied to clipboard
Getting state of LifecycleNode
I was trying to use ROS2 LifecycleNode as explained here: http://design.ros2.org/articles/node_lifecycle.html https://github.com/ros2/ros2/wiki/Managed-Nodes
I did some experiments and had a number issues, while trying to make it work.
I have ROS2 running on Ubuntu and a LifecycleNode in one thread. I want to request the state of that LifecycleNode from another thread.
Here is a code for that request:
https://gist.github.com/mc-android-developer/fda2634f1553d789c974237bde8db0b3
When I calling getState() function, it only works on certain conditions. Here are some working samples:
// Case#1 Works auto task = std::async(std::launch::async, [&node] { std::this_thread::sleep_for(1s); auto state = getState(); }); rclcpp::spin(node);
// Case#2 Works auto task = std::async(std::launch::async, [&node] { std::this_thread::sleep_for(1s); auto state = getState(); }); auto timer = node->create_wall_timer(1s, [&node]() { std::cout// Case#3 Works rclcpp::executors::SingleThreadedExecutor controllerExecutor; controllerExecutor.add_node(node); auto spinLambda= [&controllerExecutor]() { controllerExecutor.spin(); }; std::thread nodeExecutionThread(spinLambda); auto state = getState(); nodeExecutionThread.join();and some NOT working samples:
// Case#9 NOT Works auto timer = node->create_wall_timer(1s, [&node]() { std::this_thread::sleep_for(1s); auto state = getState(); }); rclcpp::spin(node);// Case#10 NOT Works auto timer = node->create_wall_timer(1s, [&node]() { std::async(std::launch::async, [&node] { std::this_thread::sleep_for(1s); auto state = getState(); }); }); rclcpp::spin(node);// Case#11 NOT Works rclcpp::executors::SingleThreadedExecutor controllerExecutor; controllerExecutor.add_node(node); auto spinLambda= [&controllerExecutor]() { controllerExecutor.spin(); }; auto timer = node->create_wall_timer(3s, [&node]() { auto state = getState(); }); std::thread nodeExecutionThread(spinLambda); nodeExecutionThread.join();// Case#12 NOT Works rclcpp::executors::SingleThreadedExecutor controllerExecutor; controllerExecutor.add_node(node); auto spinLambda= [&controllerExecutor]() { controllerExecutor.spin(); }; auto timer = node->create_wall_timer(1s, [&node]() { std::async(std::launch::async, [&node] { std::this_thread::sleep_for(1s); auto state = getState(); }); }); std::thread nodeExecutionThread(spinLambda); nodeExecutionThread.join();'NOT Works' mean that getState() function comes to line // EXIT BY TIMEOUT
Could you help me to understand why cases 9-16 do not work? Is ROS2 designed to work this way OR it's an issue?
thanks for reporting such a verbose feedback. I haven't had time to look at every case in detail, but what I believe is happening (at least for case 9-10) is that you essentially try to call spin
within one spin
execution.
That is, your timer callback gets executed within your first round of spin
and you wait for your service within this callback. However, this service would need yet another call to spin
in order to get executed. For this second round of spin
, your timer callback has to return first.
You experience this behavior your first cases where your spin
and wait_for_service
always run in two separate threads.
Does this make sense what I am saying here?
I will look into the other cases in more detail once I have same spare cycles.
Thank you for the prompt response.
Yes, it makes sense for case#9, cos I request state in the same thread where spinning happens. In case#10 however, new thread is created inside the spinning thread and state is requested asynchronously from that new thread. The spinning thread is not delayed this way, isn't it?
I guess I fixed it for case#10. It should be something like:
auto timer = node->create_wall_timer(1s, [&node]() { static auto task = std::async(std::launch::async, [&node] { std::this_thread::sleep_for(1s); auto state = getState(); }); });
It works this way.