• 如何理解ROS的ros::NodeHandle,学习ROS一年后的体会


    1, 一个节点(Node)可以有多个节点句柄(NodeHandle)

    虽然一般最多看见两个NodeHandle(e.g, nh和pnh),但是一个节点(Node)可以有多个节点句柄(NodeHandle),可以是一个,可以是两个,可以是三个,甚至更多,但是他们都指向同一个节点

    2, 节点句柄的名称任意

    节点句柄的名称任意,但一般约定俗成为nh(表示一般句柄)和pnhprivate_nh(表示私有句柄),nh是node handle的缩写。

    ros::NodeHandle nh;//ok
    ros::NodeHandle pnh;//ok
    ros::NodeHandle publisher_nh;//ok
    ros::NodeHandle subscriber_nh;//ok
    
    • 1
    • 2
    • 3
    • 4

    3, 节点句柄初始化主要的写法可以分为三类

    ros::NodeHandle nh;//普通句柄,通常用于topic和service的调用
    ros::NodeHandle nh("~");//私有句柄,通常用于参数的调用
    ros::NodeHandle nh("some_namespace");//可以这么用,但通常不用
    
    • 1
    • 2
    • 3

    因为话题和服务通常是多个节点共用的,所以一般用普通的初始化方式,这样A节点定义的话题,能够被B节点看到。
    而私有节点句柄通常将节点名称(用~表示)作为一个子命名空间(私有可以理解为:make it private to this node),这样便于管理参数,因为参数通常和节点是配套使用的,使用私有节点句柄可以避免名称冲突。比如,控制器A有PID参数(P,I,D),控制器B也有PID参数(P,I,D),那么如果仅查找P I D,那么就会有两个结果,造成混乱,而如果查找B:I,那么我就知道是B控制器的I参数。

    假设节点名称为node_name,节点所处的命名空间为node_namespace

    ros::init(argc, argv, "node_name");//所在的命名空间为node_namespace
    ros::NodeHandle nh_1;
    ros::NodeHandle nh_2("~");
    ros::NodeHandle nh_3("some_namespace");
    nh_1.param("param_name", param_name_variable, kDefaultParamName);
    //将参数服务器中有“param_name”名字的参数读取进来,
    //赋值给param_name_variable变量
    //如果这个参数不存在,那么将默认值kDefaultParamName赋值给param_name_variable变量
    nh_2.param("param_name", param_name_variable, kDefaultParamName);
    nh_3.param("param_name", param_name_variable, kDefaultParamName);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    节点句柄初始化方式ROS真正寻找(resolve)的参数
    ros::NodeHandle nh_1;/node_namespace/param_name
    ros::NodeHandle nh_2("~");/node_namespace/node_name/param_name
    ros::NodeHandle nh_3("some_namespace");/node_namespace/some_namespace/param_name

    4, 在类中声明节点句柄

    我现在遇到的节点,通常都是以类的形式编写,然后在主函数中实例化,
    类似于:

    class DemoNode{
    private:
      ros::NodeHandle nh_;
      
      ros::Publisher pub_;
      ros::Subscriber sub_;
      ros::Rate rate_;
    }
    
    DemoNode::DemoNode() :rate_(kDefaultHilFrequency) {
      ros::NodeHandle pnh("~");
    
      bool sensor_level_hil;
      std::string actuators_pub_topic;
      std::string hil_controls_sub_topic;
      pnh.param("actuators_pub_topic", actuators_pub_topic, std::string(mav_msgs::default_topics::COMMAND_ACTUATORS));
      pnh.param("hil_controls_sub_topic", hil_controls_sub_topic, kDefaultHilControlsSubTopic);
      pub_ = nh_.advertise<mav_msgs::Actuators>(actuators_pub_topic, 1);
      sub_ = nh_.subscribe(hil_controls_sub_topic, 1,&HilInterfaceNode::HilControlsCallback, this);
    }
    
    int main(int argc, char** argv) {
      ros::init(argc, argv, "this_is_a_node");
      DemoNode demo_node;
      ros::spin();
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    可以看到,节点句柄作为类的数据成员,私有节点句柄用来读取参数,普通节点句柄用来调用订阅和发布函数(access topic)。

    参考

    Accessing Private Names from a NodeHandle
    Node Handles, Parameters, and Topics

  • 相关阅读:
    亚马逊的推广包括站内推广和站外推广
    大数据下一代变革之必研究数据湖技术Hudi原理实战双管齐下-后续
    golang 使用python脚本将pdf文件转为png图片
    前端CSS实现响应式TimeLine效果(附源码)
    19.前端笔记-CSS-显示隐藏元素
    Python飞机大战项目终篇(一步一步实现---最全笔记)
    【小程序源码】看成语猜古诗句好玩解闷小游戏
    SpringCloudAliBaba篇(三)之Ribbon负载均衡器
    vue Sts认证后直传图片到阿里云OSS
    《Spring Boot配置文件大揭秘:看懂 application.yaml 与 bootstrap.yaml 的不同》
  • 原文地址:https://blog.csdn.net/weixin_45910027/article/details/134436322