ROS学习第二讲20181124

创建工作空间

1.创建工作空间

方法一:1.直接在/home/下建文件夹catkin_ws/src
2.在src文件下打开终端使用如下命令来把文件夹src初始化为ROS的工作空间

➜  src catkin_init_workspace 
Creating symlink "/home/tangshp/catkin_ws/src/CMakeLists.txt" pointing to "/opt/ros/kinetic/share/catkin/cmake/toplevel.cmake"

方法二:直接使用命令完成

~ mkdir -p ~/catkin_ws/src
➜  ~ cd ~/catkin_ws/src
➜  src catkin_init_workspace 
Creating symlink "/home/tangshp/catkin_ws/src/CMakeLists.txt" pointing to "/opt/ros/kinetic/share/catkin/cmake/toplevel.cmake"

会在src文件夹下生成一个CMakeLists.txt文件(该文件里的内容就会告诉系统这是一个ROS的工作空间)
在这里插入图片描述

2.编译工作空间

所有需要使用catkin的命令来完成编译都要在catkin_ws文件夹下的终端进行

➜  src cd ..#返回父级文件夹
➜  catkin_ws catkin_make #在catkin_ws中用指令catkin_make来完成编译
Base path: /home/tangshp/catkin_ws
Source space: /home/tangshp/catkin_ws/src
Build space: /home/tangshp/catkin_ws/build
Devel space: /home/tangshp/catkin_ws/devel
Install space: /home/tangshp/catkin_ws/install
####
#### Running command: "cmake /home/tangshp/catkin_ws/src -DCATKIN_DEVEL_PREFIX=/home/tangshp/catkin_ws/devel -DCMAKE_INSTALL_PREFIX=/home/tangshp/catkin_ws/install -G Unix Makefiles" in "/home/tangshp/catkin_ws/build"
####
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Using CATKIN_DEVEL_PREFIX: /home/tangshp/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /opt/ros/kinetic
-- This workspace overlays: /opt/ros/kinetic
-- Found PythonInterp: /usr/bin/python (found version "2.7.12") 
-- Using PYTHON_EXECUTABLE: /usr/bin/python
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/tangshp/catkin_ws/build/test_results
-- Found gmock sources under '/usr/src/gmock': gmock will be built
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE  
-- Found gtest sources under '/usr/src/gmock': gtests will be built
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.14
-- BUILD_SHARED_LIBS is on
-- Configuring done
-- Generating done
-- Build files have been written to: /home/tangshp/catkin_ws/build
####
#### Running command: "make -j4 -l4" in "/home/tangshp/catkin_ws/build"

编译完成后,catkin_ws文件夹下会产生两个与src同级的文件夹;如下图
在这里插入图片描述build:放置编译过程产生的中间文件
devel:放置编译产生的可执行文件
在这里插入图片描述上图中的setup.zsh就是设置环境的脚本

3.设置环境变量

在后面操作过程中,让整个linux系统找到我们具体这个ROS功能报在什么位置

➜  catkin_ws source devel/setup.zsh #注意要在catkin_ws中运行终端;这里使用的是zsh终端,如果使用bash终端,则setup.zsh因改为setup.bash

注意:该命令只会在当前终端生效,重新打开别的终端,这个环境变量的设置就没有任何效果,所以最好把这条命令放在终端的配置文件中去;配置文件在home的根目录下

~ vi ~/.zshrc #vi编辑器打开根目录下的终端配置文件

会弹出重新弹出一个终端
在这里插入图片描述在这个终端中按照vi编辑器使用方法详解把setup.zsh添加进去,并保存好

source ~/catkin_ws/devel/setup.zsh

退出后原来带有(~ vi ~/.zshrc )的终端,执行如下命令,让配置在终端生效

~ source ~/.zshrc 

4.检查环境变量

~ echo $ROS_PACKAGE_PATH
/home/tangshp/catkin_ws/src:/opt/ros/kinetic/share
#冒号后面是安装时设置的环境变量
#冒号前面是刚才添加的环境变量5.1.1 **创建功能包的格式**

5.创建功能包

5.1 创建功能包

5.1.1 创建功能包的格式

