ros_fuerte创建工作空间、创建ROS功能包、编译ROS功能包、创建节点(cpp)、编译节点、使用launch文件、创建srv和msg文件、使用新建的srv和msg文件

参考《ROS机器人程序设计》一二版均有

1.创建工作空间

在开始具体工作之前,首先创建工作空间。在工作空间中完成代码。

若查看ROS正在使用道工作空间:

echo $ROS_PACKAGE_PATH

创建新文件夹:

cd~

mkdir ~p dev/rosbook

将此路径添加ROS_PACKAGE_PATH.只需在~/.bashrc文件末尾添加一个新行:

echo "export ROS_PACKAGE_PATH=~/dev/rosbook:${ROS_PACKAGE_PATH}"  >>  ~/.bashrc


. ~/.bashrc

.bashrc文件在home中,隐藏,

 ls -a  ////显示隐藏文件

gedit ~/.bashrc/////在文本中打开

cat ~/.bashrc////在终端打开


2.创建ros功能包

功能包,指的是一种特定的文件结构和文件夹组合。这种结构如下所示:
● bin/ 这是我们编译和链接程序后,用于存储可执行文件的文件夹。
● include/package_name/ 此目录包含了你所需要库的头文件。不要忘记导出功能包清单,因为它们还会被其他功能包所使用。
● msg/ 如果你要开发非标准消息,请把文件放在这里。
● scripts/ 其中包括 Bash、Python 或任何其他脚本的可执行脚本文件。
● src/ 这是存储程序源文件的地方。你可能会为节点创建一个文件夹或按照你希望
的方式去组织它。
• srv/ 这表示的是服务(srv)类型。
● CMakeLists.txt 这是 CMake 的生成文件。
• manifest.xml 这是功能包清单文件。


可以手动创建功能包。

最好使用roscreat-pkg命令行工具。

cd ~/dev/rosbook

roscreate-pkg chapter2_tutorials std_msgs rospy roscpp

chapter2_tutorials是功能包名词,std_msgs、 rospy 、roscpp是依赖项

std_msgs包含了常见道消息类型,表示基本数据类型和其他基本道消息构造,如多维数组。

rospy 一个ros的纯Python客户端库

roscpp 使用C++ 实现ROS的各种功能。

3.编译ROS功能包

rosmake chapter2_tutorials
编译之后会出现bin文件夹

4.创建节点(cpp)

创建两个节点:一个发布一些数据,另一个接受这些数据。两个节点之间使用最基本道方式进行通信。

$ roscd chapter2_tutorials/src/

创建两个文件并分别命名为  example1_a.cpp、example1_b.cpp。

 example1_a.cpp文件将会发送带有节点名称的数据

example1_b.cpp 会把这些数据显示在 shell 窗口中。


example1_a.cpp内容:

#include "ros/ros.h"//包含使用ROS节点所有必要道文件
#include "std_msgs/String.h"//
#include ///////////包含要使用的文件类型

int main(int argc, char **argv)
{
  ros::init(argc, argv, "example1_a");//启动该节点并设置其名称,名称必须唯一
  ros::NodeHandle n;//设置节点进程的句柄
  ros::Publisher pub = n.advertise("message", 1000);//将节点设置成发布者,并将所发布主题道类型和名称告知节点管理器。第一个参数是消息的名称:message,第二个是缓冲区道大小。如果主题发布数据速度较快,那么将缓冲区设置为1000个消息。
  ros::Rate loop_rate(10);//设置发送数据道频率为10Hz
  while (ros::ok())//当收到Ctrl+C的按键消息或ROS停止当前节点运行时,ros::ok()库会执行停止节点运行道命令
  {
//////创建一个消息变量,变量类型必须符合发送数据的要求
    std_msgs::String msg;
    std::stringstream ss;
    ss << " I am the example1_a node ";
    msg.data = ss.str();
    //ROS_INFO("%s", msg.data.c_str());
    pub.publish(msg);//消息被发布
    ros::spinOnce();//如果一个订阅者出现,ROS就会更新和读取所有主题
    loop_rate.sleep();//按照10Hz的频率将程序挂起
  }
  return 0;
}

