ROS 简单理解

https://download.csdn.net/download/qq_30022867/11120759?utm_medium=distribute.pc_relevant_download.none-task-download-baidujs-9.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-download-baidujs-9.nonecase

书籍下载

 

 

一、图概念概述

    Nodes:节点,一个节点即为一个可执行文件,它可以通过ROS与其它节点进行通信。

    Messages:消息,消息是一种ROS数据类型,用于订阅或发布到一个话题。

    Topics:话题,节点可以发布消息到话题,也可以订阅话题以接收消息。

    Master:节点管理器,ROS名称服务 (比如帮助节点找到彼此)。

    rosout: ROS中相当于stdout/stderr。

    roscore: 主机+ rosout + 参数服务器 (参数服务器会在后面介绍)。
 

运行ros节点的方法:

一般有两种:

第一种:使用rosrun,在设置完环境变量后,可以使用包名来直接运行一个包内的节点。

用法:

$rosrun  [package_name]  [node_name]

注意:这种方法需要新打开一个终端 运行

$roscore

第二种:使用roslaunch

用法:

$roslaunch  [package]  [fliename.launch]

launch是个文件,用launch文件来运行程序相对于rosrun的优点有两个

<1>可以向程序传参

<2>可以同时运行多个节点

launch文件结构

<launch>
 <!--第1个节点-->
 	<node pkg="包名" type="包内可执行程序名字" name="节点名">
   	<!--注释内容-->
    		<para name="程序中的数值或布尔参数" value="" />
		<para name="程序中的字符串参数" value=" " type="str" />
		...
 	<node>
	...
 <!--第n个节点-->
	<node pkg="包名" type="包内可执行程序名字" name="节点名">
  	 <!--注释内容-->
    		...
	 <node>
</launch>

注意:

<1>包内可执行程序名由包内CMakeLists.txt控制生成。

<2>在每个可执行程序的main里都会有定义节点的语句,这里的节点名字只是用于代码编译,和launch文件的节点名不是一回事。

比如:

int main (int argc, char **argv)

{

 ros::init(argc,argv,"节点名字");

}

 

 

 二、ROS常用命令

命令重要度命令释义详细说明
roscore ★★★ ros+core

master(ROS名称服务) + rosout(日志记录) + parameter
server(参数管理)

rosrun ★★★ ros+run运行节点
 roslaunch  ★★★ ros+launch 运行多个节点或设置运行选项
rosclean★★☆  ros+clean 检查或删除ROS日志文件

 

三、创建一个工作空间

 前提:安装了相关的程序,比如:catkin

创建一个catkin工作空间

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make

这里 -p 是允许创建目录下的子目录的意思效果如下(我这里实在桌面创建的)

 

四、ROS发布者节点以及订阅者节点的编写

4.1、编写发布者节点

“节点”是连接到ROS网络的可执行文件的ROS术语。在这里,我们将创建一个将继续广播消息的发布者(“talker”)节点。
将目录更改为您在catkin工作区之前的教程中创建的beginner_tutorials包:

首先使用指令更改一下roscd的绝对路径:

$ . ~/catkin_ws/devel/setup.bash

然后使用

$ roscd beginner_tutorials

在beginner_tutorials包目录中创建一个src目录:

$ mkdir -p src

该目录将包含beginner_tutorials包的任何源文件。
在beginner_tutorials包中创建src / talker.cpp文件并在其中粘贴以下内容:

#include "ros/ros.h"          		
/*ros/ros.h是一个方便的包括,包括使用ROS系统最常见的公共部分所需的所有标题。*/

#include "std_msgs/String.h"
#include <sstream>
/*这包括std_msgs / String消息,该消息驻留在std_msgs包中。
这是从该包中的String.msg文件自动生成的标头。*/