caktin_creak_pkg<package_name>[depend1][depend2][depend3]
#[depend1][depend2][depend3]被依赖的功能包

5.1.2 创建功能包需要在src文件中的终端进行
5.1.3 具体操作

~ cd ~/catkin_ws/src#保证在src中进行
➜  src catkin_create_pkg learning_communication std_msgs rospy roscpp
#learning_communication:功能包的名字
#std_msgs(ROS在std_msgs中提供了已经被定义好的标准的数据结构)
#rospy(ROS提供好的python接口)
#roscpp(ROS提供好的C++接口)		C Plus Plus
Created file learning_communication/package.xml
Created file learning_communication/CMakeLists.txt
Created folder learning_communication/include/learning_communication
Created folder learning_communication/src
Successfully created files in /home/tangshp/catkin_ws/src/learning_communication. Please adjust the values in package.xml.

会生成相应的文件夹及文件,如下图
在这里插入图片描述src:用来放置功能包具体的代码
include:用来放置头文件
CMakeLists.txtpackage.xml是所有功能包都必须具备的两个文件
CMakeLists.txt 放置我们如何去编译这个功能包的一些编译选项,需要CMake这个接口去设置的
package.xml 如下:

<?xml version="1.0"?>		#声明版本号
<package format="2">
  <name>learning_communication</name>		#功能包的名字
  <version>0.0.0</version>
  <description>The learning_communication package</description>		#对功能包的描述

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  ......
  <!--   <doc_depend>doxygen</doc_depend> -->		#该功能包所要依赖的功能包
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_export_depend>roscpp</build_export_depend>
  <build_export_depend>rospy</build_export_depend>
  <build_export_depend>std_msgs</build_export_depend>
  <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

后期可以在package.xml 中加入新加的依赖包

功能包依赖关系:

查看一级依赖
➜  src rospack depends1 beginner_tutorials#rospack不论在和地址都可以使用
roscpp
rospy
std_msgs

这些依赖包是在运行

src catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

时,作为参数的依赖包,这些依赖包随后被保存在/home/tangshp/My_First_catkin_ws/src/beginner_tutorials/package.xml文件中;
使用以下命令来查看package.xml

/sbin roscd beginner_tutorials/
#roscd区别与cd在于:不论当前在什么位置,roscd+功能包名都可以跳转到该功能包路径下面去
➜  beginner_tutorials cat package.xml 

在这里插入图片描述

间接依赖(查看上述依赖包他们本身所依赖的依赖包)

如查看rospy的依赖包,rospy本身也是一个功能包

~ rospack depends1 rospy
genpy
roscpp
rosgraph
rosgraph_msgs
roslib
std_msgs

递归地检测所有依赖包

~ rospack depends beginner_tutorials 
cpp_common
rostime
roscpp_traits
roscpp_serialization
catkin
genmsg
genpy
message_runtime
gencpp
geneus
gennodejs
genlisp
message_generation
rosbuild
rosconsole
std_msgs
rosgraph_msgs
xmlrpcpp
roscpp
rosgraph
ros_environment
rospack
roslib
rospy

5.2 编译功能包

➜  src cd ..
➜  catkin_ws catkin_make
#➜  catkin_ws source ~/catkin_ws/devel/setup.zsh 该步骤不要需要了(因为之前已经把环境变量设置加入zsh终端的配置文件中了)

5.3注意

5.3.1.同一个工作空间下,不允许存在同名功能包

5.3.2.不同工作空间下,允许存在同名功能包

5.3.3.当不同工作空间下,有同名功能包时,ROS将使用Overlaying机制查找功能包(工作空间的覆盖)

➜  catkin_ws env |grep ros	#env查询系统所有环境变量,grep过滤出与ros相关的环境变量
PATH=/opt/ros/kinetic/bin:/home/tangshp/bin:/home/tangshp/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
CMAKE_PREFIX_PATH=/home/tangshp/catkin_ws/devel:/opt/ros/kinetic
LD_LIBRARY_PATH=/home/tangshp/catkin_ws/devel/lib:/opt/ros/kinetic/lib:/opt/ros/kinetic/lib/x86_64-linux-gnu
PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/ros/kinetic/lib/x86_64-linux-gnu/pkgconfig
PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages
ROS_ETC_DIR=/opt/ros/kinetic/etc/ros
ROS_PACKAGE_PATH=/home/tangshp/catkin_ws/src:/opt/ros/kinetic/share #功能包的环境变量;
ROS_ROOT=/opt/ros/kinetic/share/ros

