将命名空间相关知识梳理一下,最近在命名空间上吃了大亏,浪费了很多时间,特别是涉及到后面的参数读取以及订阅发布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
通常使用的参数获取方法有,这里列举两个可以设置默认值的,使用比较安全。
这种获取参数的方式与当前的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");
这种获取参数与当前的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);