int main(int argc, char **argv)
{
 
  ros::init(argc, argv, "talker");
/*初始化ROS。这允许ROS通过命令行进行名称重映射 - 现在不重要。这也是我们
  指定节点名称的地方。节点名称在正在运行的系统中必须是唯一的.
  此处使用的名称必须是基本名称,即。它不能有/在其中。*/
  
  ros::NodeHandle n;
/*为此进程的节点创建句柄。创建的第一个NodeHandle实际上将执行节点的初始化*/
  
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
/*告诉主人我们将在主题chatter中发布类型为std_msgs / String的消息。
  	这让主人告诉任何监听chatter节点的节点,我们将发布有关该主题的数据。
  	第二个参数是我们的发布队列的大小。在这种情况下,如果我们发布得太快,
  	它将在开始丢弃旧消息之前缓冲最多1000条消息。
  	NodeHandle::advertise()返回一个ros::Publisher对象,它有两个目的:
  	1)它包含一个publish()方法,它允许你将消息发布到它创建的主题上,以及
  	2)当它超出范围时,它会自动取消广告。*/
  
  ros::Rate loop_rate(10);
/*使用ros :: Rate对象可以指定要循环的频率。它将跟踪自上次调用
  Rate :: sleep()以来的持续时间,并在正确的时间内休眠。在这种情况下,
  我们告诉它我们想要以10Hz运行。*/
  
  int count = 0;
  
/*默认情况下,roscpp将安装一个SIGINT处理程序,该处理程序提供Ctrl-C处理,
如果发生这种情况,将导致ros :: ok()返回false。如果出现以下情况,
ros :: ok()将返回false:
收到SIGINT(Ctrl-C)
我们已被另一个具有相同名称的节点踢出网络
ros :: shutdown()已被应用程序的另一部分调用。
所有ros ::NodeHandles都被销毁了
一旦ros :: ok()返回false,所有ROS调用都将失败。
*/
  while (ros::ok())   
  {
/*我们使用消息适配类在ROS上广播消息,通常从msg文件生成。
更复杂的数据类型是可能的,但是现在我们将使用标准的String消息,
它有一个成员:“data”。*/
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

/*ROS_INFO和friend是printf/cout的替代品。*/
    ROS_INFO("%s", msg.data.c_str());

/*将消息广播给任何已连接的人。*/
    chatter_pub.publish(msg);

/*这个简单的程序不需要调用ros :: spinOnce(),因为我们没有收到任何回调。
但是,如果您要在此应用程序中添加订阅,并且此处没有ros::spinOnce(),
则永远不会调用您的回调。所以,添加它是为了衡量。*/
    ros::spinOnce();

/*现在我们使用ros::Rate对象在剩余时间内休眠,让我们达到10Hz的发布速度。*/
    loop_rate.sleep();
    ++count;
  }    
  return 0;
}

这是正在发生的事情的浓缩版本:
初始化ROS系统
宣传我们将把聊天主题上的std_msgs / String消息发布给master
循环发布消息,每秒10次聊天
现在我们需要编写一个节点来接收这些消息。

 

4.2、编写订阅者节点

在beginner_tutorials包中创建src / listener.cpp文件并在其中粘贴以下内容:

#include "ros/ros.h"
#include "std_msgs/String.h"

/*这是一个回调函数,当一个新消息到达chatter主题时将被调用。消息在
boost shared_ptr中传递,这意味着您可以根据需要将其存储起来,而
不必担心它会被删除,并且不会复制基础数据。*/
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");

  ros::NodeHandle n;
/*与主人订阅chatter主题。每当有新消息到达时,ROS都会调用chatterCallback()
函数。第二个参数是队列大小,以防我们无法足够快地处理消息。在这种情况下,
如果队列达到1000条消息,我们将在新消息到达时开始丢弃旧消息。
NodeHandle :: subscribe()返回一个ros::Subscriber对象,您必须保留该对象,
直到您想取消订阅为止。订阅者对象被销毁后,它将自动取消订阅chatter主题。
NodeHandle::subscribe()函数有一些版本允许您指定类成员函数,甚至可以指定
Boost.Function对象可调用的任何函数。该roscpp概述包含更多的信息。*/
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

/*ros::spin()进入一个循环,尽可能快地调用消息回调。不过不用担心,如果没有什么
可以做的话就不会占用太多的CPU。只要ros::ok()返回false,ros::spin()将退出,
这意味着已经调用了ros::shutdown(),默认的Ctrl-C处理程序,master告诉我们关
闭,或者手动调用它。*/
  ros::spin();

  return 0;
}

再次,这是一个精简版的正在发生的事情:
初始化ROS系统
订阅聊天主题
旋转,等待消息到达
当消息到达时,将调用chatterCallback()函数

 

五、ROS单线程和多线程订阅

5.1、单线程订阅

#include <ros/ros.h>
#include <std_msgs/Bool.h>

void tempCallback(const std_msgs::BoolConstPtr& msg)
{
    int num = 10;
    ros::Rate loop_rate(10);
    while (ros::ok() && num)
    {
        ROS_INFO_STREAM("temp temp temp temp temp temp temp temp call back, num->"<<num);
        num--;
        loop_rate.sleep();
    }
}

