参考资料

  • 古月居ROS21讲
  • ROSwiki

ROS命令行概述

  • roscore启动命令

  • rosrun

    rosrun [package_name] [node_name] #允许你使用包名直接运行一个包内的节点(而不需要知道这个包的路径)。
  • rosls

    rosls是rosbash命令集中的一部分,它允许你直接按软件包的名称而不是绝对路径执行ls命令(罗列目录).

    rosls beginner_tutorials/
    CMakeLists.txt include package.xml src
  • roscd log

    使用roscd log可以切换到ROS保存日记文件的目录下。需要注意的是,如果你没有执行过任何ROS程序,系统会报错说该目录不存在。

  • rosed

    rosed 是 rosbash 的一部分。利用它可以直接通过package名来获取到待编辑的文件而无需指定该文件的存储路径了。

    rosed [package_name] [filename]

    这个实例展示了如何编辑roscpp package里的Logger.msg文件。

  • rospack命令

    rospack允许你获取软件包的有关信息

    rospack find roscpp
    /opt/ros/kinetic/share/roscpp

    $ rospack list                #显示出当前的包信息

    $ rospack depends1 beginner_tutorials    #显示当前包的一级依赖

    $ rospack depends beginner_tutorials     #显示当前包的所有依赖
  • rqt

    rqt_graph   #显示计算图
  • rosnode

    rosnode ping  节点名 #测试节点的联通情况
    rosnode list #显示全部节点
    rosnode info 节点名 #显示节点信息
    rosnode machine #显示当前机器
    rosnode kill 节点名 #结束一个正在运行的node
    rosnode cleanup #清除无法访问的节点的注册信息
  • rostopic

    rostopic bw	    #显示主题使用的带宽
    rostopic delay #从标题中的时间戳显示主题的延迟
    rostopic echo #将消息打印到屏幕,可以显 示在某个话题上发布的数据.
    rostopic find #按类型查找主题
    rostopic hz #显示主题的发布率
    rostopic info #打印有关活动主题的信息
    rostopic list #列出活动主题
    -h, --help #(显示此帮助消息并退出)
    -b BAGFILE, --bag=BAGFILE #(列出.bag文件中的主题)
    -v, --verbose #(列出每个主题的完整详细信息)
    -p #(仅列出发布商)
    -s #(仅列出订阅者)
    --host #(按主机名分组)
    rostopic pub #将数据发布到主题
    rostopic type #打印主题或字段类型,命令用来查看所发布话题的消息类型。
  • rostopic pub

    $ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
    #发送一条消息给turtlesim,告诉它以2.0大小的线速度和1.8大小的角速度开始移动。
    #这条命令以1Hz的频率发布速度命令到速度话题上。

    $ rostopic pub -r 10 /turtle1/cmd_vel geometry_msgs/Twist"linear:
    x:1.0
    y:0.0
    z:0.0
    angular:
    x:0.0
    y:0.0
    z:0.0"

    #/turtle1/cmd_vel话题名
    #geometry_msgs/Twist消息结构
    #-r 表示循环
  • rostopic hz

    $ rostopic hz /turtle1/pose
    subscribed to [/turtle1/pose]
    average rate: 62.486
    min: 0.015s max: 0.017s std dev: 0.00047s window: 60
    average rate: 62.476
    min: 0.015s max: 0.018s std dev: 0.00045s window: 122
    average rate: 62.514
    min: 0.014s max: 0.020s std dev: 0.00057s window: 185
    average rate: 62.506
    min: 0.013s max: 0.020s std dev: 0.00061s window: 248
  • rosmsg

    $rosmsg show geometry_msgs/Twist
    geometry_msgs/Vector3 linear
    float64 x
    float64 y
    float64 z
    geometry_msgs/Vector3 angular
    float64 x
    float64 y
    float64 z
  • rosbag

    将ROS系统运行过程中的数据录制到一个.bag文件中,然后可以通过回放数据来重现相似的运行过程.退出录制时按Ctrl-C退出该命令,你应该会看到在当前目录下一个以年份、日期和时间命名并以.bag作为后缀的文件。

    #录制所有发布的话题,其中 -a 选项,该选项表示将当前发布的所有话题数据都录制保存到一个bag文件中。
    $ rosbag record -a
    #回放bag文件以再现系统运行过程
    $ rosbag play <your bagfile>
    #以某一频率发布消息(控制bag包播放的频率) : rosbag play -r 2
    #从某一时间节点开始播放发布消息 : rosbag play -s 2
    $ rosbag info <your bagfile> #rosbag info 查看bag文件信息
    $ rosbag record -O 2018-12.bag /turtle1/command_velocity /turtle1/pose
    #rosbag record命令支持只录制某些特别指定的话题到单个bag文件中,这样就允许用户只录制他们感兴趣的话题
    $ rosbag record -a -O 2018-12.bag
    #可以使用rosbag info 2018-12.bag 命令查看录制时指定话题的信息.
    #也可以只指定bag包的文件名,录制所有数据
    $ rosbag record --split --duration=5m -e /radar/back_targets /vehicle_speed /imu_data
    #录取指定topic,并且每五分钟分割一次, -e为正则匹配。
    $ rosrun image_view image_view image:=/camera/front_middle compressed
    #如果查看视频,就可以实现视频播放功能

