ROS学习笔记-基础

一、基础复习
1.1 初始化工作环境
打开控制台窗口,输入以下命令,建立第一个工作环境。之后将工作环境添加到ROS路径变量当中,并进行查看。

$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/
$ catkin_make
$ source devel/setup.bash
$ echo $ROS_PACKAGE_PATH

1.2 简单的ROS命令
下面代码分别是:
查找并返回package的位置,
查找某个package下面的子文件夹,
读取日志文件夹,
打印当前路径,
显示package下面的所有目录文件
借助TAB键来完成快速输入

$ rospack find [package_name]
$ roscd [locationname[/subdir]]
$ roscd log
$ pwd
$ rosls [locationname[/subdir]]
$ roscd roscpp_tut<<< now push the TAB key >>>

1.3 创建ROS package
ROS package具有以下的特点,所有的package都在src的下面一层目录,而且并行的CMakeLists.txt负责对packages进行管理,package.xml负责对package进行解释。

workspace_folder/        -- WORKSPACE
  src/                   -- SOURCE SPACE
    CMakeLists.txt       -- 'Toplevel' CMake file, provided by catkin
    package_1/
      CMakeLists.txt     -- CMakeLists.txt file for package_1
      package.xml        -- Package manifest for package_1
    ...
    package_n/
      CMakeLists.txt     -- CMakeLists.txt file for package_n
      package.xml        -- Package manifest for package_n

要创建ROS Package,执行以下代码:

$ cd ~/catkin_ws/src
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
# catkin_create_pkg  [depend1] [depend2] [depend3]

要查看package的创建依赖文件,执行以下代码:

$ rospack depends1 beginner_tutorials 
$ rospack depends1 rospy
$ rospack depends beginner_tutorials

1.4 编译package
在创建完成package之后,执行以下代码对package中内容进行编译

$ cd ~/catkin_ws
$ catkin_make

需要注意的是,编译之后会多产生两个文件夹:

build
devel

build文件夹是默认编译package的位置,devel文件夹是executables 和 libraries 运行的位置
1.5 ROS 节点和其他的概念理解
1.5.1概念
Nodes: 与其他Node可以相互交流的节点,通常为.cpp文件
Messages: 节点通讯时传输的ROS data type
Topics: 节点发布信息的地方
Master: 为了帮助节点能够找到彼此设置的Name service
rosout: ROS 中的输出面板,也就是显示器
roscore: 在运行ROS中节点时需要启动的项
ROS 有两个client libraries,它允许使用python语言和c++语言的节点能够互相通讯 allow
rospy = python client library
roscpp = c++ client library
1.5.2 关于ROS节点的一些命令:
显示正在运行的ROS节点,
查看某个节点的信息
运行某个package下面的节点
为节点更改名称

$ rosnode list
$ rosnode info [节点名称](/rosout)
$ rosrun [package_name] [node_name]
$ rosrun turtlesim turtlesim_node __name:=my_turtle

1.6 关于ROS话题的一些命令
1.6.1用话题图查看当前的通讯状态

$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun turtlesim turtle_teleop_key
之后运行
$ rosrun rqt_graph rqt_graph

通过使用话题图的refresh按钮可以更新话题状态
1.6.2 查看rostopic 命令

$ rostopic -h

1.6.3 针对上述的rostopic 进行说明

rostopic echo [topic] 通过对topic进行订阅,从而查看topic发出的信息

$ rostopic echo /turtle1/cmd_vel

rostopic list 返回当前正在订阅topic和正在发布消息的topic

   $ rostopic list -h

rostopic type [topic] ,由于消息的发布者和接收者都要接受同种消息类型,所以rostopic的类型实际上是由消息来决定的,要查看rostopic的类型使用命令:rostopic type [topic] 和 rosmsg show [type]

 $ rostopic type /turtle1/cmd_vel

之后返回:geometry_msgs/Twist

$ rosmsg show geometry_msgs/Twist

之后返回该类型具体包含的内容
rostopic pub 给某个正在运行的话题发送新的消息,使用命令:rostopic pub [topic] [msg_type] [args]

$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'

-1:发送一条消息之后立即退出
两个-- :由于有的参数为负数(-),所以为了避免歧义,告诉选项解析器以下内容不是选项。
两个数组: linear value with x=2.0, y=0.0, and z=0.0, and angular value with x=0.0, y=0.0, z=1.8.

**rostopic hz [topic]**某个话题发布消息的频率,使用命令:rostopic hz [topic]

$ rostopic hz /turtle1/pose
$ rostopic type /turtle1/cmd_vel | rosmsg show 使用内连查看话题类型的同时显示话题信息

1.6.4 显示话题的数据-时间图
执行以下命令

$ rosrun rqt_plot rqt_plot

在弹出的文本框左上角,添加显示的话题,如
/turtle1/pose/x /turtle1/pose/theta

1.7 ROS service & rosparam
节点发送请求,然后service会返回结果给节点。rosservice可以通过服务轻松附加到ROS的客户端/服务框架。 rosservice有许多可用于主题的命令,如下所示:

rosservice list         print information about active services
rosservice call         call the service with the provided args
rosservice type         print service type
rosservice find         find services by service type
rosservice uri          print service ROSRPC uri

1.7.1
rosservice list

$ roscore
$ rosrun turtlesim turtlesim_node
$ rosservice list

之后弹出turtlesim_node提供的服务列表
rosservice type通常和call一起使用
rosservice type

$ rosservice type /clear

之后弹出std_srvs/Empty,这意味着当我们使用下面的call命令时他不会接受发送的任何参数,而是直接执行自己的固有使命,清除所有轨迹

rosservice call [service] [args]

$ rosservice call /clear

之后会将界面上的运动轨迹都清除,针对一些需要使用参数的type,运行以下的代码:

$ rosservice type /spawn | rossrv show

之后会弹出我们调用call命令时需要提供的参数,如下所示:
其中,string name是可选的

float32 x
float32 y
float32 theta
string name
---
string name

执行以下代码:

$ rosservice call /spawn 2 2 0.2 ""

1.7.2 rosparam
我们可以存储一些数据在ROS的参数服务器上,从而方便我们之后进行调用。参数的命令有以下几个:set, get, load, dump, delete, list,下面分别说明
rosparam list
运行以下代码,之后返回 turtlesim node 调用的参数服务器上的参数

$ rosparam list

rosparam set [param_name]
运行以下代码,可以看到参数background_r被设置成了150

$ rosparam set /background_r 150

rosparam get [param_name]
运行以下代码,分别获取特定的参数值和所有的参数值

$ rosparam get /background_g 
$ rosparam get /

rosparam dump [file_name] [namespace]
rosparam load [file_name] [namespace]

运行以下代码,分别将所有参数写入params.yaml文件中,将params.yaml文件载入到命名空间copy中

$ rosparam dump params.yaml
$ rosparam load params.yaml copy
$ rosparam get /copy/background_b

1.8 使用rqt_console 和roslaunch
1.8.1 rqt_console通常和rqt_logger_level一起使用来获取节点输出的信息。logger_level用来改变日志等级从而确定要显示的内容。运行以下命令:

$ rosrun rqt_console rqt_console
$ rosrun rqt_logger_level rqt_logger_level

在新的terminal运行

$ rosrun turtlesim turtlesim_node

此时可以通过调整logger_level在console面板看到不同的日志信息,level分为五个等级,Fatal,Error, Warn, Info, Debug.后面的等级越来越高。
1.8.2 使用roslaunch
roslaunch命令,将所有要执行的命令写在一起,按顺序运行,它会在给定的package中自动寻找要执行的.launch文件,因此不必单独设置文件夹,但是为了界面简洁,一般要设置一个,如下所示:

$ cd ~/catkin_ws
$ source devel/setup.bash
$ roscd beginner_tutorials
$ mkdir launch
$ cd launch

在launch file下面创建一个turtlemimic.launch文本,粘贴以下代码:
要查看标签的解释,请参考launch文件详解

    //声明文件是launch类型

  //建立命名空间标签1,发动node
    
  

  //建立命名空间标签2,发动node
    
  

  //发动node mimic
    //输入mimic的话题名改为1
    //输入mimic的话题名改为2
  


1.9 编辑文档
使用linux自带的文本编辑器
1.10 创建消息和服务
msg:msg文件是用来产生消息的源代码,通常是存储在package的msg directory中的描述消息类型的文本文件,消息类型主要有:int8, int16, int32, int64 (plus uint*), float32, float64
string, time, duration,other msg files,variable-length array[] and fixed-length array[C].还有一类是Header类型,它包含有timestamp和坐标框架信息。
srv: srv文件与msg文件类似,只不过多了’- - -'这个符号:
int 64 A
符号
int64 sum
上面的int64A是request,int64 sum就是响应
1.10.1 新建msg
输入以下代码:

$ roscd beginner_tutorials
$ mkdir msg
$ echo "int64 num" > msg/Num.msg

之后将msg文件转换为c++或者python语言的源代码,打开package.xml文件,添加两行代码:

  message_generation
  message_runtime

为了从源代码产生消息,打开CMakeLists.txt文件,添加如下代码:

find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...)
  add_message_files(   #确保添加了其他msg文件时能够重新配置项目
  FILES
  Num.msg
)
generate_messages(
  DEPENDENCIES
  std_msgs
)

之后使用rosmsg show 命令查看传递的消息类型:

$ rosmsg show beginner_tutorials/Num
$ rosmsg show Num

1.10.2新建服务
从roscp_tutorials 包中拷贝.srv文件,执行以下代码:

$ roscd beginner_tutorials
$ mkdir srv
$ roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv

在CMakeLists.txt文件下添加代码:

add_service_files(
  FILES
  AddTwoInts.srv
)

之后使用rossrv show命令查看服务数据的类型

$ rossrv show beginner_tutorials/AddTwoInts
$ rossrv show AddTwoInts

1.11 编写Publisher Node和Subscriber Node
1.11.1 Publisher
在之前创建的beginner_tutorials package下面的src文件夹拷贝代码到talker.cpp,节点名称必须唯一