void longCallback(const std_msgs::BoolConstPtr& msg)
{
    int num = 10;
    ros::Rate loop_rate(10);
    while (ros::ok() && num)
    {
        ROS_INFO_STREAM("long call back, num->"<<num);
        num--;
        loop_rate.sleep();
    }
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "test_node");

    ros::NodeHandle nh;
    ros::Subscriber tempSub = nh.subscribe<std_msgs::Bool>("temp", 1, tempCallback);
    ros::Subscriber longSub = nh.subscribe<std_msgs::Bool>("long", 1, longCallback);

    ros::spin();

    return 0;
}

输入:

rostopic pub /long std_msgs/Bool "data: false" -r 10
rostopic pub /temp std_msgs/Bool "data: false" -r 10

输出:

[ INFO] [1565918138.532995825]: long call back, num->10
[ INFO] [1565918138.633079367]: long call back, num->9
[ INFO] [1565918138.733064686]: long call back, num->8
[ INFO] [1565918138.832994117]: long call back, num->7
[ INFO] [1565918138.932998012]: long call back, num->6
[ INFO] [1565918139.032996832]: long call back, num->5
[ INFO] [1565918139.133071165]: long call back, num->4
[ INFO] [1565918139.232960431]: long call back, num->3
[ INFO] [1565918139.332995614]: long call back, num->2
[ INFO] [1565918139.432999905]: long call back, num->1
[ INFO] [1565918139.533033535]: temp temp temp temp temp temp temp temp call back, num->10
[ INFO] [1565918139.633149213]: temp temp temp temp temp temp temp temp call back, num->9
[ INFO] [1565918139.733148347]: temp temp temp temp temp temp temp temp call back, num->8
[ INFO] [1565918139.833150790]: temp temp temp temp temp temp temp temp call back, num->7
[ INFO] [1565918139.933050574]: temp temp temp temp temp temp temp temp call back, num->6
[ INFO] [1565918140.033141442]: temp temp temp temp temp temp temp temp call back, num->5
[ INFO] [1565918140.133159048]: temp temp temp temp temp temp temp temp call back, num->4
[ INFO] [1565918140.233151712]: temp temp temp temp temp temp temp temp call back, num->3
[ INFO] [1565918140.333148631]: temp temp temp temp temp temp temp temp call back, num->2
[ INFO] [1565918140.433147718]: temp temp temp temp temp temp temp temp call back, num->1
[ INFO] [1565918140.533266548]: long call back, num->10
[ INFO] [1565918140.633400237]: long call back, num->9
[ INFO] [1565918140.733407032]: long call back, num->8
[ INFO] [1565918140.833389468]: long call back, num->7
[ INFO] [1565918140.933386767]: long call back, num->6
[ INFO] [1565918141.033389566]: long call back, num->5
[ INFO] [1565918141.133389982]: long call back, num->4
[ INFO] [1565918141.233389902]: long call back, num->3
[ INFO] [1565918141.333395700]: long call back, num->2
[ INFO] [1565918141.433399861]: long call back, num->1
[ INFO] [1565918141.533413994]: temp temp temp temp temp temp temp temp call back, num->10
[ INFO] [1565918141.633477569]: temp temp temp temp temp temp temp temp call back, num->9
[ INFO] [1565918141.733526139]: temp temp temp temp temp temp temp temp call back, num->8
[ INFO] [1565918141.833527631]: temp temp temp temp temp temp temp temp call back, num->7
[ INFO] [1565918141.933526546]: temp temp temp temp temp temp temp temp call back, num->6
[ INFO] [1565918142.033560826]: temp temp temp temp temp temp temp temp call back, num->5
[ INFO] [1565918142.133522903]: temp temp temp temp temp temp temp temp call back, num->4
[ INFO] [1565918142.233525957]: temp temp temp temp temp temp temp temp call back, num->3
[ INFO] [1565918142.333525708]: temp temp temp temp temp temp temp temp call back, num->2
[ INFO] [1565918142.433521566]: temp temp temp temp temp temp temp temp call back, num->1

 

5.2、多线程订阅

#include <ros/ros.h>
#include <std_msgs/Bool.h>

void tempCallback(const std_msgs::BoolConstPtr& msg)
{
    int num = 1;
    ros::Rate loop_rate(10);
    while (ros::ok() && num)
    {
        ROS_INFO_STREAM("temp temp temp temp temp temp temp temp call back, num->");
        num--;
        loop_rate.sleep();
    }
}