查找某个功能包的路径

~ rospack find roscpp_tutorials 
/opt/ros/kinetic/share/roscpp_tutorials

后被添加的环境变量,却先被系统查找到;即新的路径放在就路径前,也就是所谓的覆盖

对ROS功能包搜索路径的验证
1.在ROS wiki找到软件包下载链接(软件>软件包>Source的git链接)
在这里插入图片描述
2.点击
在这里插入图片描述
下载解压后
把其中的roscpp_tutorials复制一份到~/catkin_ws/src/下(其实该文件夹在安装ros-kinetic-desktop-full时就有了,存在与/opt/ros/kinetic/share/roscpp_tutorials下)
3.使用rospack find命令查找roscpp_tutorials功能包的路径

~ rospack find roscpp_tutorials 
/home/tangshp/catkin_ws/src/roscpp_tutorials

分析:由于/home/tangshp/catkin_ws/src/是后来被添加到zsh配置文件中,所以被下找到;而/opt/ros/kinetic/share/roscpp_tutorials是先被添加到配置文件中,所以不会被找到。

5.3.4.如果不存在,就顺序查找后面其它路径是否存在该功能包

5.3.5.由于roscpp_tutorials既存在于ros系统文件下,又存在于工作空间中;如果第三个功能包依赖系统文件下的roscpp_tutorials,而工作空间中的roscpp_tutorials又被修改了,工作空间中的配置路径又在系统配置路径之前,那么这个第三个功能包在使用时,就会报错;

/opt/ros/kinetic/share/roscpp_tutorials
/home/tangshp/catkin_ws/src/roscpp_tutorials

ROS通信编程

1.话题编程

话题编程流程

如何实现一个发布者

1.在/home/tangshp/catkin_ws/src/learning_communication/src路径下新建空白文档,名字为talker.cpp
2.向ROS Master注册节点信息(包括话题名,话题中的消息类型)
3.按照一定的频率循环发布消息;
编写如下:

/**
 * 该例程将发布chatter话题,消息类型String
 */
 
#include <sstream>
// C++字符串处理等的头文件
#include "ros/ros.h"
//包括订阅者/发布者 日志的输出 等ros一些常用的api
#include "std_msgs/String.h"
//ros提供一些常用的变量形式

int main(int argc, char **argv)
{
  //该api: ROS节点初始化
  ros::init(argc, argv, "talker");
//定义节点运行起来的名称是talker
  
  // 创建节点句柄
  ros::NodeHandle n;
//通过句柄n来管理的
  
  // 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
// 1000 表示队列数,队列满了以后,会把队列1000中时间戳最早的溢出
  // 设置循环的频率
  ros::Rate loop_rate(10);
//10的单位是Hz;是下面的循环周期,10 1/s. 100ms循环一次
  int count = 0;
  while (ros::ok())
  {
	// 初始化std_msgs::String类型的消息
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

	// 发布消息
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);

	// 循环等待回调函数
    ros::spinOnce();
	
	// 按照循环频率延时
    loop_rate.sleep();//没循环一次休眠100ms
    ++count;
  }

  return 0;
}

如何实现一个订阅者

1.初始化ROS节点
2.订阅需要的话题
3.循环等待话题消息,接收到消息后进入回调函数
4.在回调函数中完成消息处理
新建listener.cpp
在该文件中编写如下:

/**
 * 该例程将订阅chatter话题,消息类型String
 */
 
#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节点
  ros::init(argc, argv, "listener");

  // 创建节点句柄
  ros::NodeHandle n;

  // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  // 循环等待回调函数
  ros::spin();

  return 0;
}

如何编译代码

步骤框架:

1.设置需要编译的代码和生成的可执行文件
2.设置链接库
3.设置依赖

具体操作:

1.额外说明:
在这里插入图片描述该文件夹下的CMakeList.txt配置一些具体的编译选项的;里面许多指令被注释掉了,只要取消注释相应的行就行!这里直接在相应行添加
打开CMakeLIst.txt添加如下:

add_executable(talker src/talker.cpp)
#把src下的talker.cpp生成可执行文件talker
target_link_libraries(talker ${catkin_LIBRARIES})
#把可执行文件和所依赖的其他库做一个链接
#add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)
#添加功能报依赖

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
#add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)

如下图
在这里插入图片描述2.保存关闭后,在catkin_ws下编译

➜  catkin_ws catkin_make
➜  catkin_ws catkin_make
Base path: /home/tangshp/catkin_ws
Source space: /home/tangshp/catkin_ws/src
Build space: /home/tangshp/catkin_ws/build
Devel space: /home/tangshp/catkin_ws/devel
Install space: /home/tangshp/catkin_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/tangshp/catkin_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/tangshp/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /home/tangshp/catkin_ws/devel;/opt/ros/kinetic
-- This workspace overlays: /home/tangshp/catkin_ws/devel;/opt/ros/kinetic
-- Using PYTHON_EXECUTABLE: /usr/bin/python
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/tangshp/catkin_ws/build/test_results
-- Found gmock sources under '/usr/src/gmock': gmock will be built
-- Found gtest sources under '/usr/src/gmock': gtests will be built
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.14
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 1 packages in topological order:
-- ~~  - learning_communication
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'learning_communication'
-- ==> add_subdirectory(learning_communication)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/tangshp/catkin_ws/build
####
#### Running command: "make -j6 -l6" in "/home/tangshp/catkin_ws/build"
####
[ 50%] Linking CXX executable /home/tangshp/catkin_ws/devel/lib/learning_communication/listener
[ 50%] Linking CXX executable /home/tangshp/catkin_ws/devel/lib/learning_communication/talker
[ 75%] Built target talker
[100%] Built target listener

编译完成后,会在/home/tangshp/catkin_ws/devel/lib/learning_communication中生成连个可执行文件如下图:
在这里插入图片描述

如何运行可执行文件

1.运行大网管(在第一个终端里输入)

~ roscore

2.运行节点talker(在第二个终端里输入)

~ rosrun learning_communication talker

3.运行节点listener(在第三个终端里输入)

~ rosrun learning_communication listener

在这里插入图片描述talker以10Hz的频率发送hello world
listener同步接受其所定义的
4.运行rqt_graph节点显示计算图

~ rqt_graph

在这里插入图片描述

×如何自定义话题消息

在这里插入图片描述
1.定义msg文件

具体操作:

1.在/home/tangshp/catkin_ws/src/learning_communication中新建名为msg的文件夹
在这里插入图片描述2.在/home/tangshp/catkin_ws/src/learning_communication/msg中新建名为Person.msg的空白文档
在这里插入图片描述
添加如下语句

string name
uint8  sex
uint8  age

uint8 unknown = 0
uint8 male    = 1
uint8 female  = 2

2.在package.xml中添加功能包依赖
在/home/tangshp/catkin_ws/src/learning_communication里的package.xml添加以下

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

在这里插入图片描述
3.在CMakeList.txt添加编译选项
在/home/tangshp/catkin_ws/src/learning_communication中CMakeList.txt中添加以下

find_package( ...... message_generation)
#编译过程会通过自定义的Person.msg生成可执行代码,这个过程需要依赖message_generation来完成代码的生成工作

如图
在这里插入图片描述

catkin_package(CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs message_runtime)
#编译时要的依赖

如图
在这里插入图片描述

add_message_files(FILES Person.msg)
#添加要使用的msg文件名
generate_messages(DEPENDENCIES std_msgs)

在这里插入图片描述4.保存关闭package.xml与CMakeList.txt后,在根目录下编译

