机器人操作系统(ROS)浅析

这是看了《A Gentle Introduction to ROS 》这本书后记的笔记,网上刚好找得到中文版的,就看中文版了,欢迎大佬批评指正,如需书的pdf可留下邮箱。

1.文件架构

工作空间

  • 顾名思义就是进行操作的地方,放置有编译空间,
  • 初始化工作空间:在src文件夹下创建了一个 CMakeLists.txt 的文件,目的是告诉系统,这个是ROS的工作空间

为了可以正常使用它,我们需要设置环境变量,让环境变量在所有终端都可以使用

  • src文件下放置你所需要的功能包

功能包

  • 功能包的创建

    • 会自动生成src文件和CMakeLists.txt、package.xml文件
catkin_creat_package [功能包名字] [依赖]
依赖也可以在CMakeLists.txt、package.xml文件中进行添加
  • package.xml

    • 我们可以在这里添加我们需要的运行依赖、编译依赖
  • CMakeLists.txt
    • 规定了依赖哪些功能包,编译生成什么文件,如何编译等流程
    • 当我们在工作空间目录下进行编译时,catkin编译系统首先会找到每个package下的 CMakeLists.txt ,然后按照规则来编译构建。

2.节点

2.1节点管理器ROS Master

作用

  • ROS的通讯是基于节点来实现的,而ROSMaster起到了统一管理的作用
  • 节点之间需要能够互相通信,而实现这一步最关键的就是ROSMaster

使用

  • 必须roscore启动节点管理器
  • 使用rosrun启动节点只能开启一个节点,后面将会介绍roslaunch来启动节点,与rosrun不同的是,launch文件可以启动同时启动多个节点,并且会开启节点管理器

2.2节点

ROSwiki:一旦启动roscore后,便可以运行ROS程序了。ROS程序的运行
实例被称为节点(node)

使用rosrun命令来启动节点

rosrun [功能包名称] [节点名称(一般是生成的可执行文件)]
  • 如果该节点是发布消息的,那么就需要定义好消息的话题,数据类型
  • 如果该节点是接受消息的,那么就需要写明要接受的话题

查看节点

查看节点列表 rosnode list
查看特定节点 rosnode info node-name
终止节点 rosnode kill node-name

查看节点构成图

rqt_graph

在这个命令中,r 代表 ROS,qt 指的是用来实现这个可视化程序的 Qt 图形界面(GUI)工具包。输入该命令之后,你将会看到一个图形界面,其中大部分区域用于展示当前系统中的节点。

  • 注意:rqt_graph本身就是一个节点

3.话题和消息

节点管理器的作用的地方就是节点与节点之间的话题和消息

  • 获取当前活跃话题:rostopic list
  • 为 了 查 看 某 个 话 题 上 发 布 的 消 息 :rostopic echo topic-name
  • 查看消息类型:rosmsg show message-type-name

4.编写ROS程序

1.Hello_ROS

1.创建工作空间和功能包

2.在工作空间下创建src文件来放置功能包

3.按照自己需要的功能编写代码,注意:

  • 头文件需要包含ros/ros.h
  • 如果包含了消息类型就需要包含指定的头文件

4.代码完成后开始配置文件

  • CMakeLists.txt

    • 需要写明文件包含了哪些头文件
    • 添加文件编译选项
  • package.xml
    • 添加文件的编译运行依赖

5.进行编译

  • 如果是第一次进行编译,需要source一下环境

    source devel/setup.bash
    

6.运行

  • roscore启动节点管理器

  • rosrun启动节点

贴上代码

 // This is a ROS version of the standard "hello , world"// program.// This header defines the standard ROS classes .#include <ros/ros.h>int main ( int argc , char **argv ) {// Initialize the ROS system .ros::init ( argc , argv , "hello_ros" ) ;// Establ ish this program as a ROS node .ros::NodeHandle nh ;// Send some output as a log message .ROS_INFO_STREAM( "Hello,ROS!" ) ;}

2.发布者程序