void longCallback(const std_msgs::BoolConstPtr& msg)
{
    int num = 10;
    ros::Rate loop_rate(10);
    while (ros::ok() && num)
    {
        ROS_INFO_STREAM("long call back, num->"<<num);
        num--;
        loop_rate.sleep();
    }
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "test_node");

    ros::NodeHandle nh;
    ros::Subscriber tempSub = nh.subscribe<std_msgs::Bool>("temp", 1, tempCallback);
    ros::Subscriber longSub = nh.subscribe<std_msgs::Bool>("long", 1, longCallback);

    ros::MultiThreadedSpinner spinner(3);//三个线程订阅
    spinner.spin();

    return 0;
}

输入:

rostopic pub /long std_msgs/Bool "data: false" -r 10
rostopic pub /temp std_msgs/Bool "data: false" -r 10

输出:

[ INFO] [1565917840.270586066]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.332730168]: long call back, num->10
[ INFO] [1565917840.370680016]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.432812052]: long call back, num->9
[ INFO] [1565917840.470733027]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.532746151]: long call back, num->8
[ INFO] [1565917840.570822519]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.632748312]: long call back, num->7
[ INFO] [1565917840.670920845]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.732748731]: long call back, num->6
[ INFO] [1565917840.771020449]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.832749593]: long call back, num->5
[ INFO] [1565917840.871116535]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917840.932749685]: long call back, num->4
[ INFO] [1565917840.971215785]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917841.032749710]: long call back, num->3
[ INFO] [1565917841.071313507]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917841.132749230]: long call back, num->2
[ INFO] [1565917841.171407053]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917841.232743868]: long call back, num->1
[ INFO] [1565917841.271526256]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917841.332755181]: long call back, num->10
[ INFO] [1565917841.371625145]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917841.432905582]: long call back, num->9
[ INFO] [1565917841.471753894]: temp temp temp temp temp temp temp temp call back, num->
[ INFO] [1565917841.532846109]: long call back, num->8

 

 

六、创建编译并运行完整的ros helloword工程(c++版-加深理解)

6.1 、创建工作空间

1. 创建catkin工作空间

$  mkdir -p ~/catkin_ws/src
$  cd ~/catkin_ws/src

2. 编译catkin工作空间

$  cd ~/catkin_ws/
$  catkin_make

3.配置环境变量

$  source devel/setup.bash

echo $ROS_PACKAGE_PATH # 查看刚刚配置的环境变量是否生效
————————————————
6.2 、创建软件包(project)

创建名称为 my_ros_helloworld_cpluse 的软件包

cd catkin_ws/src  # 进入工作空间下的 src 目录  (注意路径!!!)

catkin_create_pkg my_ros_helloworld_cpluse std_msgs rospy roscpp

cd ..             #退到 catkin_ws 工作空间路径下

catkin_make       #编译软件包

 

6.3、工程创建

1、 编写talker.cpp 创建消息发布器节点 (发布话题)

创建src/talker.cpp 文件

#include <iostream>
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <sstream>

using namespace std;

int main( int argc, char** argv )
{
    // 创建节点
    ros::init(argc, argv, "talker_node");
    ros::NodeHandle n;

    // 发布话题
    ros::Publisher talkerPub = n.advertise<std_msgs::String>("chatter", 10);

    // 设置发送频率
    ros::Rate loop_rate(10);

    int count = 0;
    while(ros::ok())
    {

        std_msgs::String msg;

        std::stringstream ss;
        ss << "hello world" <<count; // 将“hello world” 和 count 一起输出到 string流中

        msg.data = ss.str(); // String 转为 str 作为消息体的数据

        ROS_INFO("%s", msg.data.c_str());

        talkerPub.publish(msg);

        ros::spinOnce();

        loop_rate.sleep();

        count ++;
    }

    return 0;
}

2、 编写listener.cpp 创建消息接收器节点 (订阅话题)

创建src/listener.cpp 文件

#include <iostream>
#include <ros/ros.h>
#include <std_msgs/String.h>

using namespace std;
// 定义回调函数
void listener_callback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("I heard : [%s]" , msg->data.c_str()); // String 转为 str字符串
}

int main( int argc, char** argv)
{
    // 创建节点
    ros::init(argc, argv, "listener_node");
    ros::NodeHandle n;

    // 订阅话题 以及指定该话题的回调函数
    ros::Subscriber listenerSub = n.subscribe("chatter", 10,listener_callback);

    ros::spin();

    return 0;
}

3、 编写CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(my_ros_helloworld_cpluse)

## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)