创建工作空间和功能包

工程文件 workspace

四个文件夹:

  • src代码空间
  • build编译空间
  • devel开发空间
  • install安装空间
#创建工作空间
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
#编译工作空间
$ cd ~/catkin_ws/
$ catkin_make
$ catkin_make install
#设置环境变量
$ source devel/setup.bash
#检查环境变量
$ echo $ROS_PACKAGE_PATH
home/qxd/catkin_ws/src:/opt/ros/melodic/share
#创建功能包
$ cd ~/catkin_ws/src
$ catkin_create_pkg test_pkg std_msgs rospy roscpp
eg: $ catkin_create_pkg 包名 依赖名 依赖名 依赖名 ...
#编译功能包
$ cd ~/catkin_ws
$ catkin_make
$ source ~/catkin_ws/devel/setup.bash

发布者publisher编程实现

#创建功能包
$ cd ~/catkin_ws/src
$ catkin_create_pkg learning_topic std_msgs rospy roscpp geometry_msgs turtlesim

image-20220127193532123

代码放到src目录

创建一个.cpp文件即可,注意文件名不能重复!!

/**
* 该程序将发布turtle1/cmd_vel话题,消息类型geometry——msgs::Twist
*/
#include<ros/ros.h>
#include<geometry_msgs/Twist.h>

int main(int argc,char **argv)
{
//ROS节点初始化
ros::init(argc,argv,"velocity_publisher");

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

//创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry——msgs::Twist,队列长度10
ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);

//设置循环频率
ros::Rate loop_rate(10);

int count = 0;
while(ros::ok())
{
//初始化geometry_msgs::Twist类型的消息
geometry_msgs::Twist vel_msg;
vel_msg.linear.x = 0.5;
vel_msg.angular.z = 0.2;

//发布消息
turtle_vel_pub.publish(vel_msg);
ROS_INFO("Publsh turtle velocity command[%0.2f m/s,%0.2f rad/s]",
vel_msg.linear.x,vel_msg.angular.z);

//按照循环频率延时
loop_rate.sleep();
}
return 0;
}

接下来需要编译运行,需要配置CMakeLists.txt中的编译规则

cmake_minimum_required(VERSION 3.0.2)
project(learning_topic)

## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
turtlesim
message_generation
)

## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)


## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()

################################################
## Declare ROS messages, services and actions ##
################################################

## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend tag for "message_generation"
## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
## but can be declared for certainty nonetheless:
## * add a exec_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)

## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )

## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )

## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )

## Generate added messages and services with any dependencies listed here
# generate_messages(
# DEPENDENCIES
# geometry_msgs# std_msgs
# )

add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)

################################################
## Declare ROS dynamic reconfigure parameters ##
################################################

## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
## * add "dynamic_reconfigure" to
## find_package(catkin REQUIRED COMPONENTS ...)
## * uncomment the "generate_dynamic_reconfigure_options" section below
## and list every .cfg file to be processed

## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
# cfg/DynReconf1.cfg
# cfg/DynReconf2.cfg
# )

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES learning_topic
# CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim
# DEPENDS system_lib
message_runtime
)


###########
## Build ##
###########

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)

## Declare a C++ library
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/learning_topic.cpp
# )

## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/learning_topic_node.cpp)

## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")

## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )

#将velocity_publisher.cpp编译成velocity_publisher可执行文件
add_executable(velocity_publisher src/velocity_publisher.cpp)

#对velocity_publisher做可执行文件的链接
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})

add_executable(pose_subscriber src/pose_subscriber.cpp)
target_link_libraries(pose_subscriber ${catkin_LIBRARIES})



#############
## Install ##
#############

# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# catkin_install_python(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark executables for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
# install(TARGETS ${PROJECT_NAME}_node
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )

## Mark libraries for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
# install(TARGETS ${PROJECT_NAME}
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
# )

## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
# FILES_MATCHING PATTERN "*.h"
# PATTERN ".svn" EXCLUDE
# )

## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
# # myfile1
# # myfile2
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )

#############
## Testing ##
#############

## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_learning_topic.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()

## Add folders to be run by python nosetests
# catkin_add_nosetests(test)

接下来就可以编译,在你的工作空间的src下

$ catkin_make

设置环境变量

source devel/setup.bash

也可以在主文件夹下

cd /
ls -a
vim .bashrc
#最后一行添加 source /home/qxd/catkin_ws/devel/setup.bash

接下来就可以执行

$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun learning_topic velocity_publisher

也可用python来完成,首行注意添加 #!/usr/bin/env python

#!/usr/bin/env python   
import rospy
from geometry_msgs.msg import Twist

def velocity_publisher():
#ROS
rospy.init_node('velocity_publisher',anonymous=True)

turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel',Twist,queue_size=10)

rate = rospy.Rate(10)
while not rospy.is_shutdown():
vel_msg = Twist()
vel_msg.linear.x = 0.5
vel_msg.angular.z = 0.2

turtle_vel_pub.publish(vel_msg)
rospy.loginfo("Publish turtle velocity command[%0.2f m/s,%0.2f rad/s]",
vel_msg.linear.x,vel_msg.angular.z)
rate.sleep()

if __name__ == '__main__':
try:
velocity_publisher()
except rospy.ROSInterruptException:
pass

订阅者subscriber的编程实现

项目工程文件夹下src中创建代码

//pose_subscriber.CPP
/**
* this program will subscribe /turtle/pose topic,message type is turtlesim::pose
*/

#include<ros/ros.h>
#include"turtlesim/Pose.h"

//recived the subscribe,then will go into the function that message recall
void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
ROS_INFO("Turtle pose: x:%0.6f,y:%0.6f",msg->x,msg->y);
}

int main(int argc,char **argv)
{
//初始化ROS节点
ros::init(argc,argv,"pose_subscriber");

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

//创建一个Subscriber,订阅名为/turtle1/pose的topic,注册回调函数poseCallback
ros::Subscriber pose_sub = n.subscribe("/turtle1/pose",10,poseCallback);

//循环等待回调函数
ros::spin();
return 0;
}
编译执行过程同发布者
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#该例程将订阅/turtle1/pose话题,消息类型turtlesim::Pose

import rospy
from turtlesim.msg import Pose

def poseCallback(msg):
rospy.loginfo("Turtle pose: x:%0.6f,y:%0.6f",msg.x,msg.y)
def pose_subscriber():
rospy.init_node('pose_subscriber',anonymous=True)

rospy.Subscriber("/turtle1/pose",Pose,poseCallback)

rospy.spin()
if __name__ == '__main__':
pose_subscriber()

话题消息定义与使用

如何自定义一个话题的消息

  • 定义msg文件

    在项目文件夹下创建一个msg文件夹,专门存放.msg文件,不能随便命名

    string name
    uint8 sex
    uint8 age

    uint8 unknown = 0
    uint8 male = 1
    uint8 female =2
  • 在package.xml中添加功能包依赖

    <build_depend>message_generation</build_depend>
    <exec_depend>message_runtime</exec_depend>
  • 在CMakeList.txt添加编译选项

    ## Find catkin macros and libraries
    ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
    ## is used, also find other catkin packages
    find_package(catkin REQUIRED COMPONENTS
    geometry_msgs
    roscpp
    rospy
    std_msgs
    turtlesim
    message_generation #添加功能包
    )

    ## Generate added messages and services with any dependencies listed here
    # generate_messages(
    # DEPENDENCIES
    # geometry_msgs# std_msgs
    # )
    add_message_files(FILES Person.msg)
    generate_messages(DEPENDENCIES std_msgs)


    ###################################
    ## catkin specific configuration ##
    ###################################
    ## The catkin_package macro generates cmake config files for your package
    ## Declare things to be passed to dependent projects
    ## INCLUDE_DIRS: uncomment this if your package contains header files
    ## LIBRARIES: libraries you create in this project that dependent projects also need
    ## CATKIN_DEPENDS: catkin_packages dependent projects also need
    ## DEPENDS: system dependencies of this project that dependent projects also need
    catkin_package(
    # INCLUDE_DIRS include
    # LIBRARIES learning_topic
    CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime #添加此处
    # DEPENDS system_lib
    )

  • 最后直接编译catkin_make编译即可

客户端Client的编程实现

  • 创建一个新的功能包文件夹

    $ cd ~/catkin_ws/src
    $ catkin_create_pkg learnin_service roscpp rospy std_msgs geometry_msgs turtlesim
  • 在learnin_service的src下创建cpp代码

    /**
    *该程序将请求/spawn服务,服务数据类型turtlesim::Spawn
    */
    #include<ros/ros.h>
    #include<turtlesim/Spawn.h>

    int main(int argc,char **argv)
    {
    //初始化ROS节点
    ros::init(argc,argv,"turtle_spawn");

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

    //发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    ros::service::waitForService("/spawn"); //循环等待
    ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");

    //初始化turtlesim::Spawn的请求数据
    turtlesim::Spawn srv;
    srv.request.x = 2.0;
    srv.request.y = 2.0;
    srv.request.name = "turtle2";

    //请求服务调用
    ROS_INFO("Call service to spwan turtle[x:%0.6f,y:%0.6f,name:%s]",srv.request.x,srv.request.y,srv.request.name.c_str());

    add_turtle.call(srv);

    //显示服务调用结果
    ROS_INFO("Spwan turtle successfully [name:%s]",srv.response.name.c_str());

    return 0;
    }

    配置编译规则CMakeList.txt

    add_executable(turtle_spawn src/turtle_spawn.cpp) //设置需要编译的代码和生成的可执行文件;
    target_link_libraries(turtle_spawn ${catkin_LIBRARIES}) //设置链接库;

    回到根目录/catkin_ws编译并运行客户端

    编译成功后在devel/lib下产生功能包

服务端Server的编程实现

​ 在src下turtle_command_server.cpp

/**
* 该程序将执行/turtle_command服务,服务数据类型td_srvs/Trigger
*/
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <std_srvs/Trigger.h>

ros::Publisher turtle_vel_pub;
bool pubCommand = false;

// service回调函数,输入参数req,输出参数res
bool commandCallback(std_srvs::Trigger::Request &req,
std_srvs::Trigger::Response &res)
{
pubCommand = !pubCommand;

//显示请求数据
ROS_INFO("Publish turtle velocity command [%s]", pubCommand==true?"Yes":"No");

//设置反馈数据
res.success = true;
res.message = "Change turtle command state!"

return true;
}

int main(int argc, char **argv)
{
//ROS节点初始化
ros::init(argc, argv, "turtle_command_server");
//创建节点"把手"
ros::NodeHandle n;
//创建一个名为turtle_command的erver,注册回调函数ommandCallback
ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);
// 创建一个Publisher,发布名为turtle1/cmd_vel的topic消息类型为geometry_msgs::Twist,队列长度为10
turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
//循环等待回调函数
ROS_INFO("Ready to receive turtle command.");
//设置循环的频率
ros::Rate loop_rate(10);
while(ros::ok())
{
//查看一次回调函数队列
ros::spinOnce();
//如果标志为true,则发布速度指令
if(pubCommand)
{
geometry_msgs::Twist vel_msg;
vel_msg.linear.x = 0.5;
vel_msg.angular.z = 0.2;
turtle_vel_pub.publish(vel_msg);
}
//按照循环频率延时
loop_rate.sleep();
}
return 0;
}

配置CMakeLists

add_executable(turtle_command_server src/turtle_command_server.cpp)
target_link_libraries(turtle_command_server ${catkin_LIBRARIES})

编译运行服务器

$ cd ~/catkin_ws
$ catkin_make
$ source devel/setup.bash
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun learning_service turtle_command_server
$ rosservice call /turtle_command "{}"

自定义服务数据

  • 定义srv文件

    string name
    uint8 age
    uint8 sex
    uint8 unknown = 0
    uint8 male = 1
    uint8 female = 2
    --- //之上表示request,之下表示respons
    string result
  • 在package.xml中添加功能包依赖

    <build_depend>message_generation</build_depend>
    <exec_depend>message_runtime</exec_depend>
  • 在CMakeLists.txt提娜佳编译选项

    find_package( …… message_generation)
    add_service_files(FILES Person.srv)
    generate_messages(DEPENDENCIES std_msgs)
    catkin_package(…… message_runtime)
  • 编译生成语言相关文件

  • 服务端实现

    /**
    * 该例程将请求/show_person服务,服务数据类型learning_service::Person
    */

    #include <ros/ros.h>
    #include "learning_service/Person.h"

    // service回调函数,输入参数req,输出参数res
    bool personCallback(learning_service::Person::Request &req,
    learning_service::Person::Response &res)
    {
    // 显示请求数据
    ROS_INFO("Person: name:%s age:%d sex:%d", req.name.c_str(), req.age, req.sex);

    // 设置反馈数据
    res.result = "OK";

    return true;
    }

    int main(int argc, char **argv)
    {
    // ROS节点初始化
    ros::init(argc, argv, "person_server");

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

    // 创建一个名为show_person的erver,注册回调函数ersonCallback
    ros::ServiceServer person_service = n.advertiseService("/show_person", personCallback);

    // 循环等待回调函数
    ROS_INFO("Ready to show person informtion.");
    ros::spin();

    return 0;
    }


  • 客户端实现

    /**
    * 该例程将请求/show_person服务,服务数据类型learning_service::Person
    */

    #include <ros/ros.h>
    #include "learning_service/Person.h"

    int main(int argc, char** argv)
    {
    // 初始化ROS节点
    ros::init(argc, argv, "person_client");

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

    // 发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service
    ros::service::waitForService("/show_person");
    ros::ServiceClient person_client = node.serviceClient<learning_service::Person>("/show_person");

    // 初始化learning_service::Person的请求数据
    learning_service::Person srv;
    srv.request.name = "Tom";
    srv.request.age = 20;
    srv.request.sex = learning_service::Person::Request::male;

    // 请求服务调用
    ROS_INFO("Call service to show person[name:%s, age:%d, sex:%d]",
    srv.request.name.c_str(), srv.request.age, srv.request.sex);

    person_client.call(srv);

    // 显示服务调用结果
    ROS_INFO("Show person result : %s", srv.response.result.c_str());

    return 0;
    };

    配置编译规则

    add_executable(person_server src/person_server.cpp)
    target_link_libraries(person_server ${catkin_LIBRARIES})
    add_dependencies(person_server ${PROJECT_NAME}_gencpp)
    add_executable(person_client src/person_client.cpp)
    target_link_libraries(person_client ${catkin_LIBRARIES})
    add_dependencies(person_client ${PROJECT_NAME}_gencpp)
  • 运行

    $ cd ~/catkin_ws
    $ catkin_make
    $ source devel/setup.bash
    $ roscore
    $ rosrun learning_service person_server
    $ rosrun learning_service person_client

参数的使用与编程方法

  • 创建功能包

    $ cd ~/catkin_ws/src
    $ catkin_create_pkg learning_parameter roscpp rospy std_srvs
  • 参数命令行使用

    $ rosparam list #列出当前多有参数
    $ rosparam get param_key #显示某个参数值
    $ rosparam set param_key param_value #设置某个参数值
    $ rosparam dump file_name #保存参数到文件
    $ rosparam load file_name #从文件读取参数
    $ rosparam delete param_key #删除参数
  • 创建parameter_conflg.cpp

    /**
    * 该例程设置/读取海龟例程中的参数
    */
    #include <string>
    #include <ros/ros.h>
    #include <std_srvs/Empty.h>

    int main(int argc, char **argv)
    {
    int red, green, blue;

    // ROS节点初始化
    ros::init(argc, argv, "parameter_config");

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

    // 读取背景颜色参数
    ros::param::get("/background_r", red);
    ros::param::get("/background_g", green);
    ros::param::get("/background_b", blue);

    ROS_INFO("Get Backgroud Color[%d, %d, %d]", red, green, blue);

    // 设置背景颜色参数
    ros::param::set("/background_r", 255);
    ros::param::set("/background_g", 255);
    ros::param::set("/background_b", 255);

    ROS_INFO("Set Backgroud Color[255, 255, 255]");

    // 读取背景颜色参数
    ros::param::get("/background_r", red);
    ros::param::get("/background_g", green);
    ros::param::get("/background_b", blue);

    ROS_INFO("Re-get Backgroud Color[%d, %d, %d]", red, green, blue);

    // 调用服务,刷新背景颜色
    ros::service::waitForService("/clear");
    ros::ServiceClient clear_background = node.serviceClient<std_srvs::Empty>("/clear");
    std_srvs::Empty srv;
    clear_background.call(srv);

    sleep(1);

    return 0;
    }
  • 配置CMakeLists参数

    add_executable(parameter_config src/parameter_config.cpp)
    target_link_libraries(parameter_config ${catkin_LIBRARIES})
  • 编译运行

    $ cd ~/catkin_ws
    $ catkin_make
    $ source devel/setup.bash
    $ roscore
    $ rosrun turtlesim turtlesim_node
    $ rosrun learning_parameter parameter_config