2.1代码部分

  • 因为该程序中包含了消息类型,因此我们需要添加头文件
  • 用双分号(::)来区分开包名和类型名,双分号也称为范围解析运算符
  • main函数中首先进行初始化,并定义节点名称
  • 接着创建句柄
    • 句柄的作用是为了更方便的开启和关闭节点
  • 创建发布者对象
    • ros::Publisher pub = node_handle.advertise<message_type>(
      topic_name, queue_size);
    • 队列长度不是指存放那个多少字节,而是发布消息序列的大小
  • 进入循环( ros::ok () 检测的是程序作为 ROS 节点是否仍处于运行良好的状态。它会一直返回 true)
    • 创建消息对象
    • 发布消息
    • 定义消息发布格式

2.2编译部分

修改两个文件中的声明

贴上代码

 // This program publishes randomly−generated velocity// messages for turtlesim .#include <ros/ros.h>#include <geometry_msgs/Twist.h> // For geometry_msgs:: Twist#include <stdlib.h> // For rand() and RAND_MAXint main ( int argc , char **argv ) {// Initialize the ROS system and become a node .ros::init ( argc , argv , "publish_velocity" ) ;ros::NodeHandle nh ;// Create a publisher obj ect .ros::Publisher pub = nh.advertise <geometry_msgs::Twist >("turtle1/cmd_vel" , 1000) ;// Seed the random number generator .srand ( time ( 0 ) ) ;// Loop at 2Hz until the node is shut down.ros::Rate rate(2);while ( ros::ok () ) {// Create and fill in the message . The other four// fields , which are ignored by turtl esim , default to 0.geometry_msgs::Twist msg;msg.linear.x = double (rand())/double(RAND_MAX) ;msg.angular.z = 2*double(rand())/double(RAND_MAX)-1;// Publish the message .pub.publish(msg);// Send a message to rosout with the details .ROS_INFO_STREAM( "Sending random velocity command : "<< " linear=" << msg.linear.x<< " angular=" << msg.angular.z) ;// Wait untilit's time for another iteration .rate.sleep ( ) ;}
}

3.订阅者程序

与发布者差不多,下边介绍发布者中没有的内容

  • 回调函数:订阅者功能实现的地方

给ROS控制权

  • ros::spinOnce():要求ROS执行所有挂起的回调函数,然后返回控制权
    ros::spin():要求 ROS 等待并且执行回调函数,直到这个节点关机。
    换句话说,ros::spin()大体等于这样一个循环:
    while(ros::ok( ))
    {
    ros::spinOnce();
    }
  • 使用 ros::spinOnce()还是使用 ros::spin()的建议如下:你的程
    序除了响应回调函数,还有其他重复性工作要做吗?如果答案是
    “否”,那么使用 ros::spin();否则,合理的选择是写一个循环,做
    其他需要做的事情,并且周期性地调用 ros::spinOnce()来处理回调。

贴上代码

 // This program subscribes to turtle1/pose and shows its// messages on the screen .#include <ros/ros.h>#include <turtlesim/Pose.h>#include <iomanip> // for std::setprecision and std::fixed// A callback function . Executed each time a new pose// message arrives .void poseMessageReceived (const turtlesim::Pose &msg ) {ROS_INFO_STREAM( std::setprecision(2) << std::fixed<< "position =("<< msg.x << "," << msg.y << ")"<< "*direction=" << msg.theta ) ;}int main ( int argc , char **argv ) {// Initialize the ROS system and become a node .ros::init ( argc , argv , "subscribe_to_pose" ) ;ros::NodeHandle nh ;// Create a subscri ber object .ros::Subscriber sub = nh.subscribe ("turtle1/pose" ,1000,&poseMessageReceived ) ;// Let ROS take over .ros::spin ( ) ;}

5.日志消息

1.级别

DEBUG、INFO、WARN、ERROR、FATAL

  • 级别旨在提供一种区分和管理日志消息的全局方法

2.生成日志消息

  • 生成简单的日志消息

    #这些都是宏
    ROS_DEBUG_STREAM(message);
    ROS_INFO_STREAM(message);
    ROS_WARN_STREAM(message);
    ROS_ERROR_STREAM(message);
    ROS_FATAL_STREAM(message);
    
  • 生成一次性日志消息

    ROS_DEBUG_STREAM_ONCE(message);
    ROS_INFO_STREAM_ONCE (message);
    ROS_WARN_STREAM_ONCE (message);
    ROS_ERROR_STREAM_ONCE (message);
    ROS_FATAL_STREAM_ONCE (message);
    

3.查看日志消息

rqt_console:显示所有结点的日志消息

4.检查和清除日志文件

  • 查看当前账户中被ROS日志消耗的硬盘空间 :rosclean check

  • 如果日志正在消耗过多的硬盘空间,可以通过下面的命令删除所有已经存在的日志:rosclean purge

6.launch文件

launch文件的作用

  • 同时启动节点管理器和多个节点

  • 启动方式

    roslaunch package-name launch-file-name
    

如何编写launch文件

1.根元素

<launch>
...
<launch>

2.写节点

<node
pkg=package-name”
type=executable-name”
name=node-name”
/>注意:如果有remap或在param元素这样的子节点,就需要加上</node>标签,称为显式结束标签
<node pkg=”...” type=”...” name=”...”></node>

3.节点中的元素

  • pkg、type就不在这多讲了
  • name给节点指派了名称,可以覆盖其他赋予节点的名称
  • output=screen” 可以在控制台中输出信息(等校于roslaunch –screen package-name launch-file-name)
  • respawn=“true” 请求复位,可以在节点停止的时候重启该节点,常常用于必要节点
  • required=”true”在一个必要节点关闭的时候可以关闭其他节点

launch文件的缺点:对于launch文件启动的节点是共用一个终端的,如果有需要控制台控制的节点则建议使用rosrun单独启动,例如键盘控制节点

  • 节点元素使用启动前缀(launch-prefix)属性:launch-prefix=“command-prefix”

  • xterm–e rosrun turtlesim turtle_teleop_key,xterm-e会开启一个终端窗口来运行rosrun的代码

4.包含其他launch文件

<include file="path-to-launch-file”>(这里路径需要完整路径,建议使用下边这种方法)
或者
<include file=$(find package-name)/launch-file-name”>

5.启动参数(这个目前没怎么用过但还是记一下笔记吧)

  • 我们可以在roslaunch命令行中修改参数,但是只能改default的值,改不了value的值,因此有了下边这种写法
<incluce file=”path–to-launch-file”>
<arg name=”arg-name” value=”arg-value”/>
...
</include>

6.创建组

  • 可以将许多节点放在 同一命名空间下,写法为
<group ns=”namespace”/>
...
</group>
  • 且组可以有条件的使能或者禁用一个节点
<group if=”0 or 1”/>
</group>
在这里,如果if的属性值是1,那么该标签内元素就正常包含,反之会被忽略
unless意思相反

注意:1.一般不会直接设置为0或1,灵活运用启动参数,丰富启动文件的可配置性

2.组不是必须的,当然我们也可以单独为每个节点配置if,ns等属性

3.有些属性不能通过组来传递,例如output=”screen”,我们需要单独为节点设置该属性

  • csdn上看到这边笔记也很棒:launch文件

7.参数

1.基础操作

  • 查看参数列表:rosparam list
  • 查询某个参数的值:rosparam get /参数
    • 例如:rosparam get /rosistro 得到的是ros的操作版本
  • 设置参数:rosparam set 参数名 值
同时设置一个命名空间中的几个参数
rosparam set /duck_colors "huey: red
dewey: blue
louie: green
webby: pink"
注意:第一个引号告诉bash 命令尚未完成,因此按下回车时终端将会插入一个换行符而不是执行命令
  • 创建参数文件:rosparam dump filename namespace
  • 加载参数文件:rosparam load filename namespace(namespace默认是全局命名空间/)

2.案例

  • 设置背景颜色后,只有调用turtlesim_node的/clear服务后才会从参数服务器读取参数的值

    • 调用该服务:rosservice call /clear

3.使用ROS参数的C++接口

void ros::param::set(parameter_name, input_value);
bool ros::param::get(parameter_name, output_value);

4.启动文件中设置参数

<node
pkg="agitr"
type="pubvel_with_max"
name="publish_velocity"
/>
<param name="max_vel" value="3" />
</node>

8.服务

  • 服务调用是双向的,节点消息发出去后会等待响应
  • 实现的是一对一的通讯,每个服务由一个节点发起,响应也返回同一个节点。每一个消息都和一个话题相关,该话题可能有很多个发布者和订阅者

1.概念

客户端(client):发送请求到服务器节点等待响应

服务端(server):接受到请求后作出响应,响应可以是配置,改变某些行为

请求和响应携带的内容由数据类型决定,数据类型分为两部分:客户端和服务端

2.服务查询

rosservice list:查询活跃的服务,输出的服务名称是全局名称

rosnode info node-name:查看某个节点的服务类型

rosservice node service-name:查看服务是由哪个节点发出的

rosservice info service-name:查看服务的数据类型

roscrv show service-date-type-name:查看服务数据类型的详情(即发布和响应的数据字段,字段可以同时为空)

  • 注意区分rosservice和rossrv的区别

    Topics Services
    active things rostopic rosservice
    date types rosmsg rossrv

3.两类服务类型

  • 一些服务:由特定节点获取或传递信息,例如get_loggers 和 set_logger_level
  • 其他服务:不针对某些特定节点的服务,我们调用该服务时只关心服务的结果,而不关心服务是由哪个节点产生的

4.从命令行调用服务

  • rosservice call service-name request-content

    例如:rosservice call /spawn 3 3 0 Mikey 这条服务调用的效果是在现有仿真器中,位置 ( x , y ) = (3,3) 处创建一个名为“Mikey”的新海龟,其朝向角度 θ = 0 。这些新的资源都在新的命名空间Mikey中,很好的阐明了命名空间可以有效的阻止命名冲突

5.客户端程序

1.声明请求和响应的类型

#include <package_name/type_name.h>

2.创建客户端对象

首先ros::init和创建NodeHandle句柄

ros::ServiceClient client = node_handle.serviceClient<service_type>(
service_name);
  • node_handle 是常用的 ros::NodeHandle 对象,这里我们将调用它的 serviceClient 方法
  • service_type 是我们在上面头文件中定义的服务对象的数据类型
  • service_name 是一个字符串,说明了我们想要调用的服务名称。再次强调,这应当是一个相对名称,虽然也可以声明为全局名称。

与发布者不同的是,服务不需要设置队列大小,服务调用直到响应后才会返回,所以不用维持发送状态

3.创建请求和响应对象

定义请求和响应的类,命名为Request和Response

4.声明依赖

编辑 CMakeLists.txt 和清单文件 packag.xml

贴上代码

// This program spawns a new turtlesim turtle by calling// the appropriate service .#include <ros/ros.h>// The srv class for the service .#include <turtlesim/Spawn.h>int main( int argc , char ** argv ) {ros::init( argc , argv , "spawn_turtle") ;ros::NodeHandle nh ;// Create a client object for the spawn service . This// needs to know the data type of the service and its// name.ros::ServiceClient spawnClient= nh.serviceClient <turtlesim::Spawn>("spawn") ;// Create the request and response objects.turtlesim::Spawn::Request req ;turtlesim::Spawn::Response resp ;// Fill in the request data members.// 不能在这里给Response对象赋值req.x = 2;req.y = 3;req.theta = M_PI/2;req.name = "Leo" ;// Actually c a l l the service. This won't return until// the service is complete .// 这一步是在调用服务bool success = spawnClient.call( req , resp ) ;// Check for success and use the response .核对服务调用的返回值i f ( success ) {ROS_INFO_STREAM("Spawned␣ a␣ turtle␣ named␣ "<< resp.name) ;} else {ROS_ERROR_STREAM("Failed␣ to␣ spawn.") ;}}

6.服务器程序

  • 当接受到请求时,进入回调函数,Request来自于客户端的数据

1.编写服务的回调函数

bool function_name(
package_name::service_type::Request &req),
package_name::service_type::Response &resp)
) {
...
}

当回调函数返回true表明成功,false表明失败

2.创建对象

ros::ServiceServer server = node_handle.advertiseService(
service_name,pointer_to_callback_function);

最后一个参数是指向回调函数的指针

3.注意

因为用到了回调函数,所以我们需要提供ROS控制权

贴上代码

 // This program t oggles between rotation and translation// commands, based on calls to a service .#include <ros/ros.h>#include <std_srvs/Empty.h>#include <geometry_msgs/Twist.h>bool forward = true ;bool toggleForward (std_srvs::Empty::Request &req ,std_srvs::Empty::Response &resp) {forward = !forward ;ROS_INFO_STREAM("Now␣ sending␣ " << ( forward ?"forward" : " rotate ") << "␣ commands.") ;return true ;}int main( int argc , char ** argv ) {ros::i n i t ( argc , argv , "pubvel_toggle") ;ros::NodeHandle nh ;// Register our service with the master .ros::ServiceServer server = nh.advertiseService ("toggle_forward" , &toggleForward ) ;// Publish commands, using the latest value for forward ,// until the node shuts down.ros::Publisher pub = nh.advertise <geometry_msgs::Twist>("turtle1/cmd_vel" , 1000) ;ros::Rate rate (2) ;while ( ros::ok () ) {geometry_msgs::Twist msg ;msg.linear.x = forward ? 1.0 : 0.0 ;msg.angular.z = forward ? 0.0 : 1.0 ;pub.publish (msg) ;ros::spinOnce () ;rate.sleep () ;}}

缺陷分析

  • 代码中有延迟,原因是sleep系统会以较低的频率进行循环,大部分时间处于休眠,大部分服务调用在sleep执行时到达,等待后再执行

解决方案

  • 使用两个线程:一个发布消息,一个处理服务回调
  • 使用ros::spin来代替sleep/ros::spinOnce循环,并且利用计数器回调函数(timer callback) 来发布消息

9.消息的录制与回放

使用包(bag)文件来录制和回放信息

通过 rosbag,我们能够将发布在一个或者多个话题上的消息录制到一个包文件中,然后可以回放这些消息,重现相似的运行过程。将这两种能力结合,便形成了测试某些机器人软件的有效方式:我们可以偶尔运行机器人,运行过程中录制关注的话题,然后多次回放与这些话题相关的消息,同时使用处理这些数据的软件进行实验。

1.录制和回放包文件

  • 录制包文件:rosbag record -O filename.bag topic-names(如果不指定文件名,就会基于日期和时间自动生成文件名)

  • 也可以使用rosbag record -a记录当前所有话题的消息

  • Ctrl+C停止rosbag

  • 回放包文件:rosbag play filename.bag

  • 检查文件包:rosbag info filename.bag

2.注意

rosbag如果没有记录初始状态,则在回放时会在结束时刻的位置开始回放

3.放入launch文件

方法:包括适当的节点元素

  • 录制节点

    <node
    pkg="rosbag"
    name="record"
    type="record"
    args="-O filename.bag topic-names"
    />
    
  • 回放节点

    <node
    pkg="rosbag"
    name="play"
    type="play"
    args="filename.bag"
    />
    

10.提升

1.规范代码

2.将数据可视化

3.创建消息和服务类型

4.使用TF工具管理多个坐标系

5.使用Gazebo仿真

《机器人操作系统(ROS)浅析》笔记相关推荐

  1. 《信贷的逻辑与常识》笔记

    序 银行信贷风险管理的反思 现状与趋势 银行贷款的质量变化与经济周期.宏观调控政策等存在很高的相关性 现在银行不良贷款的增加主要是前几年经济快速增长时企业过度投资.银行过度放贷所带来的结果. 从历史情 ...

  2. AI公开课:19.02.27周逵(投资人)《AI时代的投资逻辑》课堂笔记以及个人感悟

    AI公开课:19.02.27周逵(投资人)<AI时代的投资逻辑>课堂笔记以及个人感悟 目录 课堂PPT图片 精彩语录 个人感悟 课堂PPT图片 精彩语录 更新中-- 文件图片已经丢失-- ...

  3. 人工智能入门算法逻辑回归学习笔记

    逻辑回归是一个非常经典的算法,其中也包含了非常多的细节,曾看到一句话:如果面试官问你熟悉哪个机器学习模型,可以说 SVM,但千万别说 LR,因为细节真的太多了. 秉持着精益求精的工匠精神不断对笔记进行 ...

  4. 【逻辑回归学习笔记】

    算法描述 1.逻辑回归要做的事就是寻找分界面实现二分类. 2.问题假设:对一堆三角形和正方形分类. 3.数据输入:已知正方形和三角形的坐标和标签. 4.算法过程: 知识储备 1.分类和回归 ①分类的目 ...

  5. 逻辑回归函数学习笔记

    继续逻辑回归学习,今日笔记记录. 1.逻辑回归和线性回归的关系:对逻辑回归的概率比取自然对数,则得到的是一个线性函数,推导过程如下. 首先,看逻辑回归的定义 其次,计算两个极端y/(1-y),其值为( ...

  6. 2.2 逻辑回归-机器学习笔记-斯坦福吴恩达教授

    逻辑回归 上一节我们知道,使用线性回归来处理 0/1 分类问题总是困难重重的,因此,人们定义了逻辑回归来完成 0/1 分类问题,逻辑一词也代表了是(1) 和 非(0). Sigmoid预测函数 在逻辑 ...

  7. LVM逻辑卷分区笔记

    磁盘的静态分区有其缺点:分区大小难评估,估计不准确,当分区空间不够用的时候,系统管理员可能需要先备份整个系统,清除磁盘空间,然后重新对磁盘进行分区,然后恢复磁盘数据到新分区,且需要停机一段时间进行恢复 ...

  8. 适合理工直男的钟平老师逻辑英语学习笔记

    一切的一切都只是套路!             --鲁迅 核心公式: En: (状语1) 主(定语1) 谓(状语2) (宾)(定语2) (状语1) Ch: (状语1) (定语1)主 (状语2)谓 (定 ...

  9. 【数字逻辑】学习笔记 第四章 Part2 常用组合逻辑电路与竞争、险象

    文章目录 一.常用组合逻辑电路 1. 译码器 (1) 二进制译码器 74LS138(3/8译码器) a. 一般符号和图形符号 b. 74LS138功能表 c. 两片 `74LS138` 构成 `4-1 ...

  10. 线性回归、逻辑回归学习笔记

    学习源代码 import numpy as np import matplotlib.pyplot as plt def true_fun(X): # 这是我们设定的真实函数,即ground trut ...

最新文章

  1. SQL 2012 Group By Rollup, Grouping
  2. nginx和apache 配置
  3. 建模元件有哪些在MapleSim中
  4. Xshell连接Linux
  5. 令牌桶算法和漏桶算法python_图解Python算法
  6. LeetCode 一题多解
  7. Mac自带嗅探器和Wireshake抓包(三)
  8. python的下划线
  9. Java房地产销售管理系统_Java学员作品-房地产销售管理系统
  10. 《东周列国志》第二十二回 公子友两定鲁君 齐皇子独对委蛇
  11. 字体外面怎么加边框_CSS如何给字体加边框
  12. 给大家爆个秘密:怎样迅速提高你的校内人人网人气
  13. 韶音耳机连不上电脑_骨传导耳机怎么连接电脑
  14. linux登录界面鼠标键盘失灵,在archlinux安装界面这卡住了,鼠标键盘失灵
  15. 最简单的改变字体大小代码
  16. 【2022版】Java多线程与高并发面试题总结,108道题含答案解析。
  17. jQuery图片预览插件
  18. requests模块用法举例
  19. 企业AAA信用等级认证好处
  20. JavaScript到底算不算函数式编程语言?

热门文章

  1. 基于信号指纹的多旋翼无人机遥控端个体识别研究(1)
  2. tmi 技术管理与服创新_技术创新与流程创新
  3. 概率论——泊松随机变量
  4. phpcms v9电脑pc站+手机wap移动端双模板共用数据库数据同步可同步生成静态文件
  5. 【开发工具集】Process Explorer——进程资源管理器
  6. 【软考-软件设计师】(下午题).
  7. python课后练习
  8. 【计算机科学】【2013.08】无人机路径规划问题的算法研究
  9. RGB565 to gray
  10. WPF--Prism框架安装初识