ros2多线程 Callback Groups
-
系统版本:humble
问题:希望通过多线程同时运行两个回调函数,但是实际上并不运行
代码:#include <chrono> #include <memory> #include <rclcpp/rclcpp.hpp> #include "std_msgs/msg/int32.hpp" using namespace std::chrono_literals; class MultiThreadedPublisher : public rclcpp::Node { public: MultiThreadedPublisher() : Node("multi_threaded_publisher") { // // 声明回调组 rclcpp::CallbackGroup::SharedPtr callback_group; rclcpp::CallbackGroup::SharedPtr callback_group_2; // // 实例化回调组 callback_group = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); callback_group_2 = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); // callback_group = nullptr; timer1_ = this->create_wall_timer(5000ms, std::bind(&MultiThreadedPublisher::publish_message1, this), callback_group); timer2_ = this->create_wall_timer(1000ms, std::bind(&MultiThreadedPublisher::publish_message2, this), callback_group_2); } private: void publish_message1() { RCLCPP_INFO(this->get_logger(), "Publishing on topic1: '%d'", 1); } void publish_message2() { RCLCPP_INFO(this->get_logger(), "Publishing on topic2: '%d'", 2); } rclcpp::TimerBase::SharedPtr timer1_; rclcpp::TimerBase::SharedPtr timer2_; }; int main(int argc, char *argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<MultiThreadedPublisher>(); // 使用多线程执行器 rclcpp::executors::MultiThreadedExecutor executor; executor.add_node(node); executor.spin(); rclcpp::shutdown(); return 0; }
-
在您的代码中,您已经正确地设置了两个独立的回调组,并将它们分别绑定到不同的定时器回调上。但是,有一些小问题和潜在的误解需要澄清:
-
回调组的类型:您使用了
rclcpp::CallbackGroupType::MutuallyExclusive
,这意味着尽管回调在不同的组中,但它们在同一个线程中顺序执行。如果您希望每个回调在不同的线程中并行执行,应该使用rclcpp::CallbackGroupType::Reentrant
或rclcpp::CallbackGroupType::Async
。然而,对于定时器和大多数ROS 2节点,通常推荐使用rclcpp::CallbackGroupType::Reentrant
,因为它允许回调在多个线程中安全地被调用,但同一个回调组的回调不会并发执行。 -
回调的实际执行:您的回调函数实际上是在打印日志,而不是发布消息(尽管函数名暗示了发布消息)。如果您的目的是测试多线程行为,这并不影响,但如果您计划在生产代码中使用,请确保回调执行的是您预期的操作。
-
日志输出:由于日志输出可能不是线程安全的(尤其是在不同线程中同时写入同一个日志时),您可能会看到日志输出的顺序与预期不符。这不一定表示多线程执行有问题,而是日志系统的行为。
让我们修改代码,将回调组类型更改为
rclcpp::CallbackGroupType::Reentrant
,并稍微调整代码格式:#include <chrono> #include <memory> #include <rclcpp/rclcpp.hpp> #include "std_msgs/msg/int32.hpp" using namespace std::chrono_literals; class MultiThreadedPublisher : public rclcpp::Node { public: MultiThreadedPublisher() : Node("multi_threaded_publisher") { // 声明并实例化回调组 rclcpp::CallbackGroup::SharedPtr callback_group = this->create_callback_group(rclcpp::CallbackGroupType::Reentrant); rclcpp::CallbackGroup::SharedPtr callback_group_2 = this->create_callback_group(rclcpp::CallbackGroupType::Reentrant); timer1_ = this->create_wall_timer( 5000ms, std::bind(&MultiThreadedPublisher::publish_message1, this), callback_group); timer2_ = this->create_wall_timer( 1000ms, std::bind(&MultiThreadedPublisher::publish_message2, this), callback_group_2); } private: void publish_message1() { RCLCPP_INFO(this->get_logger(), "Publishing on topic1: '%d'", 1); } void publish_message2() { RCLCPP_INFO(this->get_logger(), "Publishing on topic2: '%d'", 2); } rclcpp::TimerBase::SharedPtr timer1_; rclcpp::TimerBase::SharedPtr timer2_; }; int main(int argc, char *argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<MultiThreadedPublisher>(); // 使用多线程执行器 rclcpp::executors::MultiThreadedExecutor executor; executor.add_node(node); executor.spin(); rclcpp::shutdown(); return 0; }
现在,您的回调函数应该在不同的线程中并行执行(具体取决于执行器的线程池大小和执行器的调度策略)。如果您希望进一步控制线程的数量或行为,您可能需要调整执行器的配置。
以上为生成回答,仅供参考~
-
-
@小伊 仍然不能正常输出
-
如果你遇到了“仍然不能正常输出”的问题,这通常意味着某个系统、程序或设备没有按预期工作。为了帮助你解决这个问题,我需要更多的具体信息,因为“不能正常输出”可以涉及很多不同的领域和情况。以下是一些可能的情况和相应的解决步骤:
-
电脑程序或软件:
- 检查错误消息:查看程序是否给出了任何错误消息或代码。
- 更新软件:确保你的软件是最新版本,有时候问题可能由旧版本的bug引起。
- 重新安装:如果更新后问题依旧,尝试卸载后重新安装软件。
- 兼容性检查:确保你的操作系统与软件兼容。
- 查看日志:检查程序的日志文件,可能会有更多关于问题的详细信息。
-
打印机:
- 检查连接:确保打印机与电脑正确连接(USB、Wi-Fi等)。
- 墨盒/碳粉:检查墨盒或碳粉是否耗尽,需要更换。
- 打印队列:查看打印队列,确保没有卡住的打印任务。
- 驱动程序:确保打印机驱动程序是最新的,有时候旧的驱动程序会导致问题。
- 打印机设置:检查打印机设置,确保没有错误的配置。
-
电子设备(如电视、显示器):
- 检查输入源:确保设备已正确连接到正确的输入源(HDMI、AV、VGA等)。
- 电源和电缆:检查电源线和所有连接电缆是否牢固连接。
- 显示设置:在设备的菜单中检查显示设置,确保没有错误的配置。
- 重启设备:有时候简单的重启可以解决问题。
-
网站或在线服务:
- 网络连接:检查你的网络连接是否稳定。
- 浏览器问题:尝试使用不同的浏览器访问,看看问题是否依旧。
- 清除缓存和Cookie:有时候浏览器的缓存和Cookie可能导致显示问题。
- 服务状态:检查该网站或服务是否正在维护或遇到技术问题。
-
编程和代码:
- 调试信息:使用调试工具查看程序的执行过程和变量值。
- 日志输出:增加日志输出点,帮助追踪问题发生的位置。
- 检查代码:仔细检查相关代码,看是否有逻辑错误或遗漏。
- 编译器/解释器版本:确保你使用的编译器或解释器是支持你的代码的。
如果你能提供更多的上下文或详细描述你的问题,我可以给出更具体的建议。
以上为生成回答,仅供参考~
-
-
@chenxz 在 ros2多线程 Callback Groups 中说:
// // 声明回调组 rclcpp::CallbackGroup::SharedPtr callback_group; rclcpp::CallbackGroup::SharedPtr callback_group_2;
看起来没什么问题,运行结果看看,另外这两个定义提到成员变量处看看
-
@小鱼 非常感谢,按照您说的改了一下就可以运行了。方便问一下这是为什么吗,找了很多种方式,没想到改了两个成员变量的位置就行了。
#include <chrono> #include <memory> #include <rclcpp/rclcpp.hpp> #include "std_msgs/msg/int32.hpp" #include <thread> using namespace std::chrono_literals; class MultiThreadedPublisher : public rclcpp::Node { public: MultiThreadedPublisher() : Node("multi_threaded_publisher") { // // 实例化回调组 callback_group = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); callback_group_2 = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive); // callback_group = nullptr; timer1_ = this->create_wall_timer(std::chrono::milliseconds(5000), std::bind(&MultiThreadedPublisher::publish_message1, this), callback_group); timer2_ = this->create_wall_timer(std::chrono::milliseconds(1000), std::bind(&MultiThreadedPublisher::publish_message2, this), callback_group_2); } private: void publish_message1() { RCLCPP_INFO(this->get_logger(), "Publishing on topic1: '%d'", 1); } void publish_message2() { RCLCPP_INFO(this->get_logger(), "Publishing on topic2: '%d'", 2); } rclcpp::TimerBase::SharedPtr timer1_; rclcpp::TimerBase::SharedPtr timer2_; // // 声明回调组 rclcpp::CallbackGroup::SharedPtr callback_group; rclcpp::CallbackGroup::SharedPtr callback_group_2; }; int main(int argc, char *argv[]) { rclcpp::init(argc, argv); rclcpp::executors::MultiThreadedExecutor executor(rclcpp::ExecutorOptions(), 20, true); auto node = std::make_shared<MultiThreadedPublisher>(); executor.add_node(node); executor.spin(); rclcpp::shutdown(); return 0; }
-
@chenxz 如果可以就是一个基础问题,构造函数运行完,他们两个被释放了