example1_b.cpp的内容:

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

void messageCallback(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, "example1_b");
  ros::NodeHandle n;
/////创建一个订阅者,并从主题获取以message为名称的消息数据。设置缓冲区为1000个消息,处理消息句柄的回调函数为messageCallback
  ros::Subscriber sub = n.subscribe("message", 1000, messageCallback);
 //// ros::spin()库是节点读取数据道消息响应循环,当消息到达的时候,回调函数就会被调用。当按下Ctrl+C时,节点会退出消息循环,于是循环结束。
  ros::spin();
  return 0;
}

5.编译节点

当使用chapter2_tutorial功能包时,要自行编辑其中道CMakeList.txt文件。

$ rosed chapter2_tutorials CMakeLists.txt    /////////////用VIM编辑器打开文件,但是我没有装,直接找到打开就行。

将以下命令复制到文件末尾:

rosbuild_add_executable(example1_a src/example1_a.cpp)

rosbuild_add_executable(example1_b src/example1_b.cpp)

这两个命令会在bin文件夹下创建两个可执行文件。

使用rosmake工具编译功能包就会编译全部道节点:

rosmake chapter2_tutorials

PS:如果没有启动ROS,先roscore.检查ROS是否运行:rosnode list

分别在两个终端运行:

rosrun chapter2_tutorials example1_a

rosrun chapter2_tutorials example1_b

6.使用launch文件

aunch文件是ROS里一个有用的特征可以启动多个节点。在以上章节中,我们已经创建了节点、并且在不同的shell中执行这些节点。想象20个节点同时工作,并且在每个shell里执行有一个节点,这简直是噩梦!

有了launch文件,我们可以通过启动一个扩展名为.launch的配置文件在同一个shell里完成同样的工作。

为了实践此功用,我们要在我们的程序包里创建新的文件夹,如下:

$ roscd chapter2_tutorials/

$ mkdir launch

$ cd launch

$ vim chapter2.launch

现在,将以下代码放入chapter2.launch文件:

type="example1_a"/>

type="example1_b"/>

这个文件很简单,但如果需要,你可以写一个非常复杂的文件。例如,控制一个完整的机器人,如PR2或者Robonaut。它们都是真正的机器人并且在ROS中被模拟。

这个文件有一个launch标签,你可以看到node标签。node标签用来从程序包启动一个节点,例如,从chapter2_tutorials程序包启动example1_a节点。

这个launch文件会执行两个节点——本章前两个节点。如果你记得,example1_a节点发送一个消息到 example1_b节点。为了启动这个文件,你可以用以下命令:

$ roslaunch chapter2_tutorialschapter2.launch

When you launch a launch file, it is not necessary to execute it before the roscore
command; roslaunch does it for us.
Remember that the example1_b node prints in the screen the message received
from the other node. If you take a look, you won't see anything. This is because
example1_b prints the message using ROS_INFO, and when you run only a node
in a shell, you can see it, but when you run a launch file, you can't.

Now, to see the message printed in the screen, you can use the rqt_console utility.
You will learn more about this utility in the following chapters. Now, run the
following command:

$ rqt_console


7.创建msg和srv文件

用于创建自定义消息。

首先,在chapter2_tutorials功能包下创建msg文件夹,并在其中创建新的文件chapter2_msg1.msg.在文件中添加:

int32 A
int32 B
int32 C


现在编辑 CMakeList.txt,从 # rosbuild_genmsg() 这一行中删除 #,然后使用rosmake 命令编译功能包:
$ rosmake chapter2_tutorials

为了检查编译是否正确,可以使用 rosmsg 命令:
$ rosmsg show chapter2_tutorials/chapter2_msg1


如果你在 chapter2_msg1.msg 文件中看到一样的内容,说明编译正确

Now we are going to create an
现在创建一个 srv 文件。在chapter2_tutorials 文件夹下创建一个名为 srv 的文件夹,并新建文件chapter2_srv1.srv,在文件中增加以下行:
int32 A
int32 B
int32 C
---
int32 sum


编辑 CMakeList.txt 文件,从 #rosbuild_gensrv() 这一行中删除 #,并且使用
rosmake chapter2_tutorials 命令编译功能包。

你可以通过 rossrv 工具来检查编译是否正确:
$ rossrv show chapter2_tutorials/chapter2_srv1

如果你在 chapter2_srv1.srv 文件中看到相同的内容,说明编译正确。

8.使用新建的srv和msg文件

首先,学习如何创建一个服务并在ROS中使用它。该服务对三个整数求和。我们需要两个节点,一个服务器一个客户端。

在chapter2_tutorial功能包src中创建两个节点:example2_a.cpp和example2_b.cpp

8.1用自定义的srv文件创建节点

example2_a.cpp内容:

//包含必要的头文件和创建道srv文件
#include "ros/ros.h"
#include "chapter2_tutorials/chapter2_srv1.h"
//对三个变量求和,并将计算结果发送给其他节点
bool add(chapter2_tutorials::chapter2_srv1::Request  &req,
         chapter2_tutorials::chapter2_srv1::Response &res)
{
  res.sum = req.A + req.B + req.C;
  ROS_INFO("request: A=%ld, B=%ld C=%ld", (int)req.A, (int)req.B, (int)req.C);
  ROS_INFO("sending back response: [%ld]", (int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_3_ints_server");
  ros::NodeHandle n;
  //创建服务并在ROS中发布广播
  ros::ServiceServer service = n.advertiseService("add_3_ints", add);
  ROS_INFO("Ready to add 3 ints.");
  ros::spin();

  return 0;
}

example2_b.cpp内容:

#include "ros/ros.h"
#include "chapter2_tutorials/chapter2_srv1.h"
#include 

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_3_ints_client");
  if (argc != 4)
  {
    ROS_INFO("usage: add_3_ints_client A B C ");
    return 1;
  }

  ros::NodeHandle n;
////使用add_3_ints为名称创建一个服务的客户端
  ros::ServiceClient client = n.serviceClient("add_3_ints");
 ///创建srv文件的一个实例,并且加入需要发送的数据值
  chapter2_tutorials::chapter2_srv1 srv;
  srv.request.A = atoll(argv[1]);
  srv.request.B = atoll(argv[2]);
  srv.request.C = atoll(argv[3]);
///代码调用服务并发送数据,如果调用成功,call()函数会返回true;如果没有成功,返回false
  if (client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

编译节点,在CMakeList.txt文件末尾加入:

rosbuild_add_executable(example2_a src/example2_a.cpp)

rosbuild_add_executable(example2_b src/example2_b.cpp)


编译节点:

rosmake chapter2_tutorials

分别在两个终端运行:

rosrun chapter2_tutorials example2_a

rosrun chapter2_tutorials example2_b 1 2 3

8.2用自定义的msg文件来创建节点

同8.1,只是调用chapter2_msg1.msg

example3_a.cpp内容:

#include "ros/ros.h"
#include "chapter2_tutorials/chapter2_msg1.h"
#include 

int main(int argc, char **argv)
{
  ros::init(argc, argv, "example1_a");
  ros::NodeHandle n;
  ros::Publisher pub = n.advertise("message", 1000);
  ros::Rate loop_rate(10);
  while (ros::ok())
  {
    chapter2_tutorials::chapter2_msg1 msg;
    msg.A = 1;
    msg.B = 2;
    msg.C = 3;
    pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}

example3_b.cpp内容:

#include "ros/ros.h"
#include "chapter2_tutorials/chapter2_msg1.h"

void messageCallback(const chapter2_tutorials::chapter2_msg1::ConstPtr& msg)
{
  ROS_INFO("I heard: [%d] [%d] [%d]", msg->A, msg->B, msg->C);
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "example1_b");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("message", 1000, messageCallback);
  ros::spin();
  return 0;
}

参考文献:ROS机器人程序设计
一二版均有。launch部分是二版里的。

你可能感兴趣的:(ROS)