第一个发布者程序

1 写在开头的话

      首先确保自己已经有工作区间,且已经将该工作区间的setup.bash加入当前用户的环境变量中,若是则直接看第二章节,否则继续往下看。

     若没有工作区间则查看顺序为:1.1——>1.2——>2——>1.3——》3

     若有工作区间但是没有将setup.bash加入当前用户的环境变量中,则查看顺序为:1.2——》1.3——》2——》3

    若是已经有工作区间且已经将该工作区间的setup.bash加入当前用户的环境变量中,则查看顺序1.2—》2—》3

1.1 新建工作区间

  在当前用户home目录下调用mkdir命令新建文件夹test,cd进入该文件夹,再次调用mkdir新建文件夹src,如下

1.2 创建功能包

  在工作区间的src目录下,调用catkin_create_pkg创建功能包pubvel。如下

  调用ls查看是否创建成功,成功会在src下出现pubvel文件夹

  注意:下图中的amin文件夹和CMakeLists.txt文件都是由于本人之前已经有工作区才会存在,若初次创建工作区间和功能包则不会出现这两项,即只有pubvel文件夹;若已经有工作区间则会出现这两项;

   cd进入pubvel文件夹,同时调用ls查看pubve文件夹,此时可以看到里面包含2个文件,如下

  注意:pubvel.cpp文件是由于本人已经做过所以才会出现,此时应该是没有的】

   第一个配置文件,叫做package.xml

   第二个文件,叫做CMakeLists.txt,是一个Cmake的脚本文件,Cmake是一个符合工业标准的跨平台编译系统。

1.3  添加环境变量

       执行此部分需要两个条件(满足其一即可),条件为:其一,在查看本文前已经有工作区间但是没有将该工作区间的setuo.bash配置到当前用户的环境变量中;其二,已经执行了本文的第二部分

      添加环境变量到当前目录步骤如下:

      a.在当前用户目录的工作区目录下,即test目录下【此时的test为本人的工作区名称,若查阅本文者查看此文前已经有自己的工作区间,则此步骤的test为查阅者的工作区间名称】,调用ls查看此目录下内容,如下:

   b.调用cd进入devel目录,调用ls查看此目录下内容:

c. 注意:a、b步骤只是为了确保该工作区间中存在该工作区间环境变量的配置文件setup.bash,没有做任何实质性的工作

d。再次进入当前用户的home目录,调用ls -a查看该目录下包含隐藏文件的全部文件,如下

可以看到,上图中有隐藏文件.bashrc

e。调用vim编辑此文件,如下

在最后加入一行:source  ~/test/devel/setup.bash,注意此处的test是工作区间的名字,根据需要修改,如下

按esc退出编辑,继而输入:wq保存退出


2  创建编译执行发布者程序

2.1 创建发布者程序

2.1.1 添加代码

 cd进入工作区目录下的src,再调用cd进入pubvel文件夹中,如下

在pubvel文件夹下调用vim 创建发布者程序pubvel.cpp,并添加如下代码

2.1.2 关于代码内容详细说明

 2.1.2.1 关于头文件说明

 头文件ros/ros.h包含了标准ROS类的声明,你将会在每一个你写的ROS程序中包含它。

 在pubvel程序中,我们想发布一条类型为geometry_msgs/Twist的消息(名为geometry_msgs的包所拥有的类型为Twist的消   息),我们应该这样:#include <geometry_msgs/Twist.h    这个头文件的目的是定义一个C++类,此类和给定的消息类型含有相同的数据类型成员。这个类定义在以包名命名的域名空间中。这样命名的实际影响是当引用C++代码中的消息类时,你将会使用  双分号(::)来区分开包名和类型名,双分号也称为范围解析运算符。在我们的pubvel例程中,头文件定义了一个名为geometry_msgs::Twist的类。

头文件stdlib.h则是因为什么在main函数中调用了srand函数和rand函数

2.1.2.2 关于main函数内代码说明

 A.ros::init函数初始化ROS客户端库。请在你程序的起始处调用一次该函数3。函数最后的参数是一个包含节点默认名的字符串。

 B.ros::NodeHandle(节点句柄)对象是你的程序用于和ROS系统交互的主要机制4。创建此对象会将你的程序注册为ROS节点管    理器的节点。最简单的方法就是在整个程序中只创建一个NodeHandle对象。

C..创建发布者对象:发布消息的实际工作是由类名为ros::Publisher的一个对象来完成的。创建格式如下:                                                     ros::Publisher pub = node_handle.advertise<message_type>(topic_name, queue_size);                                                  上述格式中参数说明如下:                                                                                                                                                                      node_handle是ros::NodeHandle类的一个对象,是你在程序的开始处创建的,即ng。我们将调用这个对象的advertise方法;                                                                                                                               

          在尖括号中的message_type部分,其正式名称为模板参数,是我们要发布的消息的数据类型。这个应该是上面讨论过的头文件中定义的类名。在例程中,我们使用geometry_msgs::Twist类。

           topic_name是一个字符串,它包含了我们想发布的话题的名称。 

           advertise函数最后的参数是一个整数,表示这个发布者发布的消息序列的大小。在大多数情况下,一个相对比较大的值,比方说1000,是合适的。如果你的程序迅速发布比队列可以容纳的更多的消息,最早进入队列的未发送的消息将被丢弃。如果你想从同一个节点发布关于多个话题的消息,你需要为每个话题创建一个独立的ros::Publisher对象。

D.srand(time(0)):计算机没有办法产生真正的随机数的,是用算法模拟,所以你只调用rand,每次出来的东西是一样的。设置一个种子后,根据种子的不同,就可以产生不同的数了。而怎么保证种子的不同呢?最简单的办法当然是用永远在向前的时间。srand(time(0)) ;//先设置种子rand();//然后产生随机数。Srand是种下随机种子数,你每回种下的种子不一样,用Rand得到的随机数就不一样。为了每回种下一个不一样的种子,所以就选用Time(0),Time(0)是得到当前时时间值(因为每时每刻时间是不一样的了)。

E.创建并填充消息对象,geometry_msgs::Twist msg;                                                                                                                                                               msg.linear.x = double(rand())/double(RAND_MAX);                                                                                                                         msg.angular.z = 2*double(rand())/double(RAND_MAX) - 1;

F.发布消息 。使用ros::Publisher对象的publish方法可以很简单地发布消息。例如下面所示:pub.publish(msg);这个方法将所给的消息添加到发布者的输出消息队列中,从这里,它会尽快被发送到相同话题的订阅者那里。

G.消息发布循环。                                                                                                                                                                                     我们的pubvel例程在while循环中重复发布消息的步骤,随着时间的推移发布不同的消息。程序在这个循环中使用了两个附加的构造函数。                                                                                                                                                                                             其一为节点是否停止工作的检查 pubvel的while循环的条件是:ros::ok()  通俗地说,这个函数检查我们的程序作为ROS节点是否仍处于运行良好的状态。它会一直返回true,除非这个节点有某种原因使其停止工作。                                                                  有如下几个原因会使ros::ok()返回false:你可能对节点使用了rosnode kill命令;你可能给程序发送了一个终止信号(Ctrl-C);你可能在程序的某个位置调用了ros::shutdown()这个函数是在你的代码中发送节点工作已经完成信号的一个很有用的方法;你可能以相同的名字启动了其他节点,经常是因为你启动了一个相同程序的新实例。                                                                     其二为控制消息发布频率。pubvel的最后一个新知识点是它使用了ros::Rate对象ros::Rate rate(2);这个对象控制循环运行速度,其构造函数中的参数以赫兹(Hz)为单位,即每秒钟的循环数。                                                                                                     这个例子创建了旨在规范每秒钟执行两个迭代循环的速率对象。邻近每次循环迭代的结尾,我们调用此对象的sleep方法:
rate.sleep();每次调用此方法时就会在程序中产生延迟。延迟的持续时间被用来阻止循环的迭代速率超过指定的速率。没有这种控制,程序会以计算机允许的最快速度发布消息,这样会占满发布和订阅的序列,并且浪费计算和网络资源(在作者的电脑上,一个不加控制的程序会每秒发布大约6300条消息。)。

