ROS NodeHandle 命名空间 参数读取

ROS NodeHandle 命名空间 参数读取

  • 概述
  • 命名空间
    • 全局
    • 局部
    • 特别地
    • 测试用
  • 参数读取
    • ros::param::param
    • nh_.param
  • 小结

概述

将命名空间相关知识梳理一下,最近在命名空间上吃了大亏,浪费了很多时间,特别是涉及到后面的参数读取以及订阅发布Topic。

命名空间

全局

全局命名空间,就是默认路jin为全局的命名空间,和绝对路jin的概念相仿。定义时需要注意下面的几点。

1.node不带任何命名空间
ros::NodeHandle node;

2.此时参数路jin均为"imu_mti/imu_mti_sequence"
node.param<int>("imu_mti/imu_mti_sequence", sequence, 100);
ros::param::param<int>("imu_mti/imu_mti_sequence", sequence, 100);

3.此时订阅的topic为"imu"
sub =new message_filters::Subscriber<sensor_msgs::Imu>(node, “imu”, 100);

局部

局部命名空间,就是默认路jin为局部的命名空间,和相对路jin的概念相仿。定义时需要注意下面的几点。

1.node带有命名空间
ros::NodeHandle node("/myname");

2.此时参数路jin为"/myname"+"imu_mti/imu_mti_sequence"-> "/myname/imu_mti/imu_mti_sequence"
node.param<int>("imu_mti/imu_mti_sequence", sequence, 100);

3.此时参数路jin为"imu_mti/imu_mti_sequence",不受node影响
ros::param::param<int>("imu_mti/imu_mti_sequence", sequence, 100);

3.此时订阅的topic为"/myname"+"imu"->"/myname/imu"
sub =new message_filters::Subscriber<sensor_msgs::Imu>(node, “imu”, 100);

特别地

特别地,下面的 ~ 表示当前节点的命名空间

1.node带有命名空间"~"= 当前节点的命名空间,以节点命名,类似于"linux下面的~"
ros::NodeHandle node("~");

2.此时参数路jin为"~"+"imu_mti/imu_mti_sequence"-> "~/imu_mti/imu_mti_sequence"
node.param<int>("imu_mti/imu_mti_sequence", sequence, 100);

3.此时参数路jin为"imu_mti/imu_mti_sequence",不受node影响
ros::param::param<int>("imu_mti/imu_mti_sequence", sequence, 100);

4.此时参数路jin为"~imu_mti/imu_mti_sequence",不受node影响
ros::param::param<int>("~imu_mti/imu_mti_sequence", sequence, 100);

5.此时订阅的topic为"~"+"imu"->"~/imu"
sub =new message_filters::Subscriber<sensor_msgs::Imu>(node, “imu”, 100);

测试用

可以使用下面的代码获取当前node所使用的的命名空间,

	ros::NodeHandle node;
	ROS_INFO("%s",node.getNamespace().c_str());

不同情况下输出为

  ros::NodeHandle node;
	ROS_INFO("%s",node.getNamespace().c_str());//   /全局命名空间

  ros::NodeHandle node1("~");
	ROS_INFO("%s",node1.getNamespace().c_str());//  /nlink_sub节点名称作为命名空间

  ros::NodeHandle node2("/myname");
	ROS_INFO("%s",node2.getNamespace().c_str());//   /myname自定义命名空间

对应输出为

[ INFO] [1595406961.125790392]: /
[ INFO] [1595406961.125846145]: /nlink_sub
[ INFO] [1595406961.125868992]: /myname

参数读取

首先明确,ROS下的参数服务器的参数都是有具体的路jin,如果路jin不对,是不能准确找到参数的,例如下面,在使用时,一定要确保参数目录一致,才能正确读取参数。

 * /sbg_ellipseN/aidingAssignment/gnss1ModulePortAssignment: 5
 * /sbg_ellipseN/aidingAssignment/gnss1ModuleSyncAssignment: 5
 * /sbg_ellipseN/aidingAssignment/odometerPinAssignment: 0
 * /sbg_ellipseN/aidingAssignment/rtcmPortAssignment: 255
 * /sbg_ellipseN/confWithRos: True
 * /sbg_ellipseN/gnss/gnss_model_id: 101
 * /sbg_ellipseN/gnss/hdtRejectMode: 1
 * /sbg_ellipseN/gnss/posRejectMode: 1