## Declare a catkin package
catkin_package()

## 编译 talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})


add_executable(listener
        src/listener.cpp
        )
target_link_libraries(listener ${catkin_LIBRARIES})


add_executable(talker
        src/talker.cpp
        )
target_link_libraries(talker ${catkin_LIBRARIES})

4、 编译

在ros_test_ws 目录下 运行 catkin_make 命令编译,生成可执行文件 talker 以及 listener

在这里插入图片描述

6.4 、运行此工程

注意:用echo $ROS_PACKAGE_PATH 查看此工作空间是否在环境变量中
若没有则运行此命令 source ~/ros_test_ws/devel/setup.bash 也可以通过 直接将此命令写入 home目录下的 .bashrc文件中,这样就不需要每次都source ~/ros_test_ws/devel/setup.bash 。因为每打开一个新的终端,都会先加载 .bashrc文件。

确保环境变量加载正确,否则rosrun 找不到 软件包 !!!
开三个终端,分别运行如下命令:

1 运行 ros master
先运行命令 roscore

2 运行 talker
source ros_test_ws/devel/setup.bash
rosrun my_ros_helloworld_cpluse talker
————————————————
 在这里插入图片描述

3 运行 listener

source ros_test_ws/devel/setup.bash
rosrun my_ros_helloworld_cpluse listener

在这里插入图片描述

 

 

七、launch文件

每当我们需要运行一个ROS节点或工具时,都需要打开一个新的终端运行一个命令。当系统中的节点数量不断增加时,每个节点一个终端的模式会变得非常麻烦。那么有没有一种方式可以一次性启动所有节点呢?答案当然是肯定的。

启动文件(Launch File)便是ROS中一种同时启动多个节点的途径,还可以自动启动ROSMaster节点管理器,而且可以实现每个节点的各种配置,为多个节点的操作提供了很大便利。

7.1、基本元素

首先来看一个简单的launch文件:

  1. <launch>
  2. <nodepkg="turtlesim"name="sim1" type="turtlesim_node"/>
  3. <nodepkg="turtlesim"name="sim2" type="turtlesim_node"/>
  4. </launch>

这是一个简单而完整的launch文件,采用XML的形式进行描述,包含一个根元素<launch>和两个节点元素<node>。

1.<launch>

XML文件必须要包含一个根元素,launch文件中的根元素采用<launch>标签定义,文件中的其他内容都必须包含在这个标签之中:

  1. <launch>
  2. ......
  3. </launch>

2. <node>

启动文件的核心是启动ROS节点,采用<node>标签定义,语法如下:

  1. <node pkg="package-name"type="executable-name" name="node-name" />

从上边的定义规则可以看出,在启动文件中启动一个节点需要三个属性:pkg、type和name。其中pkg定义节点所在的功能包名称,type定义节点的可执行文件名称,这两个属性等同于在终端中使用rosrun命令执行节点时的输入参数。name属性用来定义节点运行的名称,将覆盖节点中init()赋予节点的名称。这是三个最常用的属性,在某些情况下,我们还有可能用到以下属性:

·  output = “screen”:将节点的标准输出打印到终端屏幕,默认输出为日志文档;

·  respawn = “true”:复位属性,该节点停止时,会自动重启,默认为false;

·  required = “true”:必要节点,当该节点终止时,launch文件中的其他节点也被终止;

·  ns = “namespace”:命名空间,为节点内的相对名称添加命名空间前缀;

·  args = “arguments”:节点需要的输入参数。

实际应用中的launch文件往往会更加复杂,使用的标签也会更多,例如一个启动机器人的launch文件如下:

    <launch>

       <node pkg="mrobot_bringup" type="mrobot_bringup" name="mrobot_bringup" output="screen" />

       <arg name="urdf_file" default="$(find xacro)/xacro --inorder '$(find mrobot_description)/urdf/mrobot_with_rplidar.urdf.xacro'" />
       <param name="robot_description" command="$(arg urdf_file)" />

       <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />  

       <node pkg="robot_state_publisher" type="robot_state_publisher" name="state_publisher">
           <param name="publish_frequency" type="double" value="5.0" />
       </node>
       <node name="base2laser" pkg="tf" type="static_transform_publisher" args="0 0 0 0 0 0 1 /base_link /laser 50"/>

       <node pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf">
           <remap from="robot_pose_ekf/odom_combined" to="odom_combined"/>
           <param name="freq" value="10.0"/>
           <param name="sensor_timeout" value="1.0"/>
           <param name="publish_tf" value="true"/>
           <param name="odom_used" value="true"/>
           <param name="imu_used" value="false"/>
           <param name="vo_used" value="false"/>
           <param name="output_frame" value="odom"/>
       </node>

       <include file="$(find mrobot_bringup)/launch/rplidar.launch" />

    </launch>