➜  catkin_ws catkin_make
Base path: /home/tangshp/catkin_ws
......
[ 27%] Generating Lisp code from learning_communication/Person.msg
[ 36%] Generating Javascript code from learning_communication/Person.msg
[ 45%] Generating Python from MSG learning_communication/Person
[ 54%] Generating EusLisp code from learning_communication/Person.msg
[ 54%] Built target learning_communication_generate_messages_lisp
[ 54%] Built target learning_communication_generate_messages_nodejs
[ 63%] Generating EusLisp manifest code for learning_communication
Scanning dependencies of target learning_communication_generate_messages_cpp
[ 72%] Generating C++ code from learning_communication/Person.msg
[ 81%] Generating Python msg __init__.py for learning_communication
[ 81%] Built target learning_communication_generate_messages_py
[ 81%] Built target learning_communication_generate_messages_cpp
[ 81%] Built target learning_communication_generate_messages_eus
Scanning dependencies of target learning_communication_generate_messages
[ 81%] Built target learning_communication_generate_messages
[ 90%] Linking CXX executable /home/tangshp/catkin_ws/devel/lib/learning_communication/talker
[ 90%] Built target talker
[100%] Linking CXX executable /home/tangshp/catkin_ws/devel/lib/learning_communication/listener
[100%] Built target listener

4.查看自定义的消息(查看该Person.msg结构定义是否成功)

~ cd catkin_ws 
➜  catkin_ws rosmsg show Person                 
[learning_communication/Person]:#告知该msg结构属于哪个功能包
uint8 unknown=0
uint8 male=1
uint8 female=2
string name
uint8 sex
uint8 age

说明定义成功,以后可以通过头文件包含的方式来使用

2.服务编程

在这里插入图片描述
问题描述:Listener发布两个加数给Talker;Talker把两个加数相加后,把求和结果告诉Listener

如何自定义服务请求与应答

1.定义srv文件(服务数据文件,该服务请求应答数据ROS中并没有)
在/home/tangshp/catkin_ws/src/learning_communication中新建srv文件夹
在这里插入图片描述在/home/tangshp/catkin_ws/src/learning_communication/srv中新建 AddTwoInts.srv文件,并输入以下语句

#服务请求数据
int64 a
int64 b
---#三个横杆把两类数据分割开来
#服务应答数据
int64 sum

在这里插入图片描述
2.在package.xml中添加功能依赖包
3.在CMakeList.txt添加编译选项
2 3 操作同话题编程中的相应操作一样,已经有这样的操作,不在进行该操作
3 中不同之处在于:

add_message_files(FILES Person.msg)
#添加要使用的msg文件名
generate_messages(DEPENDENCIES std_msgs)

换成

add_service_files(FILES AddTwoInts.srv)

在这里插入图片描述
下面是错误的操作
在这里插入图片描述4.通过编译来检查生成srv文件是否出错

➜  catkin_ws catkin_make 

如何创建服务器

在/home/tangshp/catkin_ws/src/learning_communication/src新建名为server.cpp
并输入以下指令

/**
 * AddTwoInts Server
 */
 
#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"

// service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwoInts::Request  &req,
         learning_communication::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节点初始化
  ros::init(argc, argv, "add_two_ints_server");
  
  // 创建节点句柄
  ros::NodeHandle n;

  // 创建一个名为add_two_ints的server,注册回调函数add()
  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  
  // 循环等待回调函数
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}

以上指令包括一下部分:
1.初始化ROS节点
2.创建Server实例
3.循环等待服务请求,进入回调函数
4.在回调函数中完成服务功能的处理,并返回应答数据

创建客户端

在/home/tangshp/catkin_ws/src/learning_communication/src新建名为client.cpp
并输入以下指令

/**
 * AddTwoInts Client
 */
 
#include <cstdlib>
#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"

int main(int argc, char **argv)
{
  // ROS节点初始化
  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;
  
  // 创建一个client,请求add_two_int service,service消息类型是learning_communication::AddTwoInts
  ros::ServiceClient client = n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
  
  // 创建learning_communication::AddTwoInts类型的service消息
  learning_communication::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  
  // 发布service请求,等待加法运算的应答结果
  if (client.call(srv))
  #call命令是阻塞命令,如果server没有应答,则客户端会一直卡在这个位置,这就会无法进行client的工作;
  #ros提供了多线程的方式来解决该问题
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

以上程序包含以下部分
1.初始化ROS节点
2.创建一个Client实例
3.发布服务请求数据
4.等待Server处理后的应答结果

如何代码编译

在/home/tangshp/catkin_ws/src/learning_communication中的CMakeLists.txt中进行以下操作
1.设置需要编译的代码和生成的可执行文件
2.设置链接库
3.设置依赖

add_executable(server src/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server ${PROJECT_NAME}_gencpp)
#生成自定义具体的请求应答数据,现在用到add_dependencies来把依赖添加到server中去

add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)

