Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce transform listener nodes #442

Merged
merged 3 commits into from
Sep 28, 2021
Merged

Reduce transform listener nodes #442

merged 3 commits into from
Sep 28, 2021

Conversation

gezp
Copy link
Contributor

@gezp gezp commented Jul 29, 2021

Signed-off-by: zhenpeng ge zhenpeng.ge@qq.com

As described in #440, I use new callback group and executor with dedicated thread so that we could avoid creating internal node which is overhead.

currently, i don't break the API, but i think the constructor TransformListener(tf2::BufferCore & buffer, bool spin_thread = true) need be deprecated, due to create internal Node.

the another constructor is enough to use like this.

tf_buffer_ = std::make_shared<tf2_ros::Buffer>(get_clock());
//case1: spin in dedicated thread (use new callback group and executor)
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_, shared_from_this(), true);
//case2: its on the application to spin
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_, shared_from_this(), false);

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
@gezp gezp changed the title reduce transform listener nodes Reduce transform listener nodes Jul 29, 2021
Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
@gezp
Copy link
Contributor Author

gezp commented Jul 29, 2021

i don't know how to fix the CI failures, i need some helps, thank you!

@SteveMacenski
Copy link
Contributor

16:34:21 KeyError: "The cache has no package named 'ros-rolling-rclcpp'"

Not your fault, I don't believe

callback_group_ = node_base_interface_->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive, false);
// Duplicate to modify option of subscription
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> options2 = options;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like you can do better than options2 here. How about tf_options and tf_static_options?

node, "/tf", qos, std::move(cb), options2);
message_subscription_tf_static_ = rclcpp::create_subscription<tf2_msgs::msg::TFMessage>(
node, "/tf_static", static_qos, std::move(static_cb), static_options2);
// Create executor with dedicated thread to spin.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A space here might be nice for a logical break between creating the subscribers and then setting up the executor

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
@SteveMacenski
Copy link
Contributor

SteveMacenski commented Aug 3, 2021

@tfoote I'd try to assign you as a reviewer if I had the permissions to do so 😄

Edit: Whoops, looks like @clalancette is the listed maintainer.

Copy link
Contributor

@tfoote tfoote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a quick read through this looks good. I haven't fully validated or tested it. But the internal node creation was a workaround for the lack of callback groups. Switching back to the dedicated thread with a callback group is a good step forward.

@SteveMacenski
Copy link
Contributor

@tfoote what are the next steps here? I'd looked over it again and I don't see any reason this wouldn't be functionally the same.

@gezp
Copy link
Contributor Author

gezp commented Sep 4, 2021

please review this PR, i need your suggestion, thank you! @clalancette @tfoote.

@ahcorde
Copy link
Contributor

ahcorde commented Sep 20, 2021

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@ros-discourse
Copy link

This pull request has been mentioned on ROS Discourse. There might be relevant details there:

https://discourse.ros.org/t/ros-2-tsc-meeting-minutes-2021-9-16/22372/1

@SteveMacenski
Copy link
Contributor

SteveMacenski commented Sep 27, 2021

@ahcorde any other action required for merging? Not that I'm a maintainer here, but I took a look and I see no issues that would pop up either.

@ahcorde ahcorde merged commit 6bc47ce into ros2:ros2 Sep 28, 2021

// Create executor with dedicated thread to spin.
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
executor_->add_callback_group(callback_group_, node_base_interface_);
Copy link
Member

@jacobperron jacobperron Nov 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this broke an existing use-case where we expect the node to have other callbacks processed, not just the the two subscriptions added here. E.g. previously I could write something like this:

#include <rclcpp/rclcpp.hpp>
#include <tf2_ros/buffer.h>
#include <tf2_ros/transform_listener.h>
#include <std_msgs/msg/string.hpp>

#include <iostream>
#include <memory>
#include <chrono>
#include <thread>

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

  auto node = std::make_shared<rclcpp::Node>("foo_node");

  auto callback = [](const std_msgs::msg::String & msg) {
    std::cerr << "Message received: " << msg.data << std::endl;
  };  
  auto sub = node->create_subscription<std_msgs::msg::String>("foo", 1, callback);

  tf2_ros::Buffer buffer(node->get_clock());
  tf2_ros::TransformListener listener(buffer, node, true);

  while (rclcpp::ok()) {
    // rclcpp::spin_some(node);
    std::this_thread::sleep_for(std::chrono::seconds(1));
  }
  rclcpp::shutdown();

  return 0;
}

Maybe assuming callbacks will be handled by the transform listener is a bad assumption, but the signature where we provide our own Node (and we set spin_thread=true) seems ill-defined.

Copy link
Contributor

@SteveMacenski SteveMacenski Nov 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my_node is never spun in this example -- how could the subscription receive messages? The spin_thread is w.r.t. the TF callbacks to isolate them from the rest of the system, its not there to process your own callbacks in your own application. That was the intent of this PR to make TF2's system decoupled from the application code. You should spin_some() in your while loop to resolve this issue (which you should have been doing before this PR anyway?). This PR is creating an executor / callback group for the TF internal needs to be processed, so that's not connected to your application subscriber using the default executor that you haven't called in the application example. 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong about what I think is happening; I will report back with a complete example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the code in my comment to be a compilable example. It appears that I can get the example to work if I uncomment the rclcpp::spin_some() call in the while-loop. IIRC, this would result in a runtime error previously. Should it be the new recommended approach?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes -- before I think it was a design error to have it spin for the user application too, that seems like a breakage in separation of concerns to have TF2 processing your execution model for your application. I would have assumed that it did what it is now doing and just spin a thread for TF2 to process its information internally. This was made because we want TF2 to process its own info and not be blocked or blocking other application callbacks & reducing the number of Node objects in complex stacks like Nav2.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it makes sense to not have users rely on the TransformListener executor, however the current change silently breaks anyone who was relying on this behavior (it took me a while to figure out why my callbacks were not being triggered). It would be nice if we could detect this scenario and warn users. At the very least, I think we should add a release note for ROS Humble.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100% agree

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not seem straight forward to add a warning, but I've added a release note in ros2/ros2_documentation#2127

@jacobperron
Copy link
Member

It might also be worth pointing out here that the Python implementation still follows the old logic of spinning on the entire node (instead of a callback group containing only the TF topics):

def run_func():
self.executor.add_node(self.node)
self.executor.spin()
self.executor.remove_node(self.node)

I can create an issue to track updating it as well.

jacobperron added a commit to ros2/ros2_documentation that referenced this pull request Nov 16, 2021
Related PR ros2/geometry2#442

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
clalancette pushed a commit to ros2/ros2_documentation that referenced this pull request Nov 18, 2021
Related PR ros2/geometry2#442

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
mergify bot pushed a commit to ros2/ros2_documentation that referenced this pull request Nov 18, 2021
Related PR ros2/geometry2#442

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
(cherry picked from commit d864ce8)
mergify bot pushed a commit to ros2/ros2_documentation that referenced this pull request Nov 18, 2021
Related PR ros2/geometry2#442

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
(cherry picked from commit d864ce8)
clalancette pushed a commit to ros2/ros2_documentation that referenced this pull request Nov 18, 2021
Related PR ros2/geometry2#442

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
(cherry picked from commit d864ce8)

Co-authored-by: Jacob Perron <jacob@openrobotics.org>
clalancette pushed a commit to ros2/ros2_documentation that referenced this pull request Nov 18, 2021
Related PR ros2/geometry2#442

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
(cherry picked from commit d864ce8)

Co-authored-by: Jacob Perron <jacob@openrobotics.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants