核心ROS教程(一)

核心ROS教程(一)

  • 1. 查看ROS的设置

  • 2. ROS环境变量都自动添加到bash会话中(只在本次终端中有效)

  • 3.ROS环境变量都自动添加到bash会话中(一直有效)

  • 4. 创建catkin_ws工作空间

  • 5. 创建和构建ROS包

  • 6. 了解ROS节点

  • 7. 了解ROS主题

  • 8. 了解ROS服务

  • 9. 使用rqt_console和roslaunch

    • 9.1 **launch启动文件说明**

  • 10. 使用rosed编辑ROS中的文件

  • 11. 创建ROS消息msg和服务srv

  • 12. 编写简单的发布者和订阅者(​​C ++)

  • 13. 编写简单的发布者和订阅者(​​Python)

  • 14. 编写简单的服务和客户端(C ++)

  • 15. 编写简单的服务和客户端(Python)

  • 16. 录制和播放数据

  • 17. roswtf


参考wiki.ros

1. 查看ROS的设置

printenv | grep ROS

2. ROS环境变量都自动添加到bash会话中(只在本次终端中有效)

source /opt/ros/indigo/setup.bash

3.ROS环境变量都自动添加到bash会话中(一直有效)

echo“source /opt/ros/indigo/setup.bash”>>/ .bashrc
source~ / .bashrc

4. 创建catkin_ws工作空间

mkdir -p ~ / catkin_ws / src
cd ~ / catkin_ws / src
catkin_init_workspace
cd~ / catkin_ws /
catkin_make
source devel / setup.bash  # 或者加上下面两句使得工作空间新打开终端依旧有效
gedit ~/.bashrc  # gedit的方式打开bashc文件
source   ~/catkin_ws/devel/setup.bash   # 末尾加上这句
echo $ROS_PACKAGE_PATH

5. 创建和构建ROS包

# 创建catkin包
cd ~ / catkin_ws / src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
# 构建catkin包
cd ~ / catkin_ws
catkin_make --pkg beginner_tutorials #构建工作空间之后,它在devel子文件夹(catkin_ws/devel)中创建了一个类似的结构,就像您在/ opt / ros / $ ROSDISTRO_NAME下找到的一样

6. 了解ROS节点

roscore   # roscore是使用ROS时应该运行的第一件事
# 用rosnode来看看正在运行的roscore做了什么.
rosnode list
rosnode info /rosout
rosrun turtlesim turtlesim_node  # 使用rosrun来启动另一个节点,允许您使用包名直接在包中运行节点(无需知道包路径),用法:rosrun [package_name] [node_name]
rosnode list   # 查看当前节点多了一个turtlesim
rosrun turtlesim turtlesim_node __name:= my_turtle   # 使用remapping argument来更改节点turtlesim为my_turtle 
rosnode list   # 会发现当前节点turtlesim变成了my_turtle
rosnode ping my_turtle   # rosnode命令ping来测试它是否正常

7. 了解ROS主题

roscore    # roscore是使用ROS时应该运行的第一件事
rosrun turtlesim turtlesim_node   # 启动乌龟节点
rosrun turtlesim turtle_teleop_key     # 启动键盘驱动节点
rosrun rqt_graph rqt_graph
rostopic -h    # 使用rostopic的help选项获取rostopic的可用子命令 
rostopic list    # 打印有关活动主题的信息
rostopic echo /turtle1/cmd_vel    # 显示了在主题/turtle1/cmd_vel上发布的数据,按rqt_graph左上角的刷新按钮显示新节点
rostopic list -h   # 查看list子命令需要什么参数
rostopic list -v    # 列出有关每个主题的完整详细信息
rostopic list -p                  # 仅列出发布者
rostopic list -s              # 仅列出订阅者
rostopic type /turtle1/cmd_vel       # 返回正在发布的/turtle1/cmd_vel 主题的消息类型,得到geometry_msgs/Twist
rosmsg show geometry_msgs/Twist  # 查看消息geometry_msgs/Twist的详细信息  
rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'    #rostopic pub [topic] [msg_type] [args]发布有关当前/turtle1/cmd_vel主题的数据。-1:仅发布一条消息然后退出;/ turtle1 / cmd_vel:要发布到的主题的名称;geometry_msgs/Twist:发布到主题时要使用的消息类型;双破折号--:告诉选项解析器以下任何参数都不是一个选项;geometry_msgs / Twist msg具有两个向量,每个向量包含三个浮点元素:线性和角度。在这种情况下,'[2.0,0.0,0.0]'变为线性值,x = 2.0,y = 0.0,z = 0.0'[0.0,0.0,1.8]'是x = 0.0的角度值,y = 0.0,z = 1.8
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1  - '[2.0,0.0,0.0]' '[0.0,0.0,-1.8]'   # rostopic pub -r命令发布稳定的命令流,该命令表示在速度主题上以1 Hz的速率发布速度命令
rostopic list
rostopic echo / turtle1 / pose   #查看我们的turtlesim发布的数据
rostopic hz / turtle1 / pose   # rostopic hz [主题];该命令看看turtlesim_node发布的速度有多快
rosrun rqt_plot rqt_plot    # rqt_plot显示主题上发布的数据的滚动时间图,将左上角的主题添加进来,键入/ turtle1 / pose / x,用来显示乌龟的x位置