在这里插入图片描述
编译:

➜  catkin_ws catkin_make

编译完后会在/home/tangshp/catkin_ws/devel/lib/learning_communication新增server和client两个可执行文件
在这里插入图片描述

下面运行这两个可执行文件
1.运行大网管(在第一个终端里输入)

~ roscore

2.运行节点server(在第二个终端里输入)

~ rosrun learning_communication server

3.运行节点client(在第三个终端里输入)

~ rosrun learning_communication client 7 8
#在客户端需要带常数输入

在这里插入图片描述

3.动作编程

动作编程产生的需要:机器人前往指定点途中,需要反馈当前位置消息及错误消息,或者运动中要停在机器人当前任务;这种要求无法通过话题或者服务来完成;
在这里插入图片描述动作:
1.一种问答通信机制
2.带有连续反馈
3.可以在任务过程中止运行
4.基于ROS的消息机制实现
Action接口
goal:发布任务目标
cancel:请求取消任务
status:同在客户端当前状态
feedback:周期反馈任务运行的监控数据
result:向客户端发送任务执行结果,只发布一次
以下以机器人洗盘子为例,机器人周期反馈当前洗了多少盘子,最终返回总共洗了多少盘子

自定义动作消息

1.定义action文件:
在/home/tangshp/catkin_ws/src/learning_communication创建action文件夹
在这里插入图片描述在/home/tangshp/catkin_ws/src/learning_communication/action/创建名为DoDishes.action
输入以下语句

# Define the goal
uint32 dishwasher_id  # Specify which dishwasher we want to use
---
# Define the result
uint32 total_dishes_cleaned
---
# Define a feedback message
float32 percent_complete

以上包括三部分内容(任务/要求返回的结果/工作进度)
2.在package.xml中添加功能包依赖

<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>

3.在CMakeList.txt添加编译选项

find_package(catkin REQUIRED actionlib_msgs actionlib)
add_action_files(DIRECTORY action FILES DoDishes.action)
generate_messages(DEPENDENCIES actionlib_msgs)

在这里插入图片描述如上图:actionlib_msgsstd_msgs冲突,把generate_messages放一块
3.通过编译查看action定义是否正确

~ cd catkin_ws 
➜  catkin_ws catkin_make

如何实现一个动作服务器

1. 在/home/tangshp/catkin_ws/src/learning_communication/src
新建DoDishes_server.cpp文件
2.输入以下命令

#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include "learning_communication/DoDishesAction.h"

typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server;

// 收到action的goal后调用该回调函数
void execute(const learning_communication::DoDishesGoalConstPtr& goal, Server* as)
{
    ros::Rate r(1);
    learning_communication::DoDishesFeedback feedback;

    ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);

    // 假设洗盘子的进度,并且按照1hz的频率发布进度feedback
    for(int i=1; i<=10; i++)
    {
        feedback.percent_complete = i * 10;
        as->publishFeedback(feedback);
        r.sleep();
    }

    // 当action完成后,向客户端返回结果
    ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id);
    as->setSucceeded();
}

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

    // 定义一个服务器
    Server server(n, "do_dishes", boost::bind(&execute, _1, &server), false);
    
    // 服务器开始运行
    server.start();

    ros::spin();

    return 0;
}

以上命令包括:
1.初始化ROS节点
2.创建动作服务器实例
3.启动服务器
4.在回调函数中完成动作服务功能的处理,并反馈进度消息
5.动作完成,方式哦嗯结束消息

如何实现一个动作客户端

1. 在/home/tangshp/catkin_ws/src/learning_communication/src
新建DoDishes_client.cpp文件
2.输入以下命令

#include <actionlib/client/simple_action_client.h>
#include "learning_communication/DoDishesAction.h"

typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client;

// 当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,
        const learning_communication::DoDishesResultConstPtr& result)
{
    ROS_INFO("Yay! The dishes are now clean");
    ros::shutdown();
}

// 当action激活后会调用该回调函数一次
void activeCb()
{
    ROS_INFO("Goal just went active");
}

// 收到feedback后调用该回调函数
void feedbackCb(const learning_communication::DoDishesFeedbackConstPtr& feedback)
{
    ROS_INFO(" percent_complete : %f ", feedback->percent_complete);
}

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

    // 定义一个客户端
    Client client("do_dishes", true);

    // 等待服务器端
    ROS_INFO("Waiting for action server to start.");
    client.waitForServer();
    ROS_INFO("Action server started, sending goal.");

    // 创建一个action的goal
    learning_communication::DoDishesGoal goal;
    goal.dishwasher_id = 1;

    // 发送action的goal给服务器端,并且设置回调函数
    client.sendGoal(goal,  &doneCb, &activeCb, &feedbackCb);

    ros::spin();

    return 0;
}

以上命令包括:
1.初始化ROS节点
2.创建动作客户端实例
3.连接动作服务端
4.发送动作目标
5.根据不同类型的服务端反馈处理回调函数

编译代码

在/home/tangshp/catkin_ws/src/learning_communication中的CMakeLists.txt中进行以下操作
1.设置需要编译的代码和生成的可执行文件
2.设置链接库
3.设置依赖

add_executable(DoDishes_client src/DoDishes_client.cpp)
target_link_libraries( DoDishes_client ${catkin_LIBRARIES})
add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})

add_executable(DoDishes_server src/DoDishes_server.cpp)
target_link_libraries( DoDishes_server ${catkin_LIBRARIES})
add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})

保存CMakeLists.txt并退出,进行编译:


下面运行这两个可执行文件
1.运行大网管(在第一个终端里输入)

~ roscore

2.运行节点DoDishes_client (在第二个终端里输入)

~ rosrun learning_communication DoDishes_client 
[ INFO] [1543552615.083894929, 153.620000000]: Waiting for action server to start.
[ INFO] [1543552665.151692995, 203.470000000]: Action server started, sending goal.
[ INFO] [1543552665.154209459, 203.472000000]: Goal just went active
[ INFO] [1543552665.154395338, 203.472000000]:  percent_complete : 10.000000 
[ INFO] [1543552666.157392992, 204.473000000]:  percent_complete : 20.000000 
[ INFO] [1543552667.159992473, 205.472000000]:  percent_complete : 30.000000 
[ INFO] [1543552668.165071629, 206.472000000]:  percent_complete : 40.000000 
[ INFO] [1543552669.168673046, 207.472000000]:  percent_complete : 50.000000 
[ INFO] [1543552670.171596978, 208.472000000]:  percent_complete : 60.000000 
[ INFO] [1543552671.176224878, 209.472000000]:  percent_complete : 70.000000 
[ INFO] [1543552672.182485578, 210.472000000]:  percent_complete : 80.000000 
[ INFO] [1543552673.184650140, 211.472000000]:  percent_complete : 90.000000 
[ INFO] [1543552674.189306742, 212.473000000]:  percent_complete : 100.000000 
[ INFO] [1543552675.192370145, 213.472000000]: Yay! The dishes are now clean

3.运行节点DoDishes_server (在第三个终端里输入)

~ rosrun learning_communication DoDishes_server 
[ INFO] [1543552665.153974131, 203.472000000]: Dishwasher 1 is working.
[ INFO] [1543552675.191849177, 213.472000000]: Dishwasher 1 finish working.

分布式通信

ROS是一种分布式框架,它的所有节点可以运行在不同主机上的,这样就可以把计算分布在不同主机上,分担每台主机计算的压力;(ROS是一种分布式软件框架,节点之间通过松耦合的方式进行组合)

如何实现分布式多机通信

(1)设置IP地址,确保底层链路的联通

ROS关键组件

Launch文件

