日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[转]ROS2 源码解析与实践 - Node

發布時間:2024/4/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转]ROS2 源码解析与实践 - Node 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載說明: 原文鏈接https://floodshao.github.io/2020/03/06/ros2-源碼解析與實踐-Node/
感謝原作者分享!如有侵權,請聯系我刪除,謝謝!

文章目錄

  • 1. Node定義
    • 1.1 ROS1與ROS2的定義區別
    • 1.2 Node.hpp代碼
  • 2. 相關C++11的語法:
    • 2.1 繼承自std::enable_shared_from_this
    • 2.2 SharedPtr成員變量來自哪里?
    • 2.3 using關鍵字
    • 2.4 刪除拷貝構造函數
    • 2.5 `__attribute__`
    • 2.6 explicit
  • 3. 創建pubsub實例
    • 3.1 創建pkg
    • 3.2 簡單的publisher node
    • 3.3 CMakeLists.txt
    • 3.4 package.xml
    • 3.5 編譯publisher node
    • 3.6 同樣的subscription node

1. Node定義

1.1 ROS1與ROS2的定義區別

  • ROS1和ROS2在功能上沒有區別(提供publish,subscribe,client,service等角色功能)
  • 生命周期:
    • ROS1中每個node的初始化都在一個main函數中,都對應一個進程。main函數中,通過初始化一個node得到一個node handle傳入自定義的node behavior構造函數來定義node行為
    • ROS2中每個node都繼承自一個基類rclcpp::Node,采用子類繼承的方式來暴露接口,這樣每個node的生命周期都得到有效的控制。(這個lifecycle定義在更底層rcl層)
  • ROS2 Node提供的創建服務接口,node實例繼承自基類,創建函數返回的都是SharedPtr:
    • rclcpp::Node->create_callback_group
    • rclcpp::Node->create_publisher
    • rclcpp::Node->create_subscription
    • rclcpp::Node->create_client
    • rclcpp::Node->create_service
    • rclcpp::Node->create_subnode
    • rclcpp::Node->create_wall_timer

1.2 Node.hpp代碼