通常使用的参数获取方法有,这里列举两个可以设置默认值的,使用比较安全。

ros::param::param

这种获取参数的方式与当前的node无关,可以自己设定具体的路jin。

/** \brief Assign value from parameter server, with default.
 *
 * This method tries to retrieve the indicated parameter value from the
 * parameter server, storing the result in param_val.  If the value
 * cannot be retrieved from the server, default_val is used instead.
 *
 * \param param_name The key to be searched on the parameter server.
 * \param[out] param_val Storage for the retrieved value.
 * \param default_val Value to use if the server doesn't contain this
 * parameter.
 * \return true if the parameter was retrieved from the server, false otherwise.
 * \throws InvalidNameException if the key is not a valid graph resource name
 */
template<typename T>
bool param(const std::string& param_name, T& param_val, const T& default_val)
{
  if (has(param_name))
  {
    if (get(param_name, param_val))
    {
      return true;
    }
  }

  param_val = default_val;
  return false;
}

具体使用时,这里的“~”表示当前节点默认命名空间,在参数服务器上获取参数时实际的目录里为node_name/port/mti_port
三个参数,第一个表示参数路jin,第二个表示赋值变量,第三个表示默认参数值。

ros::param::param<std::string>("~port/mti_port", port_name_.mti_port, "mti");

nh_.param

这种获取参数与当前的node有关,具体的路jin需要加上node已有的路jin形成最终的路jin。

  /** \brief Assign value from parameter server, with default.
   *
   * This method tries to retrieve the indicated parameter value from the
   * parameter server, storing the result in param_val.  If the value
   * cannot be retrieved from the server, default_val is used instead.
   *
   * \param param_name The key to be searched on the parameter server.
   * \param[out] param_val Storage for the retrieved value.
   * \param default_val Value to use if the server doesn't contain this
   * parameter.
   * \return true if the parameter was retrieved from the server, false otherwise.
   * \throws InvalidNameException If the parameter key begins with a tilde, or is an otherwise invalid graph resource name
   */
  template<typename T>
  bool param(const std::string& param_name, T& param_val, const T& default_val) const
  {
    if (hasParam(param_name))
    {
      if (getParam(param_name, param_val))
      {
        return true;
      }
    }

    param_val = default_val;
    return false;
  }

具体使用如下,这里的路jin实际为定义nh_时的命名空间加上port/MdVn_port,是一个相对的路jin。
三个参数,第一个表示参数路jin,第二个表示赋值变量,第三个表示默认参数值。

nh_.param<std::string>("port/MdVn_port", port_name_.MdVn_port, "MdVn");

如果定义下面的形式,

ros::NodeHandle nh_("myname");

那么参数目录为

"myname"+"port/MdVn_port" -> "myname/port/MdVn_port"

如果定义了nh_的命名空间,后面的sub以及pub都会受到影响,或者说与nh_有关的都会受到影响,例如

sub =new message_filters::Subscriber<sensor_msgs::Imu>(nh_, “imu”, 100);

实际订阅的topic为

"myname"+"imu" -> "myname/imu"

小结

使用参数、订阅Topic时一定要注意命名空间
一般使用形式如下

1.node不带任何命名空间
ros::NodeHandle node;

2.将参数路jin设置为默认命名空间"~imu_mti_sequence",使用ros::param::param,这个时候与node无关
ros::param::param<int>("~imu_mti_sequence", sequence, 100);

3.由于node不带任何命名空间,因此可以将订阅的topic设置为绝对路jin为"/imu"
sub =new message_filters::Subscriber<sensor_msgs::Imu>(node, “imu”, 100);

你可能感兴趣的:(ROS,linux,ubuntu)