ROS基础学习(一)

参考古月居胡春旭ROS入门21讲视频等内容,跟着练习整理
ROS基本概念 ROS(Robot Operating System)是一个适用于机器人的开源的元操作系统。是一种新的标准化机器人软件框架,它提供了操作系统应有的服务,为机器人开发提供包括硬件抽象,底层驱动,消息传递,程序管理,应用原型等功能机制,并整合了许多第三方工具和库文件。ROS被设计为一种分布式结构,框架中每个功能模块都可以被单独设计、编译,并且运行时以松散耦合方式结合在一起,它也提供用于获取、编译、编写、和跨计算机运行代码所需的工具和库函数。
工作空间(workspace);是ROS存放工程开发相关文件的文件夹,工作空间中一般包括四个目录空间:src(代码空间):最常用的文件夹,用来储存所有ROS功能包的源码文件;build(编译空间):储存编译过程中的缓存信息和中间文件;devel(开发空间):放置编译生成的可执行文件;install(安装空间):编译成功后使用make install执行安装文件到该空间,运行该空间中的环境变量脚本,在终端运行这些可执行文件。
功能包(package):是ROS应用程序代码的组织单元,每个软件包都可以包含程序库、节点、可执行文件、脚本或者其它手动创建的东西。 创建了相应的软件包才能实现相应的功能。功能包中通常可包含如下文件夹:include(放置头文件)scripts(放置可直接运行的python文件)src(放置需要编译的C++文件)launch(放置启动文件)msg(放置自定义的消息类型)srv(放置自定义的服务类型)action(放置自定义的动作指令)CMakeLists.txt(编译器编译功能包的规则)package.xml(功能包清单:包括功能包名称,版本号,信息描述,作者信息,许可信息等,以及功能包中代码编译所依赖的其他功能包,运行功能包中可执行程序所依赖的其他功能包)
节点(Node):是 ROS 功能包中的一个可执行文件,一个系统通常由多个节点构成,节点之间可以通过 ROS 客户端库(如roscpp 、 rospy )相互通信。一个机器人控制系统由许多节点组成,这些节点各司其职,如,一个节点控制激光距离传感器,一个节点控制轮子的马达,一个节点执行定位,一个节点执行路径规划,一个节点提供系统的整个视图等。也就是能够执行特定工作任务的工作单元。
节点管理器(Master):顾名思义,使所有节点有条不紊执行的模块,节点通过与节点管理器通信来报告他们的注册信息,帮助节点之间相互查找,建立连接,同时还为系统提供参数服务器,管理全局参数,ROS master作为管理者,必不可少。
消息(Message):是一种ROS数据类型。节点之间做重要的通讯机制就是基于发布/订阅模型的消息(Message)通讯,一个节点向特定主题发布消息,从而将数据发送到另一个节点。消息具有一定的类型和数据结构,包括ROS提供的标准类型和用户自定义类型。消息与话题(发布 / 订阅模式)是紧密联系在一起的,msg文件实质上就是一个从结构上描述ROS中所使用消息类型的简单文本,描述的是消息的数据类型。
话题( Topic ): 是节点间用来传输数据的总线,通过主题进行消息路由不需要节点之间直接连接。节点可以发布消息到话题,也可以订阅话题以接收消息。一个话题可能对应有许多节点作为话题发布者和话题订阅者。当然,一个节点可以发布和订阅许多话题。一个节点对某一类型的数据感兴趣,它只需订阅相关话题即可。一般来说。话题发布者和话题订阅者不知道对方的存在。发布者将信息发布在一个全局的工作区内,当订阅者发现该信息是它所订阅的,就可以接收到这个信息。
服务: 当需要直接与节点通信并获得应答时,将无法通过话题来实现,而需要服务(Service)。可以看出,发布 / 订阅模式是一种多对多的传输方式,显然这种传输方式不适用于请求 / 回复的交互方式。请求 / 回复交互方式经常被用于分布式系统中。请求服务通过 Service 来进行,Service 被定义为一对消息结构:一个用于请求,一个用于回复。一个客户通过发送请求信息并等待响应来使用服务( ROS中的请求 / 回复交互方式类似于一个远程函数调用,srv文件类似于函数参数和返回值的定义)。
参数管理器( Parameter Server ): 是节点管理器的一部分,是一个可通过网络访问的共享的多变量字典。节点使用此服务器来存储和检索运行时参数。
消息记录包(Bag): 是一种用于保存和回放 ROS 消息数据的格式。消息记录包是检索传感器数据的重要机制,这些数据虽然很难收集,但是对于发展和测试算法很有必要。
清单(Manifest): 是对于功能包相关信息的描述,用于定义软件包相关元信息之间的依赖关系,这些信息包括版本、维护者和许可协议等。 也就是 package.xml文件。
脚本文件: CMakeLists.txt是一个Cmake的脚本文件,Cmake是一个符合工业标准的跨平台编译系统。这个文件包含了一系列的编译指令,包括应该生成哪种可执行文件,需要哪些源文件,以及在哪里可以找到所需的头文件和链接库。
ROS中有四种通讯方式:Topic(话题)、Service(服务)、Parameter Serivce(参数服务器)、Actionlib(动作库)。
常用指令:

roscore//开启rosmaster catkin_create_pkg//创建功能包 rospack//获取功能包信息 rospack find [包名称]//找到一个软件包的目录 rospack list//显示出当前的包信息 rospack depends1 beginner_tutorials//显示当前包的一级依赖 rospack depends beginner_tutorials//显示当前包的所有依赖 catkin_make//编译工作空间中功能包 rosdep//自动安装功能包依赖的其他包 roscd [ 本地包名称[/子目录] ] //允许你直接切换(cd)工作目录到某个软件包或者软件包集当中 roscp//拷贝功能包中文件 rosed//编辑功能包中文件 rosrun [package_name] [node_name]//运行功能包中可执行文件 roslaunch//运行启动文件 rosnode 显示当前运行的ROS节点信息 rosnode list获得运行节点列表 rosnode info node-name获得特定节点的信息 rosnode pingnode-name测试节点是否连通 rosnode kill node-name终止节点 rostopic//获取有关ROS话题的信息 rossrv//针对静态服务文件 rossrv show /srv_name显示服务类型的所有信息 rossrv list显示所有服务类型信息 rossrv md5/srv_name显示服务类型的md5sum信息 rossrv package列出一个程序包中的所有服务类型 rossrv packages >列出包含服务的所有程序包 rossevice rossevice args//打印服务的参数 rosservice call//以命令行的形式调用服务,可以指定具体参数 rosservice find//根据服务类型寻找当前服务 rosservice info//打印服务信息 rosservice list//列出当前服务类型 rosservice type//打印服务类型 rosservice uri//打印服务的ROSRPC uri rosmsg//查看消息的详细情况

ROS创建工作空间和包 工作空间:一个存放工程开发相关的文件夹
功能包package:是ROS软件的基本单元,包含ROS节点、库、配置文件等
Src:代码空间(source space)功能包代码,配置文件,launch文件
Build:编译空间(build space)
Devel:开发空间(development space)放置编译生成的可执行文件,一些库,脚本
Install:安装空间(install space)
创建工作空间
mkdir –p~/catkin_ws/src
cd~/catkin_ws/src
catkin_init_workspace
编译工作空间
cd ~/catkin_ws/
catkin_make
catkin _make install(创建安装空间)
创建功能包
catkin_create_pkg test_pkg roscpp rospy std_msgs
创建的功能包名为 test_pkg,依赖c++,python以及msgs等库,后期可添加,生成的test_pkg文件中包含src文件,用来存放代码,其中include用来存放头文件
设置环境变量
source devel/setup.bash
检查环境变量
echo $ROS_PACKAGE_PATH
通过运行小海龟了解ROS基本信息
roscore// 启动rosmaster运行节点管理器 rosrun turtlesim turtlesim_node//运行海龟仿真器节点指令 rosrun turtlesim turtle_teleop_key//启动键盘操作节点 rqt_graph/rqt//是基于qt的可视化工具,rqt_graph为显示系统计算处理工具Ros中默认单位为m和弧度 ## 常用指令:

rosnode 显示系统中所有节点相关信息的指令;
rostopic 显示系统中所有话题相关的指令;
rosmsg 与消息相关的指令;
rosservice 显示与服务相关指令
rosbag
rosnode list 列出系统中所有节点;
rosnode info 节点名称 查看节点具体信息;
rostopic list 列出系统中所有话题;
发布话题: rostopic pub /话题名/节点类型/数据结构“具体数据”可用tab键补齐 例子:rostopic pub –r 10 /turtle1/cmd_vel geometry_msgs/Twist "linear: x: 0.0 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 0.0" 其中-r 10 为频率,以10Hz每秒发送数据,具体数据包括:角速度和线速度。查看发布话题的消息结构:rosmsg show geometry_msgs/Twist eg:发布服务请求:rosservice call/spawn”x:5.0 Y:5.0 Theta:0.0 name:’turtle2’”话题记录:rosbag record –a-O cmd_record/record记录,-a所有信息-o保存为压缩包+名字 话题复现:rosbag play 压缩包名字# 话题通讯模型 ## 创建功能包 cd~/catkin_ws/src catkin_create_pkg learning_topic rospy std_msgs geometry_msgs turtlesim ## 发布者publisher编程实现 ### 创建发布者代码 ## 订阅者subscriber编程实现 初始化ROS节点 订阅需要的话题 循环等待话题消息,接收到消息后进入回调函数,在回调函数中完成消息处理 话题消息订阅使用 ## 自定义话题消息 ### 定义msg文件 创建msg文件夹,存放与消息有关的文件。使用touch person.msg命令创建文件,打开后编写msg文件 string name uint8 sex uint8 age uint8 unknow = 0 uint8 male = 1 uint8 female = 2 ### 在package.xml中添加功能包依赖 编译依赖message_generation动态产生msg的功能包 执行依赖message_runtime ### 在CMakeList.txt添加编译选项 1.添加功能包依赖find…package(…message_generation) 2.把msg文件编译成对应的程序文件add_message_files(FILES person.msg) 3.声明编译msg文件时需要依赖ros已有的库generate_messages(DEPENDENCIES std_msgs) 4创建msg运行依赖 catkin_package( INCLUDE_DIRS include LIBRARIES lenrnking_topic CATKIN_DEPENDS roscpp rospy std_msgs DEPENDS system_lib message_runtime ) 5编译catkin_make;根据msg文件生成include头文件,必须采用大写首字母命名 ### 编译生成语言相关文件 创建subscriber和publisher文件在CMakeList.txt中设置需要编译的代码和生成的可执行文件; add_executable(person_publisher src/person_publisher.cpp) add_executable(person_subscriber src/person_subscriber.cpp) 设置链接库; target_link_libraries(person_publisher ${catkin_LIBRARIES}) target_link_libraries(person_subscriber ${catkin_LIBRARIES}) 添加依赖项 add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp) add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)运行roscore; 运行rosrun learning_topic person_subscriber; 运行rosrun learning_topic person_publisher; 可观察到发布者发布信息,订阅者显示打印信息# 服务通信模型 服务(services)是节点之间通讯的另一种方式。服务允许节点发送请求(request) 并获得一个响应(response) ## 在工作空间src目录下创建learning_service功能包并添加依赖 catkin_create_pkg learning_service roscpp rospy std_msg geometry_msg turtlesim ## 客户端client编程实现 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200602173756793.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzM2NTc1MQ==,size_16,color_FFFFFF,t_70) 创建客户端turtle_spawn节点,发布request给server(海龟仿真器) 当server收到request后会回馈一个response给客户端,client端与server端通过service消息结构建立联系在创建的learning_service功能包的src中使用命令行创建文件 touch turtle_spawe.cpp 编写client端程序 ```cpp /** 请求/spawn服务,服务数据类型turtlesim::spawn**/ #include #include int main(int argc, char** argv) { //初始化节点 节点名为turtle_spawn ros::init(argc,argv,"turtle_spawn"); //创建节点句柄 ros::NodeHandle node; //发现/spawn服务后,创建一个ServiceClient实例服务客户端,连接名为/spawn的service,请求的数据类型为turtlesim::Spawn ros::service::waitForService("/spawn"); //查询当前系统中是否有/spawn服务,阻塞型api,循环等待 ros::ServiceClient add_turtle = node.serviceClient("/spawn"); //封装初始化turtlesim::Spawn的请求数据 turtlesim::Spawn srv; //定义名为srv,类型为turtlesim::Spawn的请求数据 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); //调用call方法,把封装好的srv发出去,等待服务器反馈。//显示服务调用结果 ROS_INFO("Spwan turtle successfully [name:%s]",srv.response.name.c_str()); return 0; }

配置CMakeList.txt编译规则
设置需要编译的代码和生成的可执行文件 【ROS基础学习(一)】打开learning_service功能包中的CMakeList.txt,在build中声明C++可执行文件并指定库链接另一个库或一个可执行目标:
add_executable(turtle_spawnsrc/turtle_spawn.cpp)//把spawn.cpp代码编译为turtle_spawn规则 target_link_libraries(turtle_spawn ${catkin_LIBRARIES})//把生成的turtle_spawn连接到ros中的库

返回到工作空间根目录进行编译
catkin_make
ROS基础学习(一)
文章图片

编译结束中,可在工作空间目录的devel文件夹中的lib文件夹可找到生成的learning_service功能包,包含代码编译生成的可执行文件turtle_spawn
编译并运行客户端
cd ~/ros_novice catkin_make roscore rosrun turtlesim tuetlesim_node rosrun learning_service turtle_spawn

ROS基础学习(一)
文章图片

Server服务器模型 ROS基础学习(一)
文章图片

在功能包src文件夹下打开命令行 touch turtle_command_server.cpp 创建代码文件
编写服务器端turtle_command_server代码
/** * 该例程将执行/turtle_command服务,服务数据类型std_srvs/Trigger */ #include #include #include 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的server,注册回调函数commandCallback ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback); // 创建一个Publisher,发布名为/turtle1/cmd_vel的topic,消息类型为geometry_msgs::Twist,队列长度10 turtle_vel_pub = n.advertise("/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; }

配置CMakeList.txt编译规则
设置需要编译的代码和生成的可执行文件 打开learning_service功能包中的CMakeList.txt,在build中声明C++可执行文件并指定库链接另一个库或一个可执行目标:
add_executable(turtle_command_server src/turtle_command_server.cpp)//把spawn.cpp代码编译为turtle_spawn规则 target_link_libraries(turtle_command_server ${catkin_LIBRARIES})//把生成的turtle_spawn连接到ros中的库

返回到工作空间根目录进行编译
catkin_make
ROS基础学习(一)
文章图片

编译并运行客户端
cd ~/ros_novice catkin_make roscore rosrun turtlesim tuetlesim_node rosrun learning_service turtle_command_server rosservice call/turtle_command

ROS基础学习(一)
文章图片

通过反复call service可以实现对海龟的开关命令
服务数据的定义使用 ROS基础学习(一)
文章图片