8. 了解ROS服务

roscore    # roscore是使用ROS时应该运行的第一件事
rosrun turtlesim turtlesim_node   # 启动乌龟节点
rosrun turtlesim turtle_teleop_key     # 启动键盘驱动节点
rosservice list              # 打印有关活动服务的信息,得到/clear /kill /reset /rosout/get_loggers /rosout/set_logger_level /spawn /teleop_turtle/get_loggers /teleop_turtle/set_logger_level /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtlesim/get_loggers /turtlesim/set_logger_level
rosservice type /clear      # rosservice type [service],打印服务/clear类型,得到std_srvs/Empty,此服务为空,这意味着在进行服务调用时它不带参数(即,在发出请求时不发送数据,在接收响应时不接收数据)
rosservice call /clear       # rosservice call [service] [args],这里我们将调用没有参数,因为服务的类型为empty,将会清除了turtlesim_node的背景。  
rosservice type /spawn | rossrv show    # 通过查看服务spawn的信息来查看服务具有参数的情况,d得到
rosservice call /spawn 2 2 0.2 ""   # 在给定的位置和方向产生一只新的乌龟。name字段是可选的,这里没有取名,让turtlesim为我们创建一个,服务调用返回新创建的乌龟的名称
rosservice find        # 按服务类型查找服务
rosservice uri           # 打印服务
rosparam set            set parameter
rosparam get            get parameter
rosparam load           load parameters from file
rosparam dump           dump parameters to file
rosparam delete         delete parameter
rosparam list           # 看到turtlesim节点在param服务器上有三个参数用于背景颜色,得到/ background_b / background_g / background_r / rosdistro / roslaunch /URI / host_57aea0986fef__34309 / rosversion / run_id
rosparam set /background_r 150   # rosparam set [param_name],更改背景颜色的红色通道,这会更改参数值,但是背景颜色还未改变
rosservice call /clear   # 调用clear服务才能使参数更改生效,此时背景变成红色
rosparam get / background_g    # 看一下param服务器上其他参数/ background_g的值。让我们得到绿色背景的值:
rosparam get /    # 查看整个Parameter Server的内容
rosparam dump params.yaml    #rosparam dump [file_name] [namespace],将所有参数写入文件params.yaml
rosparam load params.yaml copy    #将这些yaml文件加载到新的命名空间copy中
rosparam get /copy/background_b  # 获取copy中的参数/copy/background_b

9. 使用rqt_console和roslaunch

sudo apt-get install ros-indigo-rqt ros-indigo-rqt-common-plugins ros-indigo-turtlesim          # 安装rqt和turtlesim包
rosrun rqt_console rqt_console   # 启动rqt_console并附加到ROS的日志框架以显示节点的输出
rosrun rqt_logger_level rqt_logger_level  # 启动rqt_logger_level它允许我们在节点运行时更改详细级别(DEBUGWARNINFOERROR) 
rosrun turtlesim turtlesim_node   # 在一个新的终端开始turtlesim,默认记录器级别为INFO,您将看到turtlesim在启动时发布的任何信息,这时可以将选择rqt_logger_level的Warn按钮
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.0}}'  # 将乌龟带到墙上,查看rqt_console中显示红色警告,记录级别按以下顺序排列优先级:Fatal(致命) Error(错误) Warn(警告) Info(信息) Debug(调试)
roscd beginner_tutorials   # 转到我们之前创建和构建的beginner_tutorials包:
mkdir launch   # 在beginner_tutorials下创建一个launch启动目录,roslaunch命令自动查看传递的包并检测可用的启动文件
cd launch    # 进入launch文件夹下,创建一个名为turtlemimic.launch的启动文件并粘贴以下内容:

<launch>

  <group ns="turtlesim1">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <group ns="turtlesim2">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <node pkg="turtlesim" name="mimic" type="mimic">
    <remap from="input" to="turtlesim1/turtle1"/>
    <remap from="output" to="turtlesim2/turtle1"/>
  </node>

</launch>

roslaunch beginner_tutorials turtlemimic.launch   # 启动启动文件,roslaunch [package] [filename.launch]
rostopic pub / turtlesim1 / turtle1 / cmd_vel geometry_msgs / Twist -r 1  - '[2.0,0.0,0.0]''[0.0,0.0,-1.8]'  # 发布命令仅发送到turtlesim1,您也会看到两个turtlesims开始移动
rqt_graph   # 启动rqt更好地理解我们的启动文件的作用

9.1 launch启动文件说明

<launch>  //打破启动xml,这里使用启动标记启动启动文件,以便将文件标识为启动文件

//启动两个组,名称空间标签为turtlesim1、turtlesim2为turtlesim节点,名称为sim,这允许我们在没有名称冲突的情况下启动两个模拟器
  <group ns="turtlesim1">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <group ns="turtlesim2">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

//启动模拟节点,主题输入和输出重命名为turtlesim1和turtlesim2,这个重命名会使得turtlesim2模仿turtlesim1
  <node pkg="turtlesim" name="mimic" type="mimic">
    <remap from="input" to="turtlesim1/turtle1"/>
    <remap from="output" to="turtlesim2/turtle1"/>
  </node>

</launch>//关闭启动文件的xml标记

10. 使用rosed编辑ROS中的文件

rosed roscpp Logger.msg       #  rosed [package_name] [filename],允许您使用包名roscpp直接编辑包roscpp中的文件Logger.msg,而不必键入包的整个路径
export EDITOR ='nano -w'   # rosed的默认编辑器是vim,通过编辑〜/ .bashrc文件,将默认编辑器设置为nano, .bashrc中的更改仅对新终端生效。已经打开的终端将看不到新的环境变量
export EDITOR ='emacs -nw'   # 编辑〜/ .bashrc文件,将默认编辑器设置为emacs
echo $ EDITOR    # 打开一个新终端,看看是否定义了EDITOR,得到应该是你更改后的编辑器nano -w或emacs -nw

11. 创建ROS消息msg和服务srv

  • 11.1 创建ROS消息msg

roscd beginner_tutorials    # 进入上一个教程中创建的包beginner_tutorials
mkdir msg         # 在包beginner_tutorials中定义一个新的msg
# 在msg文件夹下新建Num.msg文件,加入以下一行内容:
int64 num

#为了确保将msg文件转换为C ++,Python和其他语言的源代码,打开package.xml,确保下面两行都在其中并取消注释,构建时,我们需要“message_generation”,而在运行时,我们只需要“message_runtime”:
 <build_depend>message_generation</build_depend>
 <exec_depend>message_runtime</exec_depend>

# 打开CMakeLists.txt ,添加下面四项(有的是添加,有的是取消注释)内容,主要是添加message_generation,以便生成消息;添加message_runtime,确保导出消息运行时依赖项;添加 Num.msg,通过手动添加.msg文件,确保CMake知道在添加其他.msg文件后何时必须重新配置项目;取消注释generate_messages:确保调用generate_messages()函数:
find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)

catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...add_message_files(
  FILES
  Num.msg
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

rosmsg show beginner_tutorials/Num # 前面已经完成了准备好从msg定义生成源文件,也是创建一个消息所需要做的一切。rosmsg show [message type]用来查看Num消息的内容,也可以直接用rosmsg show Num
  • 11.2 创建ROS服务srv

roscd beginner_tutorials        # 同样进入上一个教程中创建的包beginner_tutorials
mkdir srv          # 创建srv文件夹
roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv   # 将 rospy_tutorials功能包里面的AddTwoInts.srv服务文件复制到当前功能包下的srv文件夹下面。roscp [package_name] [file_to_copy_path] [copy_path]

#为了确保将srv文件转换为C ++,Python和其他语言的源代码,打开package.xml,确保下面两行都在其中并取消注释,同样,构建时,我们需要“message_generation”,而在运行时,我们只需要“message_runtime”:
 <build_depend>message_generation</build_depend>
 <exec_depend>message_runtime</exec_depend>

# 打开CMakeLists.txt ,添加下面四项(有的是添加,有的是取消注释)内容,主要是添加message_generation(适用于msg和srv),以便生成服务;添加message_runtime,确保导出服务运行时依赖项;添加 AddTwoInts.srv,通过手动添加.srv文件,确保CMake知道在添加其他.srv文件后何时必须重新配置项目;取消注释generate_messages:确保调用generate_messages()函数:
find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)

catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...add_service_files(
  FILES
  AddTwoInts.srv
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

rossrv show beginner_tutorials/AddTwoInts  # 前面已经完成了准备好从srv定义生成源文件。rossrv show <service type>,与rosmsg类似,您可以在不指定包名的情况下找到这样的服务文件rossrv show AddTwoInts,显示了两个服务,第一个是你刚刚在beginner_tutorials包中创建的那个,第二个是rospy_tutorials包中预先存在的那个。
  • 11.3 msg和srv简介

msg文件是描述ROS消息字段的简单文本文件。它们用于生成不同语言的消息的源代码
srv文件描述服务。它由两部分组成:请求和响应。

msg文件存储在包的msg目录中,srv文件存储在srv目录中。

msgs只是简单的文本文件,每行有一个字段类型和字段名称。您可以使用的字段类型是:
int8, int16, int32, int64 (plus uint*)
float32, float64
string
time, duration
other msg files
variable-length array[] and fixed-length array[C] 

ROS中还有一种特殊类型:标题,标题包含ROS中常用的时间戳和坐标框架信息。您经常会看到msg文件中的第一行有Header头。以下是使用标头,字符串基元和另外两个消息的消息的示例:
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist

srv文件就像msg文件一样,除了它们包含两部分:请求和响应。这两部分用'---'线分开。以下是srv文件的示例(AB是请求,Sum是响应):
int64 A
int64 B
---
int64 Sum
  • 11.4 msg和srv的常用步骤

# 更改CMakeLists.txt(取消注释并添加您依赖的任何包)
generate_messages(
  DEPENDENCIES
  std_msgs
)
# 现在我们已经发了一些新消息,我们需要再次制作我们的包执行下面四行操作
roscd beginner_tutorials                         # 回到 beginner_tutorials包下
cd ../..              # 回到工作空间catkin_ws下
catkin_make install            # 再次制作
cd -      # 回到 beginner_tutorials包下

#执行完上面的操作后,msg目录中的任何.msg文件都将生成用于所有支持语言的代码。C ++消息头文件将在〜/ catkin_ws / devel / include / beginner_tutorials /中生成。Python脚本将在〜/ catkin_ws / devel / lib / python2.7 / dist-packages /beginner_tutorials / msg中创建。lisp文件出现在〜/ catkin_ws / devel / share / common-lisp / ros / beginner_tutorials / msg /中。同样,srv目录中的任何.srv文件都将使用受支持的语言生成代码。对于C ++,这将在与邮件头文件相同的目录中生成头文件。对于Python和Lisp,'msg'文件夹旁边会有一个'srv'文件夹。如果要构建使用新消息的C ++节点,则还需要在节点和消息之间声明依赖关系,参见:http://docs.ros.org/latest/api/catkin/html/howto/format2/building_msgs.html
  • 11.5获取帮助

rosmsg -h        #查看rosmsg子命令的列表
rosmsg  show -h         #获得子命令的帮助

12. 编写简单的发布者和订阅者(​​C ++)

  • 12.1 编写简单的发布者节点

roscd beginner_tutorials   # 回到功能包beginner_tutorials下
mkdir -p src       # -p表示确定目录名称beginner_tutorials存在,如果目录不存在的就新创建一个beginner_tutorials
# 在src下新建一个talker.cpp文件,代码如下
#include "ros/ros.h"
#include "std_msgs/String.h"

#include <sstream>

/**
 * This tutorial demonstrates simple sending of messages over the ROS system.
 */
int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line. For programmatic
   * remappings you can use a different version of init() which takes remappings
   * directly, but for most command-line programs, passing argc and argv is the easiest
   * way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "talker");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The advertise() function is how you tell ROS that you want to
   * publish on a given topic name. This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing. After this advertise() call is made, the master
   * node will notify anyone who is trying to subscribe to this topic name,
   * and they will in turn negotiate a peer-to-peer connection with this
   * node.  advertise() returns a Publisher object which allows you to
   * publish messages on that topic through a call to publish().  Once
   * all copies of the returned Publisher object are destroyed, the topic
   * will be automatically unadvertised.
   *
   * The second parameter to advertise() is the size of the message queue
   * used for publishing messages.  If messages are published more quickly
   * than we can send them, the number here specifies how many messages to
   * buffer up before throwing some away.
   */
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  /**
   * A count of how many messages we have sent. This is used to create
   * a unique string for each message.
   */
  int count = 0;
  while (ros::ok())
  {
    /**
     * This is a message object. You stuff it with data, and then publish it.
     */
    std_msgs::String msg;

    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

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

    /**
     * The publish() function is how you send messages. The parameter
     * is the message object. The type of this object must agree with the type
     * given as a template parameter to the advertise<>() call, as was done
     * in the constructor above.
     */
    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;
  }


  return 0;
}

  • 12.1.1 talker.cpp代码分析

#include "ros/ros.h"      //包括使用ROS系统最常见的公共部分所需的所有标题
#include "std_msgs/String.h"    //包括std_msgs/String消息,该消息在std_msgs包中
#include <sstream>

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);   //告诉master我们将在主题聊天中发布类型为std_mags/String的消息,这让master告诉任何监听聊天节点的节点,我们将发布关于该主题的数据。第二个参数是我们的发布队列的大小。在这种情况下,如果我们发布得太快,它将在开始丢弃旧消息之前缓冲最多1000条消息。

  ros::Rate loop_rate(10);  //使用ros :: Rate对象可以指定要循环的频率。它将跟踪自上次调用Rate :: sleep()以来的持续时间,并在正确的时间内休眠。这里我们告诉它我们想要以10Hz运行

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

    std::stringstream ss;
    ss << "hello world " << count;   //发布消息,通常从msg文件生成
    msg.data = ss.str();    //使用标准的String消息,它有一个成员:“data”

    ROS_INFO("%s", msg.data.c_str());  //ROS_INFO类似于printf / cout

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

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

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


  return 0;
}
  • 12.2 编写简单的订阅者节点

roscd beginner_tutorials   # 回到功能包beginner_tutorials下
mkdir -p src       # -p表示确定目录名称beginner_tutorials存在,如果目录不存在的就新创建一个beginner_tutorials
# 在src下新建一个listener.cpp文件,代码如下
#include "ros/ros.h"
#include "std_msgs/String.h"

/**
 * This tutorial demonstrates simple receipt of messages over the ROS system.
 */
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "listener");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  /**
   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
   */
  ros::spin();

  return 0;
}
  • 12.2.1listener.cpp代码分析

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

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

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


  ros::NodeHandle n;

  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);     //与master订阅聊天主题。每当有新消息到达时,ROS都会调用chatterCallback()函数。第二个参数是队列大小,以防我们无法足够快地处理消息。在这种情况下,如果队列达到1000条消息,我们将在新消息到达时开始丢弃旧消息


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

  return 0;
}

  • 12.3 构建节点

# 将这几行添加到CMakeLists.txt最底部(这将创建两个可执行文件,talker和listener,默认情况下位于〜/ catkin_ws / devel / lib / <package name>。)
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

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

# 生成的CMakeLists.txt如下所示:
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)

find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)  ##找到catkin和任何catkin包

add_message_files(FILES Num.msg)##声明ROS消息
add_service_files(FILES AddTwoInts.srv) ##声明ROS服务

generate_messages(DEPENDENCIES std_msgs)##生成添加的消息和服务

catkin_package()##宣告一个catkin包

include_directories(include ${catkin_INCLUDE_DIRS})  ##建立talker和listener

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})  ##如果您使用catkin工作区内其他包的消息,使用catkin_LIBRARIES来依赖所有必需的目标
add_dependencies(talker beginner_tutorials_generate_messages_cpp)  ##将可执行目标的依赖项添加到邮件生成目标,这样可以确保在使用之前生成此包的​​邮件头。

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

# 回到工作空间
cd ~/catkin_ws
catkin_make --pkg beginner_tutorials
  • 12.4 检查简单的Publisher和Subscriber

roscore  #启动master
cd ~/catkin_ws
source ./devel/setup.bash
rosrun beginner_tutorials talker       #运行发布者(c++)
rosrun beginner_tutorials listener         #运行订阅者接收来自发布者的消息(C++)

13. 编写简单的发布者和订阅者(​​Python)

  • 13.1 编写发布者节点

roscd beginner_tutorials   # 回到功能包beginner_tutorials下
mkdir scripts       # 创建一个'scripts'文件夹来存储我们的Python脚本
cd scripts
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py       # 将示例脚本talker.py下载到新脚本scripts目录
chmod +x talker.py          # 使示例脚本talker.py可执行
rosed beginner_tutorials talker.py      # 可以执行此句查看和编辑该文件
  • 13.1.1 talker.py代码分析

#!/usr/bin/env python            # 每个Python ROS节点都会在顶部显示此声明。第一行确保您的脚本作为Python脚本执行
# license removed for brevity
import rospy      # 导入rospy
from std_msgs.msg import String     # std_msgs.msg使我们可以重新使用std_msgs /String用于发布消息类型(一个简单的字符串容器)

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)    #这部分代码定义了talker与其余ROS的接口,声明Publisher节点使用消息类型String发布到chatter主题。这里的字符串实际上是类std_msgs.msg.String。该的queue_size参数是限制排队的消息的数量,如果任何用户不足够快地接收他们
    rospy.init_node('talker', anonymous=True)    #告诉rospy节点的名称为talker,直到rospy有这个信息,它才能开始与ROS Master通信,nonymous = True通过在NAME末尾添加随机数来确保您的节点具有唯一名称
    rate = rospy.Rate(10)   # 创建Rate对象速率。借助其方法sleep(),它提供了一种以所需速率循环的便捷方式。它的参数为10,我们应该期望每秒循环10次(只要我们的处理时间不超过1/10秒!)
    while not rospy.is_shutdown():   # 这个循环是一个相当标准的rospy构造:检查rospy.is_shutdown()标志然后做工作,你必须检查is_shutdown()以检查你的程序是否应该退出(例如,如果有Ctrl-C或其他)
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)   # 这个循环还调用rospy.loginfo(str),它执行三重任务:消息被打印到屏幕,它被写入Node的日志文件,并被写入rosout,对于调试非常方便:您可以使用rqt_console来提取消息,而不必使用Node的输出找到控制台窗口
        pub.publish(hello_str)
        rate.sleep()  # 循环调用rate.sleep(),它睡眠的时间足够长,可以通过循环保持所需的速率

if __name__ == '__main__':     #检查标准的Python __main__,这还会捕获一个rospy.ROSInterruptException异常,当按下Ctrl-C或者你的节点关闭时,rospy.sleep()和rospy.Rate.sleep()方法可以抛出该异常。引发此异常的原因是,您不会在sleep()之后意外地继续执行代码。
    try:
        talker()
    except rospy.ROSInterruptException:  # 捕获一个rospy.ROSInterruptException异常
        pass
  • 13.2 编写简单的订阅者节点

roscd beginner_tutorials/scripts /
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py     # 将示例脚本listener.py下载到新脚本scripts目录
chmod +x listener.py          # 使示例脚本listener.py可执行
  • 13.2.1 listener.py代码分析

#!/usr/bin/env python    # listener.py的代码类似于talker.py,除了我们引入了一个新的基于回调的机制来订阅消息

import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + 'I heard %s', data.data)

def listener():
   
    rospy.init_node('listener', anonymous=True)  # 添加了anonymous = True关键字参数。ROS要求每个节点都有唯一的名称。如果出现具有相同名称的节点,则会突然显示前一个节点。这样可以很容易地将故障节点从网络中踢出。anonymous=True告诉rospy为节点生成一个唯一的名称,以便可以有多个listener.py节点轻松运行。

    rospy.Subscriber('chatter', String, callback)    # 节点订阅的话题类型是std_msgs.msgs.String,收到新消息时,将调用回调,并将消息作为第一个参数
    
rospy.spin()     #spin()只是让python节点退出,直到该节点停止。与roscpp不同,rospy.spin()不会影响订阅者回调函数,因为它们有自己的线程。

if __name__ == '__main__':
    listener()
  • 13.3 构建节点

cd ~/catkin_ws
catkin_make --pkg beginner_tutorials
  • 13.4 检查简单的发布者和订阅者

roscore  #启动master
cd ~/catkin_ws
source ./devel/setup.bash
rosrun beginner_tutorials talker.py    #运行发布者(python)
rosrun beginner_tutorials listener.py       #运行订阅者接收来自发布者的消息(Python)

14. 编写简单的服务和客户端(C ++)

  • 14.1 编写简单的服务端节点

roscd beginner_tutorials
# 在src文件夹下创建add_two_ints_server.cpp文件,代码如下
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

bool add(beginner_tutorials::AddTwoInts::Request  &req,
         beginner_tutorials::AddTwoInts::Response &res)
{
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}
  • 14.1.1 add_two_ints_server.cpp代码分析

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"     # beginner_tutorials / AddTwoInts.h是从我们之前创建的srv文件生成的头文件

bool add(beginner_tutorials::AddTwoInts::Request  &req,
         beginner_tutorials::AddTwoInts::Response &res)    # add函数提供添加两个int的服务,它接受srv文件中定义的请求和响应类型并返回一个布尔值。
{
  res.sum = req.a + req.b;     #添加了两个整数并存储在响应中。然后记录有关请求和响应的一些信息。
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;      #最后,服务在完成后返回true
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", add);   #这里的服务是通过ROS创建和订阅的
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}
  • 14.2 编写客户端节点

#在beginner_tutorials包中创建src / add_two_ints_client.cpp文件,代码如下
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_client");
  if (argc != 3)
  {
    ROS_INFO("usage: add_two_ints_client X Y");
    return 1;
  }

  ros::NodeHandle n;
  ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
  beginner_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  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;
}
  • 14.2.1 add_two_ints_client.cpp代码分析

ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");    # 为add_two_ints服务创建一个客户端。该ROS :: ServiceClient对象用于以后调用服务

beginner_tutorials::AddTwoInts srv; # 实例化一个自动生成的服务类,并将值分配给它的请求成员。服务类包含两个成员,即请求和响应。它还包含两个类定义,Request和Response
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);

if (client.call(srv)) # 这实际上是调用服务。由于服务调用是阻塞的,因此一旦调用完成,它将返回。如果服务调用成功,则call()将返回true,并且srv.response中的值将有效。如果调用未成功,则call()将返回false,并且srv.response中的值将无效
  • 14.3 构建节点

# 编辑位于〜/ catkin_ws / src / beginner_tutorials / CMakeLists.txt的beginner_tutorials CMakeLists.txt,并在最后添加以下内容(创建两个可执行文件add_two_ints_server和add_two_ints_client,默认情况下位于〜/ catkin_ws / devel / lib / <package name>。您可以直接调用可执行文件,也可以使用rosrun来调用它们。它们不会放在'<prefix> / bin'中,因为在将软件包安装到系统时会污染PATH。如果您希望在安装时将可执行文件放在PATH上,可以设置安装目标,请参阅:http://wiki.ros.org/catkin/CMakeLists.txt)add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)

add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)

# 回到工作空间
cd ~/catkin_ws
catkin_make --pkg beginner_tutorials
  • 14.4 运行节点

roscore  # 启动master
rosrun beginner_tutorials add_two_ints_server   # 运行服务器
rosrun beginner_tutorials add_two_ints_client 1 3  # 运行客户端

15. 编写简单的服务和客户端(Python)

  • 15.1 编写服务端节点

roscd beginner_tutorials
# 在beginner_tutorials包中创建scripts / add_two_ints_server.py文件,代码如下:
#!/usr/bin/env python

from beginner_tutorials.srv import *
import rospy

def handle_add_two_ints(req):
    print "Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))
    return AddTwoIntsResponse(req.a + req.b)

def add_two_ints_server():
    rospy.init_node('add_two_ints_server')
    s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
    print "Ready to add two ints."
    rospy.spin()

if __name__ == "__main__":
    add_two_ints_server()

chmod +x add_two_ints_server.py          # 使示例脚本add_two_ints_server.py可执行
  • 15.1.1 add_two_ints_server.py代码分析

s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)    # 使用AddTwoInts服务类型声明一个名为add_two_ints的新服务。所有请求都传递给handle_add_two_ints函数。handle_add_two_ints被调用的情况下AddTwoIntsRequest和返回的实例AddTwoIntsResponse。就像订阅者示例一样,rospy.spin()使代码不会退出,直到服务关闭。
  • 15.2 编写客户端节点

# 在beginner_tutorials包中创建scripts / add_two_ints_client.py文件
#!/usr/bin/env python

import sys
import rospy
from beginner_tutorials.srv import *

def add_two_ints_client(x, y):
    rospy.wait_for_service('add_two_ints')
    try:
        add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
        resp1 = add_two_ints(x, y)
        return resp1.sum
    except rospy.ServiceException, e:
        print "Service call failed: %s"%e

def usage():
    return "%s [x y]"%sys.argv[0]

if __name__ == "__main__":
    if len(sys.argv) == 3:
        x = int(sys.argv[1])
        y = int(sys.argv[2])
    else:
        print usage()
        sys.exit(1)
    print "Requesting %s+%s"%(x, y)
    print "%s + %s = %s"%(x, y, add_two_ints_client(x, y))

cd scripts
chmod +x scripts/add_two_ints_client.py    # 使示例脚本add_two_ints_client.py可执行
  • 15.2.1 add_two_ints_client.py代码分析

rospy.wait_for_service('add_two_ints')    # 对于客户端,不必调用init_node()
add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)  # 创建一个用于调用服务的句柄
resp1 = add_two_ints(x, y)  # 使用这个句柄并调用它
return resp1.sum   #因为已经将服务的类型声明为AddTwoInts,所以它会生成AddTwoIntsRequest对象(您可以自由传递)。返回值是AddTwoIntsResponse对象。如果调用失败,可能会抛出rospy.ServiceException
  • 15.3 构建节点

# 回到工作空间
cd ~/catkin_ws
catkin_make --pkg beginner_tutorials
  • 15.4 运行节点

roscore  # 启动master
rosrun beginner_tutorials add_two_ints_server.py      # 运行服务器
rosrun beginner_tutorials add_two_ints_client.py 1 3     # 运行客户端

16. 录制和播放数据

  • 16.1 记录所有主题数据

roscore
rosrun turtlesim turtlesim_node 
rosrun turtlesim turtle_teleop_key
rostopic list -v     # 检查系统中当前正在运行的每个主题的完整详细信息
mkdir ~/bagfiles  # 创建一个临时目录bagfiles来记录数据
cd ~/bagfiles
rosbag record -a   # 使用选项-a 运行rosbag记录,记录了所有节点发布的所有消息。
rosbag info <your bagfile>   # 检查bag文件的内容而不回放
rosbag play <your bagfile>   # 重播bag文件以重现正在运行的系统中的行为
rosbag play -r 2 <your bagfile>  # r选项,它允许您按指定因子更改发布速率(发出的键盘命令速度提高了两倍)
  • 16.2 记录感兴趣的主题数据

roscore
rosrun turtlesim turtlesim_node 
rosrun turtlesim turtle_teleop_key
rosbag record -O subset /turtle1/cmd_vel /turtle1/pose    # 只记录/turtle1/cmd_vel和/turtle1/pose这两个主题数据到subset.bag文件中
rosbag info subset.bag       # 检查包subset.bag 文件的内容
rosbag play subset.bag     # 重播subset.bag文件以重现行为
  • 16.3 rosbag记录/播放的局限性

乌龟的路径可能没有完全映射到原始键盘输入 - 粗糙的形状应该是相同的,但乌龟可能没有完全跟踪相同的路径。这样做的原因是turtlesim跟踪的路径对系统中的时间的微小变化非常敏感,并且rosbag在能够根据rosrecord记录和处理消息时精确复制正在运行的系统的行为的能力受到限制。 ,以及使用rosplay时生成和处理消息的时间。对于像turtlesim这样的节点,当处理命令消息时微小的时序变化可以巧妙地改变行为,用户不应该期望完全模仿行为。

17. roswtf

  • 17.1 roswtf简单介绍

可以检查您的ROS设置,比如环境变量,并查找配置问题。如果您有在线ROS系统,它会查看它并检查是否存在任何潜在问题。

ps -ef | grep -i rosmaster    # 该命令用来查看roscore是否在运行,如果存在某个路径中存在roscore,则表示roscore正在运行
# 下面两行命令用来检查安装,如果安装正确运行,则输出no error啥的
roscd rosmaster 
roswtf
# 下面进行在线尝试,需要master运行,发现结果有错误
roscore    
roscd
roswtf
  • 17.2 roswtf工具

roswtf    # 检查当前包或堆栈的问题
roswtf yourfile.launch      # 检查给定的启动文件是否存在任何潜在问题,例如尚未正确构建的软件包
1. 检查文件系统问题:查看您的环境变量,包配置,堆栈配置等。它还可以接收roslaunch文件并尝试在其中查找任何潜在的配置问题,例如尚未正确构建的软件包。
2. 检查在线问题:检查您当前图表的状态,并尝试查找任何潜在问题。这些问题可能是无响应的节点,节点之间缺少连接,或者是roslaunch潜在机器配置问题
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值