目前,我们只关注其中的标签元素,除了上边介绍的<launch>和<node>,这里还出现了<arg>、<param>、<remap>,这些都是常用的标签元素。

 

7.2、参数设置

为了方便设置和修改,launch文件支持参数设置的功能,类似于编程语言中的变量声明。关于参数设置的标签元素有两个:<param>、<arg>,一个代表parameter,另一个代表argument。这两个标签元素翻译成中文都是“参数”的意思,但是这两个“参数”的意义是完全不同的。

1. <param>

parameter是ROS系统运行中的参数,存储在参数服务器中。在launch文件中通过<param>元素加载parameter;launch文件执行后,parameter就加载到ROS的参数服务器上了。每个活跃的节点都可以通过 ros::param::get()接口来获取parameter的值,用户也可以在终端中通过rosparam命令获得parameter的值。

<param>的使用方法如下:

  1. <param name="output_frame" value="odom"/>

运行launch文件后,output_frame这个parameter的值就设置为odom,并且加载到ROS参数服务器上了。但是在很多复杂的系统中,参数的数量很多,如果这样一个一个的设置会非常麻烦,ROS也为我们提供了另外一种类似的参数加载方式——<rosparam>:

  1. <rosparamfile="$(find 2dnav_pr2)/config/costmap_common_params.yaml" command="load" ns="local_costmap" />

<rosparam>可以帮助我们将一个yaml格式文件中的参数全部加载到ROS参数服务器中,需要设置command属性为“load”,还可以选择设置命名空间“ns”。

2. <arg>

argument是另外一个概念,类似于launch文件内部的局部变量,仅限于launch文件使用,便于launch文件的重构,和ROS节点内部的实现没有关系。

设置argument使用<arg>标签元素,语法如下:

  1. <arg name=”arg-name” default=”arg-value”/>

launch文件中需要使用到argument时,可以使用如下方式调用:

  1. <paramname="foo" value="$(argarg-name)" />
  2. <node name="node" pkg="package" type="type "args="$(arg arg-name)" />
  3.  

7.3、重映射机制

ROS的设计目标是提高代码的复用率,所以ROS社区中的很多功能包我们都可以拿来直接使用,而不需要关注功能包的内部实现。那么问题就来了,别人功能包的接口不一定和我们的系统兼容呀?

ROS提供一种重映射的机制,简单来说就是取别名,类似于C++中的别名机制,我们不需要修改别人功能包的接口,只需要将接口名称重映射一下,取个别名,我们的系统就认识了(接口的数据类型必须相同)。launch文件中的<remap>标签可以帮我们实现这个重映射的功能。

比如turtlebot的键盘控制节点,发布的速度控制指令话题可能是/turtlebot/cmd_vel,但是我们自己的机器人订阅的速度控制话题是/cmd_vel,这个时候使用<remap>就可以轻松解决问题,将/turtlebot /cmd_vel重映射为/cmd_vel,我们的机器人就可以接收到速度控制指令了:

  1. <remap from="/turtlebot/cmd_vel"to="/cmd_vel"/>

重映射机制在ROS中的使用非常广泛,也非常重要,方法不止这一种,也可以在终端rosrun命令中实现重映射,大家一定要理解好这种机制。

 

7.4、嵌套复用

在复杂的系统当中,launch文件往往有很多,这些launch文件之间也会存在依赖关系。如果需要直接复用一个已有launch文件中的内容,可以使用<include>标签包含其他launch文件,这和C语言中的include几乎是一样的。

  1. <include file="$(dirname)/other.launch" />

总而言之,launch是ROS框架中非常实用、灵活的功能,它类似于一种高级编程语言,可以帮助我们管理启动系统时的方方面面。在使用ROS的过程中,很多情况下我们并不需要编写大量代码,仅需要使用已有的功能包,编辑一下launch文件,就可以完成很多机器人功能。

 

 

 

 

https://blog.csdn.net/weicao1990/article/details/84400422

https://blog.csdn.net/weixin_37835423/article/details/99670885

https://blog.csdn.net/gungnirspledge/category_10147880.html

https://recomm.cnblogs.com/blogpost/6579883?page=2

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

他人是一面镜子,保持谦虚的态度

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值