Client端request发布显示人信息的请求,把信息通过service端发布数据,server端收到service发布的数据
自定义show_person服务数据结构
1、在功能包下创建srv文件夹,touch show_person.srv
定义.src文件;//—以上为request数据,—以下为response数据
string name
uint8 age
uint8 sex
uint8 unknown = 0
uint8 male =1
uint8 female = 2
string result
2、在package.xml中添加动态生成msg依赖的功能包
message_generation message_runtime

3、在CMakeList.txt添加编译选项
################################################ ## Declare ROS messages, services and actions ## ################################################ 在此目录下添加如下命令 add_service_files(FILES Person.srv) ##自动搜索srv下的文件 generate_messages(DEPENDENCIES std_msgs ) ##根据文件定义和std_msgs依赖产生对应头文件 添加依赖 catkin_package( #INCLUDE_DIRS include #LIBRARIES learning_service CATKIN_DEPENDS geometry_msg roscpp rospy std_msg turtlesim message_runtime #DEPENDS system_lib )

在工作目录中使用catkin_make编译生成头文件
创建服务器代码
/* * 该例程用于将请求/show_person服务,服务数据类型learning_service::Person * */ #include #includeint main(int argc,char** argv) { //初始化节点 ros::init(argc,argv,"person_client"); //创建节点句柄 ros::NodeHandle node; //发现/spawn服务后,创建一个服务客户端,连接名为/spawn的service ros::service::waitForService("show_person"); ros::ServiceClient person_client = node.serviceClient("/show_person"); //初始化learning_serviceL::Person请求数据 learning_service::Person srv; srv.request.name = "Tom"; srv.request.age = 27; 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 ; }

创建客户端代码
/* * 该例程将执行/show_person服务,服务数据类型learning_service::Person * */ #include #include//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的server,注册回调函数personCallback ros::ServiceServer person_service = n.advertiseService("/show_person",personCallback); //循环等待回调函数 ROS_INFO("Ready to show person inforntion"); ros::spin(); return 0; }

配置服务器/客户端代码编译规则
add_executable(person_clientsrc/person_client.cpp) ##把person_client.cpp代码编译为person_client可执行文件 target_link_libraries(person_client ${catkin_LIBRARIES}) ##把生成的person_client连接到ros中的库 add_executable(person_serversrc/person_server.cpp) ##把person_server.cpp代码编译为person_server可执行文件 target_link_libraries(person_server ${catkin_LIBRARIES}) ##把生成的person_server连接到ros中的库add_dependencies(person_client ${PROJECT_NAME}_gencpp) ## 和动态生成的头文件做依赖 add_dependencies(person_server ${PROJECT_NAME}_gencpp) ## 和动态生成的头文件做依赖

在工作空间根目录使用catkin_make编译
运行查看
roscore rosrun learning_service person_server rosrun learning_service person_client

可查看结果
ROS基础学习(一)
文章图片

运行server会发现等待show_person的数据
ROS基础学习(一)
文章图片

运行client请求service端show_person,与此同时可发现server端打印显示client发送的信息。
参数模型 参数命令行使用
rosparam list列出当前所有参数 rosparam get param_key显示某个参数值 rosparam set param_key param_value设置某个参数值 rosparam dump file_name保存参数到文件 rosparam load file_name从文件读取参数 rosparam delete param_key删除参数

首先在src中创建参数功能包
catkin_create_pkg learning_parameter roscpp rospy std_srvs

创建parameter.cpp文件
/** * 该例程设置/读取海龟例程中的参数 */ #include #include #include 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::Empty>("/clear"); std_srvs::Empty srv; clear_background.call(srv); sleep(1); return 0; }

在CMakeList.txt中添加依赖
add_executable(parameter_config src/parameter_config.cpp) target_link_libraries(parameter_config ${catkin_LIBRARIES})

在工作空间下catkin_make编译
运行测试
roscore
rosrun toutlesim turtlesim_node
rosrun learning_perameter parameter_config
ROS基础学习(一)
文章图片

    推荐阅读