Launch文件:通过XML文件实现多节点的配置和启动(可自动启动ROS Master

例如

<launch>
	<node pkg="turtlesim" name="sim1" type=“turtlesim_node”/>
	<node pkg="turtlesim" name="sim2" type=“turtlesim_node”/>
<launch>

launch文件中的根元素采用标签定义
启动节点

pkg:节点所在功能包名称
type:节点的可执行文件
name:节点运行的名称
output:通过output判断是否把节点内部的信息打印打屏幕或者是否把这些信息生成日志
respawn:如果当前节点失效或者失败后,会重新启动
required:表明该节点是必须节点,如果该节点未启动成功,这个launch文件是无法启动的
ns:(namespace)命名空间的属性
args:该节点具体需要哪些参数(如两个加数参数)
参数设置:

<param>/<rosparam>(<rosparam><param>一样):设置ROS系统运行中的参数,存储在参数服务器中,是全局变量;
<param name=“output_frame”  value=“odom"/>
name:参数名
value:参数值
<rosparam file="params.yaml"  command="load"  ns="params"/>

<arg>:launch文件内部的局部变量,仅限于launch文件使用
<arg name=“arg_name” default=“arg-value”/>
name:参数名
value:参数名

掉用<arg>
<param name="foo" value="$(arg arg-name)"/>

<node name="node" pkg="package" type=type” args="$(arg arg-name)"/>

TF坐标变换

TF功能包能做什么
1.保存5s内机器人头部坐标系相对于全局坐标系的关系
2.机器人夹取的物体相对于机器人中心坐标系的位置
3.机器人中心坐标系相对于全局坐标系的位置
TF坐标变换如何实现:所有TF变换的数据都是以树形结构进行保存的
1.广播TF变换(以广播的形式把已知的变换数据插入到该树当中)
2.监听TF变换(监听这棵树的数据,获得需要获得的两个坐标变换的数据)

~ sudo apt-get install ros-kinetic-turtle-tf#安装小海龟坐标变换的功能包~ roslaunch turtle_tf turtle_tf_demo.launch 

会出现两只海龟,一只跟着一只走
在这里插入图片描述
重新打开一个终端

~ rosrun turtlesim turtle_teleop_key 
#启动键盘控制节点

重新打开一个终端

~ rosrun tf view_frames
#监听5s坐标变换
Listening to /tf for 5.000000 seconds
Done Listening
dot - graphviz version 2.38.0 (20140413.2041)

Detected dot version 2.38
frames.pdf generated#监听记录会被保存到当前运行的根目录下

在这里插入图片描述
会显示当前系统所有坐标系(世界坐标系/turtle1(小海龟1)坐标系/turtle2(小海龟2)坐标系)
重新打开一个终端

~ rosrun tf tf_echo turtle1 turtle2#查看坐标如何变化的
At time 1543586791.547
- Translation: [0.000, 0.000, 0.000]#位移上重合,故xyz都为0
- Rotation: in Quaternion [0.000, 0.000, -0.328, 0.945]#四元数表示
            in RPY (radian) [0.000, 0.000, -0.668]#弧度表示
            in RPY (degree) [0.000, 0.000, -38.292]#角度表示

四元数-小知识
重新打开一个终端

~ rosrun rviz rviz -d 'rospack find turtle_tf' /rviz/turtle_rviz.rviz

QT工具箱

日志输出输出工具 rqt-console

~ roslaunch turtle_tf turtle_tf_demo.launch   
➜  ~ rqt_console

在这里插入图片描述

rqt_graph 查看节点计算图

rqt_plot 绘图工具

rqt_reconfigure 参数配置工具(需要rosrun)

rviz可视化平台

gazebo模型

小知识

1.如何在某个文件夹下打开终端

直接在指定文件夹下右键>在终端打开(T)

2.截图软件gnome-screenshot的使用

sudo apt-get install gnome-screenshot

3.什么是vi编辑器

vi编辑器使用方法详解
1.三种模式的转换
2.保存与退出
3.如何删除错误行

4.安装ros-kinect-roscpp-tutorials功能包(关于ros的一些例程)

➜  catkin_ws sudo apt-get install ros-kinetic-roscpp-tutorials 

remapping

~ rosrun beginner_tutorials listener.py chatter:=/wg/chatter

命名空间和重映射

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值