//std::enable_shared_from_this<T> 能讓一個(類型是T,且已經被shared_ptr管理)安全地生成額外的std::shared_ptr。(定義于<memory>, 所以只要繼承rclcpp::Node就必須要添加memory) class Node : public std::enable_shared_from_this<Node> { public:RCLCPP_SMART_PTR_DEFINITIONS(Node) //"rclcpp/macros.hpp" 生成指針SharedPtr/// Create a new node with the specified name./*** \param[in] node_name Name of the node.* \param[in] options Additional options to control creation of the node.*/RCLCPP_PUBLIC //"rclcpp/visibility_control.hpp"explicit Node( //禁止隱式轉換的構造函數。const std::string & node_name,const NodeOptions & options = NodeOptions());/// Create a new node with the specified name./*** \param[in] node_name Name of the node.* \param[in] namespace_ Namespace of the node.* \param[in] options Additional options to control creation of the node.*/RCLCPP_PUBLICexplicit Node(const std::string & node_name,const std::string & namespace_,const NodeOptions & options = NodeOptions());RCLCPP_PUBLICvirtual ~Node();/// Get the name of the node./** \return The name of the node. */RCLCPP_PUBLICconst char * //Node::name一旦定義就不能改變get_name() const; //聲明const不可修改成員變量/// Get the namespace of the node./*** This namespace is the "node's" namespace, and therefore is not affected* by any sub-namespace's that may affect entities created with this instance.* Use get_effective_namespace() to get the full namespace used by entities.** \sa get_sub_namespace()* \sa get_effective_namespace()* \return The namespace of the node.*/RCLCPP_PUBLICconst char *get_namespace() const;/// Get the fully-qualified name of the node./*** The fully-qualified name includes the local namespace and name of the node.*/RCLCPP_PUBLICconst char *get_fully_qualified_name() const;/// Get the logger of the node./** \return The logger of the node. */RCLCPP_PUBLICrclcpp::Loggerget_logger() const;/// Create and return a callback group.RCLCPP_PUBLICrclcpp::callback_group::CallbackGroup::SharedPtrcreate_callback_group(rclcpp::callback_group::CallbackGroupType group_type);/// Return the list of callback groups in the node.RCLCPP_PUBLICconst std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &get_callback_groups() const;/// Create and return a Publisher./*** The rclcpp::QoS has several convenient constructors, including a* conversion constructor for size_t, which mimics older API's that* allows just a string and size_t to create a publisher.** For example, all of these cases will work:** cpp* pub = node->create_publisher<MsgT>("chatter", 10); // implicitly KeepLast* pub = node->create_publisher<MsgT>("chatter", QoS(10)); // implicitly KeepLast* pub = node->create_publisher<MsgT>("chatter", QoS(KeepLast(10)));* pub = node->create_publisher<MsgT>("chatter", QoS(KeepAll()));* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().volatile());* {* rclcpp::QoS custom_qos(KeepLast(10), rmw_qos_profile_sensor_data);* pub = node->create_publisher<MsgT>("chatter", custom_qos);* }* ** The publisher options may optionally be passed as the third argument for* any of the above cases.** \param[in] topic_name The topic for this publisher to publish on.* \param[in] qos The Quality of Service settings for the publisher.* \param[in] options Additional options for the created Publisher.* \return Shared pointer to the created publisher.*/template<typename MessageT,typename AllocatorT = std::allocator<void>,typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>>std::shared_ptr<PublisherT>create_publisher(const std::string & topic_name,const rclcpp::QoS & qos,const PublisherOptionsWithAllocator<AllocatorT> & options =PublisherOptionsWithAllocator<AllocatorT>());//publisherT指針,定義topic_name, qos和相關options/// Create and return a Subscription./*** \param[in] topic_name The topic to subscribe on.* \param[in] callback The user-defined callback function to receive a message* \param[in] qos_history_depth The depth of the subscription's incoming message queue.* \param[in] options Additional options for the creation of the Subscription.* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.* \return Shared pointer to the created subscription.*/template<typename MessageT,typename CallbackT,typename AllocatorT = std::allocator<void>,typename CallbackMessageT =typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<CallbackMessageT,AllocatorT>>std::shared_ptr<SubscriptionT>create_subscription(const std::string & topic_name,const rclcpp::QoS & qos,CallbackT && callback,const SubscriptionOptionsWithAllocator<AllocatorT> & options =SubscriptionOptionsWithAllocator<AllocatorT>(),typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (MessageMemoryStrategyT::create_default()));//sub消息指針,qos,相關triger callback, options/// Create a timer./*** \param[in] period Time interval between triggers of the callback.* \param[in] callback User-defined callback function.* \param[in] group Callback group to execute this timer's callback in.*/template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>typename rclcpp::WallTimer<CallbackT>::SharedPtrcreate_wall_timer(std::chrono::duration<DurationRepT, DurationT> period,CallbackT callback,rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);//timer定時器,定時區間period,trigger callback//service和client/* Create and return a Client. */template<typename ServiceT>typename rclcpp::Client<ServiceT>::SharedPtrcreate_client(const std::string & service_name,const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);/* Create and return a Service. */template<typename ServiceT, typename CallbackT>typename rclcpp::Service<ServiceT>::SharedPtrcreate_service(const std::string & service_name,CallbackT && callback,const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);//參數設置部分RCLCPP_PUBLICconst rclcpp::ParameterValue &declare_parameter(const std::string & name,const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =rcl_interfaces::msg::ParameterDescriptor(),bool ignore_override = false);//泛型編程重載函數1 template<typename ParameterT>autodeclare_parameter(const std::string & name,const ParameterT & default_value,const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =rcl_interfaces::msg::ParameterDescriptor(),bool ignore_override = false);//重載2 template<typename ParameterT>std::vector<ParameterT>declare_parameters(const std::string & namespace_,const std::map<std::string, ParameterT> & parameters,bool ignore_overrides = false);//重載3 template<typename ParameterT>std::vector<ParameterT>declare_parameters(const std::string & namespace_,const std::map<std::string,std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>> & parameters,bool ignore_overrides = false);//刪除parameter RCLCPP_PUBLIC void undeclare_parameter(const std::string & name);RCLCPP_PUBLIC bool has_parameter(const std::string & name) const;RCLCPP_PUBLIC rcl_interfaces::msg::SetParametersResult set_parameter(const rclcpp::Parameter & parameter);RCLCPP_PUBLIC std::vector<rcl_interfaces::msg::SetParametersResult> set_parameters(const std::vector<rclcpp::Parameter> & parameters);RCLCPP_PUBLICrcl_interfaces::msg::SetParametersResultset_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);... //相關parameters的重載函數非常多。不列舉了//成員變量 protected:/// Construct a sub-node, which will extend the namespace of all entities created with it./*** \sa create_sub_node()** \param[in] other The node from which a new sub-node is created.* \param[in] sub_namespace The sub-namespace of the sub-node.*/RCLCPP_PUBLICNode(const Node & other,const std::string & sub_namespace);//私有成員變量 private:RCLCPP_DISABLE_COPY(Node) //刪除拷貝構造函數RCLCPP_PUBLICboolgroup_in_node(callback_group::CallbackGroup::SharedPtr group);rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_;rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;rclcpp::node_interfaces::NodeTimersInterface::SharedPtr node_timers_;rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_;rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_;rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;const rclcpp::NodeOptions node_options_;const std::string sub_namespace_;const std::string effective_namespace_; };