#include "ros/ros.h"
#include "std_msgs/String.h"
#include 
int main(int argc, char **argv)
{

  ros::init(argc, argv, "talker");  //初始化系统和节点名称
  ros::NodeHandle n;    建立句柄n和ROS System通讯,第一个句柄将会初始化节点,最后一个会关闭Node
  
  ros::Publisher chatter_pub = n.advertise("chatter", 1000);  使用n下面的advertise成员函数,该函数告诉master该文件将会在chatter topic发布消息,并通知到所有已经订阅该topic的node.1000表示buffer最多1000个messages,超出之后队列前面的就会被踢出。

  ros::Rate loop_rate(10);//发布频率为10hz
  int count = 0;
  while (ros::ok())  False的情况:1.按下Ctrl+c 2.被另一个同名的节点挤出 3. ros:: shutdown()函数被调用 4.所有的NodeHandles都被摧毁
  {
 
    std_msgs::String msg;

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

    ROS_INFO("%s", msg.data.c_str());  //代替printf输出到屏幕
    chatter_pub.publish(msg);
    ros::spinOnce(); //为了后续执行回调函数
    loop_rate.sleep();
    ++count;
  }


  return 0;
}

1.11.2 Subscriber
在src文件夹下面拷贝代码到listener.cpp文件:

#include "ros/ros.h"
#include "std_msgs/String.h"
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;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);订阅chatter话题,调用回调函数,当超出1000messages之后清除之前的消息。
  ros::spin();  回调函数再次循环,指导ros::ok()变为false

  return 0;
}

1.11.3 配置CMakeLists.txt和package.xml环境
由于package.xml在之前已经添加了message的内容,所以只需要配置CMakeLists.txt文件,添加如下代码到末尾:

include_directories(include ${catkin_INCLUDE_DIRS})

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)

1.13 检查是否正确运行
执行以下代码:

$ roscore
$ rosrun beginner_tutorials talker  
$ rosrun beginner_tutorials listener   

1.14 编写Service类型和Client类型的Node
1.14.1 Service Node
在src文件夹下面创建add_two_ints_server.cpp 文件,粘贴以下代码:

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h" //之前建立的AddTwoInts.srv文件中获得

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);广播服务“add_two_ints",并执行add函数
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}

1.14.2 Client Node
在src文件夹下面创建add_two_ints_client.cpp文件,粘贴以下代码:

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include 

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("add_two_ints"); 实例化客户端的一个client对象,并使用add_two_ints服务
  beginner_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);   给传递到服务器的两个参数a,b赋值
  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;
}

1.14.3 编译
在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)

1.14.4 测试
运行以下代码:

$ roscore
$ rosrun beginner_tutorials add_two_ints_server
$ rosrun beginner_tutorials add_two_ints_client 1 3

之后会显示发送的请求和响应数据
1.17 记录和回放数据
1.17.1记录所有topic data
为了记录ROS系统上的topic data,一般都将这些数据存储在bag文件夹中,只有已经被发布的消息才能被记录下来。运行以下代码:

$roscore
$rosrun turtlesim turtlesim_node 
$rosrun turtlesim turtle_teleop_key
$mkdir ~/bagfiles
$cd ~/bagfiles
$rosbag record -a

此时在bagfiles中已经生成了记录的数据文件,之后使用命令rosbag info 和rosbag play来分别查看bag中存放的数据和对数据进行回放

$rosbag info 
$rosbag play 

在默认条件下rosbag play会在广播消息停止之后2s开始发布bagfiles中的数据,为了避免订阅者会丢失前几个数据,停止的时间可以通过-d 参数来修改。
运行rosbag play和乌龟移动之间的这段时间长度应该大约等于原始rosbag记录执行和在教程开始部分从键盘发出命令之间的时间。通过使用-s参数来修改这段时间
通过使用-r参数可以改变发布速率,如下面代码所示:

$rosbag play -r 2 

1.17.2记录特定topic data
执行以下代码:

$rosrun turtlesim turtlesim_node 
$rosrun turtlesim turtle_teleop_key
$rosbag record -O subset /turtle1/cmd_vel /turtle1/pose

-O参数:将data记录到subset.bag文件中
/turtle1/cmd_vel /turtle1/pose:只记录这两个topic的数据
1.18 使用roswtf检查输入命令有无错误
执行以下代码:

$ roscd rosmaster
$ roswtf

显示类似如下:

Package: rosmaster     //当前运行的directory
================================================================================
Static checks summary:

No errors or warnings
================================================================================

ROS Master does not appear to be running.    //roscore没有运行
Online graph checks will not be run.
ROS_MASTER_URI is [http://localhost:11311]

执行以下代码:

$ roscd
$ ROS_PACKAGE_PATH=bad:$ROS_PACKAGE_PATH roswtf

显示如下:

Stack: ros
======================================================
Static checks summary:

Found 1 error(s).

ERROR Not all paths in ROS_PACKAGE_PATH [bad] point to an existing directory: 
 * bad
//显示PATH变量赋值有问题
======================================================

Cannot communicate with master, ignoring graph checks

你可能感兴趣的:(ROS学习笔记-基础)