ROS中的坐标系管理系统

  • 机器人中的坐标变换

    TF功能包

    $ sudo apt-get install ros-melodic-turtle-tf

    #roslaunch,启动脚本文件
    $ roslaunch turtle_tf turtle_tf_demo.launch
    $ rosrun turtlesim turtle_teleop_key

    #各种工具
    $ rosrun tf view_frames
    $ rosrun tf tf_echo turtle1 turtle2
    $ rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.rviz

TF坐标系广播监听的编程管理

  • 创建功能包

    $ cd ~/catkin_ws/src
    $ catkin_create_pkg learning_tf roscpp rospy tf turtlesim
  • 广播器broadcaster.cpp

    /**
    * 该例程产生tf数据,并计算、发布turtle2的速度指令
    */

    #include <ros/ros.h>
    #include <tf/transform_broadcaster.h>
    #include <turtlesim/Pose.h>

    std::string turtle_name;

    void poseCallback(const turtlesim::PoseConstPtr& msg)
    {
    // 创建tf的广播器
    static tf::TransformBroadcaster br;

    // 初始化tf数据
    tf::Transform transform;
    transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );
    tf::Quaternion q;
    q.setRPY(0, 0, msg->theta);
    transform.setRotation(q);

    // 广播world与海龟坐标系之间的tf数据
    br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
    }

    int main(int argc, char** argv)
    {
    // 初始化ROS节点
    ros::init(argc, argv, "my_tf_broadcaster");

    // 输入参数作为海龟的名字
    if (argc != 2)
    {
    ROS_ERROR("need turtle name as argument");
    return -1;
    }

    turtle_name = argv[1];

    // 订阅海龟的位姿话题
    ros::NodeHandle node;
    ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);

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

    return 0;
    };
  • 监听器

    /**
    * 该例程监听tf数据,并计算、发布turtle2的速度指令
    */

    #include <ros/ros.h>
    #include <tf/transform_listener.h>
    #include <geometry_msgs/Twist.h>
    #include <turtlesim/Spawn.h>

    int main(int argc, char** argv)
    {
    // 初始化ROS节点
    ros::init(argc, argv, "my_tf_listener");

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

    // 请求产生turtle2
    ros::service::waitForService("/spawn");
    ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
    turtlesim::Spawn srv;
    add_turtle.call(srv);

    // 创建发布turtle2速度控制指令的发布者
    ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel", 10);

    // 创建tf的监听器
    tf::TransformListener listener;

    ros::Rate rate(10.0);
    while (node.ok())
    {
    // 获取turtle1与turtle2坐标系之间的tf数据
    tf::StampedTransform transform;
    try
    {
    listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));
    listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);
    }
    catch (tf::TransformException &ex)
    {
    ROS_ERROR("%s",ex.what());
    ros::Duration(1.0).sleep();
    continue;
    }

    // 根据turtle1与turtle2坐标系之间的位置关系,发布turtle2的速度控制指令
    geometry_msgs::Twist vel_msg;
    vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
    transform.getOrigin().x());
    vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
    pow(transform.getOrigin().y(), 2));
    turtle_vel.publish(vel_msg);

    rate.sleep();
    }
    return 0;
    };

  • 编译配置

    add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)
    target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})

    add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
    target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})
  • 编译运行

    $ cd ~/catkin_ws
    $ catkin_make
    $ source devel/setup.bash
    $ roscore
    $ rosrun turtlesim turtlesim_node
    #重命名,避免冲突
    $ rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
    $ rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
    $ rosrun learning_tf turtle_tf_listener
    $ rosrun turtlesim turtle_teleop_key

launch启动文件的使用方法

roslaunch/XML - ROS Wiki

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

  • node启动节点 :

    pkg:节点所在的功能包名称

    type:节点的可执行文件名称

    name:节点运行时的名称

    output 、respawn 、required 、ns 、args

    <node pkg="package-name" type="executable-name" name="node-name" />
  • 参数设置

实例

常用可视化工具

  • rqt

    rqt
  • Rviz

    $ rosrun rviz
  • Gazebo