2. 相關C++11的語法:

2.1 繼承自std::enable_shared_from_this

參考鏈接: https://blog.csdn.net/fm_VAE/article/details/79660768

在智能指針的使用過程中我們會遇到這樣一種情況,我們在類的成員函數調用某一個函數,而該函數需要傳遞一個當前對象的智能指針作為參數時,我們需要能夠在成員函數中獲得自己的智能指針。傳遞這個智能指針可以增加指針的引用次數,放置在函數執行的過程中,對象被釋放而引發引用錯誤。
但是我們不能在類中使用this構建一個這樣的shared_ptr, 不是成員函數的shared_ptr是在棧中生成的,一旦超出作用域,shared_ptr被析構,會導致這個對象本身的this被析構,從而導致致命錯誤。

為了解決這個問題,在c++11中提供了enable_shared_from_this這個模板類。他提供了一個shared_from_this方法返回自己的智能指針。而這個返回的shared_from_this是基類成員變量,會在返回的過程中增加指針的引用次數。

注意這個shared_from_this()必須要等待構造函數將對象構造完成之后才能返回。

2.2 SharedPtr成員變量來自哪里?

出現在RCLCPP_SMART_PTR_DEFINITIONS(Node)
定義如下:

#define RCLCPP_SMART_PTR_DEFINITIONS(...) \RCLCPP_SHARED_PTR_DEFINITIONS(__VA_ARGS__) \RCLCPP_WEAK_PTR_DEFINITIONS(__VA_ARGS__) \RCLCPP_UNIQUE_PTR_DEFINITIONS(__VA_ARGS__)#define RCLCPP_SHARED_PTR_DEFINITIONS(...) \__RCLCPP_SHARED_PTR_ALIAS(__VA_ARGS__) \__RCLCPP_MAKE_SHARED_DEFINITION(__VA_ARGS__)#define __RCLCPP_SHARED_PTR_ALIAS(...) \using SharedPtr = std::shared_ptr<__VA_ARGS__>; \using ConstSharedPtr = std::shared_ptr<const __VA_ARGS__>;

這里都是宏定義,最終落在using SharedPtr = std::shared_ptr<VA_ARGS>等定義。在這里SharedPtr就是shared_ptr<VA_ARGS>的別名。

注意這里的SharedPtr。在看代碼的時候經常會發現有如下:

rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;

你就會發現說這個類里邊沒有定義SharedPtr這個成員變量啊,這個是怎么來的。你去看源碼的時候就會發現每一個基類都會有RCLCPP_SMART_PTR_DEFINITIONS(T)這個宏定義,找到最末端就會發現SharedPtr定義在這里,然后還是public成員變量。

這里就留了一個疑問?所有的基類都繼承自std::enable_shared_from_this,說明就提供了一個方法shared_from_this()方法返回一個這個對象的指針。那為什么還要重新創建一個SharedPtr對象。

2.3 using關鍵字