H.定义输出格式:ROS_INFO_STREAM行尽管和发布速度命令不是直接相关的,但还是值得一看的。这是关于宏ROS_INFO_STREAM可以做什么的一个更加完整的例证,因为它演示了在输出中除了插入字符串还可以插入其他数据的能力

2,2 编译pubvel

2.2.1 在CMakeLists.txt文件中声明消息类型依赖库

      因为pubvel使用了来自geometry_msgs包的消息类型和roscpp中的ros.h头文件,我们必须声明对这两个包的依赖关系

     进入工作区间目录下的src目录,cd再次进入pubvel功能包,vim打开该目录下的CMakeLists.txt

    

     CMakeLists.txt文件的默认版本含有如下行:find_package(catkin REQUIRED)

   

    所依赖的其他catkin包可以添加到这一行的COMPONENTS关键字后面,如下所示:

                     find_package(catkin REQUIRED COMPONENTS package-names)

     对于pubvel例程,我们需要添加名为roscpp和geometry_msgs的依赖库。因此,修改后的find_package行如下所示:                           

 2.2.2 在package.xml文件中声明消息类型依赖库

         我们同样需要在包的清单文件中列出依赖库,通过使用build_depend (编译依赖)和run_depend(运行依赖)两个关键字实现【注意:格式有2种,具体见https://blog.csdn.net/guosuling/article/details/83214460中的3.2】:
                                             <build_export_depend>package-name</build_export_depend>
                                             <exec_depend>package-name</run_depend>

       打开package.xml文件后,找到文件偏下方的绿色字体<buildtool_depend>catkin</buildtoo;_depend>,在其后添加我们的依赖库,添加后效果如下

         

      在清单文件中声明的依赖库并没有在编译过程中用到;如果你在此处忽略它们,你可能不会看到任何错误消息,直到发布你的包给其他人,他们可能在没有安装所需包的情况下编译你发布的包而导致报错。

2.3  声明可执行文件

       在功能包的CMakeLists.txt中添加两行,来声明我们需要创建的可执行文件。其一般形式是:
                                         add_executable(executable-name source-files)
                                          target_link_libraries(executable-name ${catkin_LIBRARIES})

       第一行声明了我们想要的可执行文件的文件名,以及生成此可执行文件所需的源文件列表。如果你有多个源文件,把它们列在此处,并用空格将其区分开

        第二行告诉Cmake当链接此可执行文件时需要链接哪些库(在上面的find_package中定义)。如果你的包中包括多个可执行文件,为每一个可执行文件复制和修改上述两行代码。

      在我们的例程中,我们需要一个名为pubvel的可执行文件,它通过名为pubvel.cpp的源文件编译而来。所以我们需要添加如下几行代码到CMakeLists.txt中。注意:在CMakeLists.txt文件中有很多注释和例句,找到对应的例句,在其下方输入我们要求的命令,保存退出

2.4. 编译工作区

   使用下列命令在工作区目录下编译包中所有的可执行文件 :catkin_make

  

   执行结果如下表示成功

若出现找不到头文件等错误,首先详细检查自己代码中相关头文件和函数是否书写出错,若已经确保直接书写正确则见另外一篇文章https://mp.csdn.net/postedit/83214460的2.4.3


3 执行pubvel

      执行完第2部分后要记得执行1.3 ,即添加环境变量到此用户的启动文件.bashrc中,然后再往下执行

     当所有这些编译步骤完成后,新的ROS程序就可以使用rosrun来执行,就像任何其他ROS程序一样。

      但是注意:任何ros程序在执行前都要保证roscore在运行

    

       此例程是发布者发送类型为为geometry_msgs/Twist的消息给话题向话题/turtle1/cmd_vel,此话题已经被节点/turtlesim节点订阅,所以执行本例程的pubvel程序时可以打开一个/turtlesim节点来显式的看我们程序的效果

      打开节点/turtlesim节点的方式为:新打开一个shell来运行如下代码

此时再开一个shell来运行我们自己的程序,如下

      

猜你喜欢

转载自blog.csdn.net/guosuling/article/details/83377946