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

文章目录

    • 1, 一个节点(Node)可以有多个节点句柄(NodeHandle)
    • 2, 节点句柄的名称任意
    • 3, 节点句柄初始化主要的写法可以分为三类
    • 4, 在类中声明节点句柄
    • 参考

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

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

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

因为话题和服务通常是多个节点共用的,所以一般用普通的初始化方式,这样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);
节点句柄初始化方式 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;
}

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

参考

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

你可能感兴趣的:(ROS,机器人,自动驾驶)