在c++11中using的三種用法:https://blog.csdn.net/shift_wwx/article/details/78742459

  • 命名空間的使用
  • 在子類中引用基類的成員
  • class T5Base { public:T5Base() :value(55) {}virtual ~T5Base() {}void test1() { cout << "T5Base test1..." << endl; } protected:int value; };class T5Derived : private T5Base { //私有繼承,成員變量在子類中全部轉為private.。那么在public中如何訪問基類成員。 public://using T5Base::test1; //using T5Base::value;void test2() { cout << "value is " << value << endl; } }; ———————————————— 版權聲明:本文為CSDN博主「私房菜」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/shift_wwx/article/details/78742459
  • 別名指定,類似于typedef。相比于typedef,using很容易區分一個別名(尤其是函數指針)。
  • 2.4 刪除拷貝構造函數

    #define RCLCPP_DISABLE_COPY (...) __VA_ARGS__(const __VA_ARGS__ &) = delete; \__VA_ARGS__ & operator=(const __VA_ARGS__ &) = delete;

    C++11則使用delete關鍵字顯式指示編譯器不生成函數的默認版本。
    https://blog.csdn.net/u012333003/article/details/25299939

    2.5 __attribute__

    __attribute__可以設置函數屬性(FunctionAttribute)、變量屬性(Variable Attribute)和類型屬性(Type Attribute). 函數屬性可以幫助開發者把一些特性添加到函數聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大。也很容易同非GNU應用程序做到兼容之功效。

    出現在RCLCPP_PUBLIC等定義中(visibility_control.hpp) https://gcc.gnu.org/wiki/Visibility
    語法格式為__attribute__ ((attribute-list))

    在C語言中,可以使用static關鍵字限制符號(函數或變量)只對當前的文件可見,即,static對符號的限制在單個文件級別。而共享庫(或動態庫)可能包含一個或多個文件,如何將符號限制在庫文件(模塊)的級別,大多數鏈接器提供了將一個模塊的所有符號進行隱藏或導出的方法,但這樣對符號的控制會缺乏靈活性,因此,還有一些額外的工作需要我們來處理。(在GCC 4.0下)

    https://blog.csdn.net/zdragon2002/article/details/6061962
    https://blog.csdn.net/delphiwcdj/article/details/45225889

    在編譯一個大型的動態鏈接庫的時候,選擇不同的鏈接方式-fvisibility=default可以決定動態鏈接庫向外暴露哪些接口。
    而使用宏定義來實現visibility可以方便代碼在不同平臺上遷移。

    所以在(visibility_control.hpp)中進行如下定義:

    #if defined _WIN32 || defined __CYGWIN__ //針對win平臺#ifdef __GNUC__#define RCLCPP_EXPORT __attribute__ ((dllexport))#define RCLCPP_IMPORT __attribute__ ((dllimport))#else#define RCLCPP_EXPORT __declspec(dllexport)#define RCLCPP_IMPORT __declspec(dllimport)#endif#ifdef RCLCPP_BUILDING_LIBRARY#define RCLCPP_PUBLIC RCLCPP_EXPORT#else#define RCLCPP_PUBLIC RCLCPP_IMPORT#endif#define RCLCPP_PUBLIC_TYPE RCLCPP_PUBLIC#define RCLCPP_LOCAL #else //針對Linux平臺#define RCLCPP_EXPORT __attribute__ ((visibility("default"))) //設置全部可見,鏈接庫接口暴露#define RCLCPP_IMPORT#if __GNUC__ >= 4 //編譯器GCC是4.0版本以上#define RCLCPP_PUBLIC __attribute__ ((visibility("default")))#define RCLCPP_LOCAL __attribute__ ((visibility("hidden"))) //連接庫接口隱藏#else //GCC4.0版本一下不支持visibility control,那就只能全部暴露出去了(因為代碼里應該也沒有相關的static聲明)#define RCLCPP_PUBLIC #define RCLCPP_LOCAL#endif#define RCLCPP_PUBLIC_TYPE #endif

    2.6 explicit

    在C++中,explicit關鍵字用來修飾類的構造函數,被修飾的構造函數的類,不能發生相應的隱式類型轉換,只能以顯示的方式進行類型轉換。
    也就是說如果一個構造函數被聲明了explicit,那么不能隱式的轉換成拷貝構造函數

    class Circle { public: Circle(double r) : R(r) {} Circle(int x, int y = 0) : X(x), Y(y) {} Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {} private: double R; int X; int Y; }; int _tmain(int argc, _TCHAR* argv[]) { //發生隱式類型轉換 //編譯器會將它變成如下代碼 //tmp = Circle(1.23) //Circle A(tmp); //tmp.~Circle(); Circle A = 1.23; //如果構造函數變成: // explicit Circle(double r) : R(r) {} // 那個上邊這一句就會報錯,不能隱式轉化拷貝構造函數。//注意是int型的,調用的是Circle(int x, int y = 0) //它雖然有2個參數,但后一個有默認值,任然能發生隱式轉換 Circle B = 123; //這個算隱式調用了拷貝構造函數 Circle C = A; return 0; }

    3. 創建pubsub實例

    3.1 創建pkg

  • 創建workspace ~/ros2_ws/src
  • 在~/ros2_ws/src下創建pkg
  • ros2 pkg create --build-type ament_cmake cpp_pubsub # 基本方法是 ros2 pkg create --build-type [cmake, ament_cmake] pkg-name # --help 訪問幫助文檔
  • 在~/ros2_ws/src/cpp_pubsub下會創建pkg樹
  • -include -src -CMakeLists.txt -package.xml
  • 在cpp_pubsub/src下創建文件
  • 3.2 簡單的publisher node

    //published_member_function.cpp #include <chrono> #include <memory>#include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp"using namespace std::chrono_literals;/* This example creates a subclass of Node and uses std::bind() to register a * member function as a callback from the timer. */class MinimalPublisher : public rclcpp::Node {public:MinimalPublisher(): Node("minimal_publisher"), count_(0){publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);timer_ = this->create_wall_timer(500ms, std::bind(&MinimalPublisher::timer_callback, this));}private:void timer_callback(){auto message = std_msgs::msg::String();message.data = "Hello, world! " + std::to_string(count_++);RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());publisher_->publish(message);}rclcpp::TimerBase::SharedPtr timer_;rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;size_t count_; };//主函數 int main(int argc, char * argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<MinimalPublisher>()); rclcpp::shutdown(); return 0; }
  • c++11中std::bind()這個方法定義在中,用來實現函數轉發器,廣泛用于泛型編程。看一下源碼定義:
  • template< class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); - f是可調用對象callable,(函數對象、指向函數指針、到函數引用、指向成員函數指針或指向數據成員指針) - args是要綁定的參數列表。
  • 注意在主函數中已經沒有顯示的創建node(ros1中是顯示的創建node handle),而是生成一個MinimalPublisher的對象進入spin。
  • std::make_shared(Args& …args)。調用class T的構造函數,并返回一個std::shared_ptr,同時use_count+1。
  • 3.3 CMakeLists.txt

    CMakeLists中要添加dependencies和相關的編譯可執行文件

    cmake_minimum_required(VERSION 3.5) project(cpp_pubsub)# Default to C++14 if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 14) endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic) endif()find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED)add_executable(talker src/publisher_member_function.cpp) ament_target_dependencies(talker rclcpp std_msgs)install(TARGETStalkerDESTINATION lib/${PROJECT_NAME})ament_package()

    3.4 package.xml

    <exec_depend>rclcpp</exec_depend> <exec_depend>std_msgs</exec_depend>

    3.5 編譯publisher node

  • 在ros2_ws/下編譯
  • colcon build 編譯ros2_ws/src下的所有pkg
  • colcon build --packages-select <pkg—name> 編譯單獨的pkg
  • 目前(2020.3)還沒有提供類似于catkin clean這樣的清理編譯空間的命令,想要清理的話只能手動刪除install, log, build文件
  • 編譯得到的可執行文件在/build/cpp_pubsub/talker,可以直接執行可執行文件,不用使用ros2 run
  • 如果要使用ros2,和ros1一樣要執行環境變量操作source ros2_ws/install/setup.bash。 查看ros2尋址的所有pkg ros2 pkg list
  • 運行ros2 run cpp_pubsub talker
  • 3.6 同樣的subscription node

    //subscribe_member_function.cpp #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" using std::placeholders::_1;class MinimalSubscriber : public rclcpp::Node {public:MinimalSubscriber(): Node("minimal_subscriber"){subscription_ = this->create_subscription<std_msgs::msg::String>("topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));}private:void topic_callback(const std_msgs::msg::String::SharedPtr msg) const{RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());}rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_; };int main(int argc, char * argv[]) {rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<MinimalSubscriber>());rclcpp::shutdown();return 0; }

    需要注意的是不管是publisher還是subscription的構造過程中,QoS不能省了。頂層的QoS可以理解為data stream buffer,在ros1中也有相關的定義,但是因為ros2的底層是DDS,所以QoS必須定義。

    std::placeholder::_1一個占位符,為什么要使用這個?
    std::bind()綁定類內成員函數:

  • 綁定的成員函數不能有重載,bind函數只能通過函數名來識別函數
  • 綁定類內成員函數,首先要傳遞對象指針this,然后通過占位符_1來添加傳遞的參數,這里也就是msg。
  • bind本身是一種延遲計算的思想。
  • 那么這里就涉及到這個callback到底什么時候在調用呢。
  • std::bind()返回的是一個函數未指定類型的函數對象,具體返回什么類型決定于可調用函數f。
  • 總結

    以上是生活随笔為你收集整理的[转]ROS2 源码解析与实践 - Node的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。