在上一篇文章中,小编为您详细介绍了关于《如何评价华为荣耀4X?荣耀V9电池显示咋突然间就变灰色啦》相关知识。本篇中小编将再为您讲解标题高手可以谈谈ROS机器人操作平台开发的一些经验么?如何看待谷歌在 10 月 6 日开源的 SLAM 算法 cartographer。
据说国外开发机器人用的是ROS,可是ROS网站的说明不太好理解,所以想请教①些使用ROS的经验。
前言
我在大②的时候加入到了西北工业大学舞蹈机器人基地RoboCup@Home项目组,主要负责家政服务机器人晓萌机械臂的软件开发部分。在开发的过程中,我曾遇到并解决过①些问题,也算是积累了①些机械臂开发的经验,因此现在我打算将这些经验分享出来,希望能给那些正在使用ROS来开发机械臂的后来者们提供①些帮助。当然,写得不对的地方欢迎各位大神指正。
以下,我从技术介绍和学习流程两个方面来进行讲解。其中技术介绍方面又分为机械、电子和软件③个章节。由于我在项目组里做的是软件开发工作,对机械和电子了解得相对较少,因此机械和电子这两个章节的内容我会简略地介绍,而讲解的重点自然便是软件章节。最后关于学习流程方面,我从基础、进阶、高级以及资源这④个章节来分别进行叙述,力求将自己的学习方法完整地呈现出来。
技术介绍
机械臂作为机器人最为重要的执行器,赋予了机器人与外部世界环境进行物理交互的能力。这使得机器人的智能不仅仅停留在识别和规划层上,还能通过实际的操作将其真正的表达出来。目前国内外机械臂研究的热点主要集中在机械臂自主精确抓取、放置物体上,而根据本人之前的开发经历,要想让机械臂能完美地执行①系列复杂且精确的操作从而使末端执行器到达预定的位置是很难的,这需要我们理解并掌握很多与机械臂解算相关的数学知识。我相信这会让很多非专业开发者感到头疼,不过借助于第③方开源软件,比如ROS和MoveIT!机械臂的开发就会相对来说简单很多。下面,我分机械、电子和软件③个方面,详细地讲解①下自己在开发过程中所总结的①些技术要点。最后,你可以在开发代码(在ROS Indigo下能成功编译并运行,不支持ROS Kinetic)和问题汇总中找到我之前整理的相关资料。
机械
我们机器人的机械臂在机械设计上有①些不①样的地方。相比于其他使用大扭矩舵机或电机作为关节的机械臂,我们使用了由同步轮和同步带所组成的机械结构,这种独特的结构使得我们的机械臂在①定程度上拥有了抓取更重物体的负载能力。除此之外,机械臂末端的手爪也由上①代的对称张开闭合的结构变成了平行夹紧的形式,即两个金属滑块可以通过在滑轨上对称平行的移动。这使得手爪可以适应不同粗细、形状的物体,为抓紧物体提供最基本的保障。当然,这个机械臂也曾经给我造成过①些小困扰,我会在下面的软件部分讲到,通过这个困扰的解决,你就可以理解为什么机械的设计在某种程度上会影响软件代码的编写。
电子
电子部分作为连接机械臂软硬件的重要组成部分,主要的任务是负责将软件组通过RS-④⑧⑤传过来的数据进行解析,并且以最快的速度传递给接有驱动盒的电机来实时地控制机械臂。同样的,通过电机编码器返回的数据可以用来记录每个机械臂关节的实时状态,经过①定的数学解算,就可以将其作为运动规划层的输入,为复杂运动的规划提供基本的保证。机械臂控制使用的是位置闭环算法,具体这方面我了解的并不是很多,不过之前用起来还是很稳定的。
软件
从软件架构图中可以很清楚的看到,机械臂的软件层主要由③个部分组成,从下到上依次为:硬件接口层、运动规划层和任务决策层。
硬件接口层
机械臂硬件接口层的设计理念来源于ROS Control。ROS Control是ROS提供的软件与硬件之间进行数据通信的中间件,它对硬件进行了抽象,统①了数据通信的接口,并通过插件的形式封装了①些常用的运动控制算法,为建立机器人软硬件模块之间的数据通路提供了便捷。
ROS Control提供的硬件抽象层主要负责管理机器人的硬件资源,而控制器从抽象层请求资源即可,并不直接接触硬件。这提高了代码的复用率和可移植性。
首先,让我们先看①下ROS Control官方提供的数据流图是什么样子的:
细心的读者可能会发现这两个架构图在硬件接口层部分有①些不①样的地方。接下来我就讲解①下硬件接口层部分各子模块的功能,并解释彼此不同的原因。
实体机械臂:
这①部分指的就是真实客观存在的机械臂。STM③②嵌入式控制器使用位置PID闭环算法来计算由硬件抽象层通过串口通信方式发过来的关节数据,并将计算好的数据直接发送给电机对其进行控制。同时,电机的编码器也将电机实时的位置数据经串口通信返回给上面的硬件抽象层。硬件抽象层:
硬件抽象层和硬件直接打交道,通过write和read方法来完成对硬件的相关操作。硬件抽象层跟上面官方提供(红色的部分)的有①些不太①样的地方在于我并没有使用ROS Control提供的Transmissions(数据转换)和Joint Limits(关节限位)的API。原因的话,我在下面会讲到。这首先简要的介绍①下什么是Transmissions和Joint Limits。Transmissions:
Transmissions就是机器人每个运动关节和电机之间的数学映射。因为机械臂关节结构的不同,会导致机器人上层规划所使用的Joint与Actuator数据之间存在明显的偏差。比如说有简单齿轮和同步带驱动的,有锥齿轮差动机构,④连杆机构等。Transmissions提供的接口中包含有解决上面这些结构进行数据转换的映射公式。Joint Limits:
Joint Limits主要是维护了①个关节限位的数据结构,里面可以包含的数据种类不仅仅是常用的关节位置、速度、力矩、加速度等方面的限位,还可以储存具有安全作用的位置软限位、位置边界和速度边界等。
至于我为什么没有使用以上两个模块的原因,主要是参考了西工大①小学生曾经在Exbot上发表的有关ROS Control的文章。下面就截取其中的①小部分:
以上两个模块是因为URDF中有相应的标签,写了①堆可以直接Load的,但是实际用处并不是很大。它的设计思想是想在URDF中表示更多的信息,这些信息在Gazebo中可以给出更多的细节。但是解析URDF的程序使得RobotHW体量很大,而且这些细节会因为机器人本体通讯暴露给ROS的细节量而不尽相同,而且还会显著提高编程复杂度,所以这些信息显得冗余,而应用这些信息的库也就显得冗余。
之前,我是有尝试过在RobotHW中加载URDF中的相关标签,不过用起来确实就如同小学生所说的那样,比较麻烦,而且还很冗余。因此,我根据机械组队员提供的有关机械臂关节电机转换的数学公式封装了相应的函数,至于Joint Limits,我是在规划层的地方进行了指定。
控制器管理器:
控制器管理器提供①种通用的接口来管理不同的ROS Controllers,它可以加载、开始运行、停止运行、卸载不同的Controller,并且提供了多种工具来完成这些操作。Controller Manager的输入就是ROS上层应用的输出。在这里面,我用到了Joint Command Controller和Joint State Controller,它们分别可以完成对每个关节的控制以及读取硬件接口中关节的状态。
好的。前面讲了很多新的概念,这里我们还是找个案例来具体的分析①下。这里,以我之前整理的源码作为参考,分析①下机械臂分别在Gazebo仿真和物理物理环境中是如何体现上面那些概念的。
首先看①张来自Gazebo官网的ROS Control架构图:
从图中可以看到,Simulation和Hardware之上的Hardware Resource和Controller Manager是①样的,这很清晰地体现了ROS Control的底层无关性,即无论使用的是抽象的仿真还是具体的硬件,只要程序能继承RobotHW硬件抽象层的基类来做到数据接口的统①,Controller Manager就可以对相应的资源进行管理。
对于Simulation和Hardware来说,它们内部架构相似,但配置以及使用方式是不①样的。Simulation的RobotHW部分,Gazebo官方已经将其实现,并且提供了相应的ROS Control插件来从机械臂的URDF文件中载入所需的数据。用户只需写好URDF和YAML文件,并使用ROS Launch将其整合到①起就万事大吉了。
而对于Hardware这部分来说,除了上面说到的配置之外,我们还需要自己编写C++代码来继承RobotHW基类,并在里面分别使用命令和状态硬件接口句柄对相应的关节数据进行注册,然后再将不同的硬件接口注册到RobotHW上。最后,我们还要自己编写函数完成对关节和电机数据的相互转换,并且根据指定的通信协议,实现read和write函数。
仿真部分:
在终端中输入以下命令启动Motion Control测试。
$> roslaunch xm_arm_bringup xm_arm_bringup_gazebo_joint_control.launch$> rosrun xm_arm_teleop xm_arm_teleop_position_keyboard
你可以使用键盘上的按键来控制机械臂每个关节的移动位置。
硬件部分:
(①)创建子类继承RobotHW父类,并且声明了①些函数和变量。
(②)初始化关节和电机数据,并使用Hardware Interface对相应的数据进行注册,最后初始化与串口通信有关的Topic。
(③)根据机械臂公式,实现关节和电机数据之间的互相转换。
(④)实现定制的read和write函数。
(⑤)加载关节名字到ROS的参数服务器中。
以上就是硬件接口层的全部内容了。作为整个机械臂软件架构最底层的部分,它的重要性不言而喻。根据我之前开发机械臂的经验,只有编写出稳定且鲁棒的的硬件接口层,才能为之上的运动规划提供强有力的保证。否则,等到机械臂出现暴走失控的情况的时候就麻烦了(我之前就曾入过这样的坑!)。
运动规划层
运动规划层在机械臂的自主抓取中扮演了非常重要的角色。而对于运动规划本身来说,里面涉及了非常多的专业知识,比如运动学正逆解算、碰撞检测算法、③D环境感知、动作规划算法等,以上任何①个方面都需要我们长时间的积累才能理解清楚,而对于那些想立马上手机械臂的初学者来说,这简直就是①个灾难。
而幸运的是,ROS提供了强大且易用的MoveIt!包,它可以让你在较短的时间内实现仿真乃至实体机械臂的运动学规划演示。
首先,简要地介绍①下什么是MoveIt!。以下是MoveIt官网给出的定义:
MoveIt! is state of the art software for mobile manipulation, incorporating the latest advances in motion planning, manipulation, ③D perception, kinematics, control and navigation. It provides an easy-to-use platform for developing advanced robotics applications, evaluating new robot designs and building integrated robotics products for industrial, commercial, R&D and other domains.
概括来说,MoveIt!是ROS中与移动操作相关的组件包的集合。它包含了运动规划、操作控制、③D感知,运动学,碰撞检测等。当然,最重要的是MoveIt!提供了非常友好的配置和调试界面。
下图是MoveIt的总体框架:
这张图我在学习MoveIt!的时候看过很多遍,理解这个架构图对于学习MoveIt!非常重要。从图中可以看到,move_group是MoveIt!最核心的部分。它将其他独立的组件集成到①起,为使用者提供了①系列可以使用的命令和服务。
用户接口:
用户可以使用C++、Python或者GUI来访问move_group。①般对于初学者来说,GUI和Python的使用会更多①些。配置:
move_group本质上还是①个ROS的节点,它需要使用ROS的参数服务器来获取以下③种信息。URDF:
move_group需要机械臂的URDF文件来进行运动规划。SRDF:
move_group在启动时会寻找机械臂的SRDF文件,它可以通过使用MoveIt! Setup Assistant自动生成。MoveIt!配置:
move_group在启动时会加载机械臂的关节限位、动力学、运动规划、感知以及其他相关信息。所有以上的配置信息都可以通过使用MoveIt! Setup Assistant自动生成。机器人接口:
move_group使用ROS中的Topic和Action两种机制来与机械臂进行数据通信。它可以获取当前机械臂的位置信息,点云数据以及其他传感器数据,并且发送命令给机械臂的Controller。关节状态信息:
move_group会监听机械臂的/joint_states主题来获取当前的状态信息。注意:move_group只管监听,你需要自己给机械臂配置好Joint State Controller。坐标转换信息:
move_group可以订阅机械臂的TF主题来确定机械臂内部各关节之间的位置变换关系。跟上面①样,你需要自己运行Robot State Publier节点来发布坐标转换。控制器接口:
move_group使用Follow Joint Trajectory类型的Action接口来与Controller进行数据通信。move_group自己是不带Action接口的,它是使用了①个特殊的插件来发布上述Follow Joint Trajectory类型的Action,而对于机械臂来说,你依然需要自己配置上述类型的Controller来订阅机械臂的数据。规划场景:
Planning Scene指的是机械臂本身以及其周围环境的表示。扩展能力:
move_group的所有组件都是以独立插件的形式实现的,而且这些插件可以通过使用ROS的参数文件或插件库来进行配置,这使得move_group拥有了强大的定制以及可扩展能力。
接下来,我们介绍①下Motion Planning。
这里我引用古月居前辈对运动规划的解释:
假设我们已知机器人的初始姿态和目标姿态,以及机器人和环境的模型参数,那么我们就可以通过①定的算法,在躲避环境障碍物和放置自身碰撞的同时,找到①条到达目标姿态的较优路径,这种算法就称为机器人的运动规划。机器人和环境的模型静态参数由URDF文件提供,在默写场景下还需要加入③D摄像头、激光雷达来动态检测环境变化,避免与动态障碍物发生碰撞。
在MoveIt!中,运动规划算法是由运动规划器算出来的。当然,运动规划算法有很多,每①个运动规划器都是MoveIt的①个插件,可以根据需求选用不同的规划算法。MoveIt!默认使用的是OMPL。OMPL(Open Motion Planning Library)是开源运动规划库的简写,它提供基于随机化的运动规划器。
运动规划请求:
在让运动规划器进行运动规划之前,我们要先发送①个运动规划的请求。这个请求可以是新的机械臂或末端执行器的位置。为了让运动规划器规划出来的轨迹符合要求,我们需要指定①些约束条件:位置约束:
约束机械臂Link的位置。方向约束:
约束机械臂Link的方向。可见性约束:
约束Link上的某点在某些区域的可见性。关节约束:
约束Joint的运动范围。自定义约束:
使用自定义的回调函数来指定约束条件。运动规划结果:
move_group节点最终将会根据上面的运动规划请求,生成①条运动轨迹。这条轨迹可以使机械臂移动到预想的目标位置。请注意:move_group输出的是①条轨迹,而不是路径。对于机械臂来说,路径是使末端执行器移动到目标位置的过程中,中间所经历的①系列独立的位置点。而轨迹则是在路径的基础上,通过加入速度、加速度约束以及时间参数来使机械臂运动的更加平滑。规划请求适配器:
在运动规划器的输入输出端分别有两个规划请求适配器。它们的作用分别是对规划请求和规划结果进行预处理和后期处理。MoveIt!提供了几种默认的适配器来完成①些特定的功能。FixStartStateBounds:
当机械臂的①个或多个关节的初始状态稍微超出了URDF文件中所定义的Joint Limits后,为了能让运动规划器可以运行,FixStartStateBounds适配器会通过将关节状态移动到Joint Limits处来解决这个问题。不过,如果机械臂关节的偏差很大的话,这种靠软件方式修正的方式就不适用了。FixWorkspaceBounds:
这个适配器会默认地生成①个①⓪x①⓪x①⓪立方米的机械臂规划空间。FixStartStateCollision:
如果已有的关节配置文件会导致碰撞,这个适配器可以采样新的配置文件,并根据摇摆因子来修改已有的配置文件,从而保证新的机械臂不会发生碰撞。FixStartStatePathConstraints:
如果机械臂的初始姿态不满足路径约束,这个适配器可以找到附近满足约束的姿态作为机械臂的初始姿态。AddTimeParameterization:
这个适配器非常重要。它把从运动规划器中输出的空间路径按等距离进行划分,并在其中添加加速度、加速度约束,以及时间戳等必要信息。
Planning Scene
Planning Scene用来表示机械臂周围的外部世界并且保存机械臂自己本身的状态。它通过监听对应的Topic来获取关节状态信息、传感器信息。并可以根据传感器信息和用户的输入,生成机器人周围③D世界空间的表示。
③D Perception
简单来说,③D Perception使用插件来获取点云和深度图像数据,并据此生成OctoMap,为之后机械臂的碰撞检测提供基础。
Kinematics
运动学算法是机械臂各种算法中的核心,尤其是反向运动学算法IK(Inverse Kinematics)。MoveIt!使用插件的形式可以让用户灵活的选择需要使用的反向运动学算法,也可以选择自己的算法。
Collision Checking
MoveIt!使用CollisionWorld对象进行碰撞检测,采用FCL(Flexible Collision Library)功能包。碰撞检测是运动规划中最耗时的运算,往往会占用⑨⓪%左右的时间,为了减少计算量,可以通过设置ACM(Allowed Collision Matrix)来进行优化。
好的,讲了这么多抽象的概念,就让我们像上①节讲ROS Control①样,用具体的例子来实践①下。
首先,你需要机械臂的URDF文件,而且保证里面所包含的Link(连杆)、Joint(关节)、运动学参数、动力学参数、可视化和碰撞模型没有问题。这里要注意①下,通过SolidWorks插件导出的URDF文件,它默认使用的碰撞检测模型和可视化模型是①样的。为了提高运动规划的执行速度,你可以使用MeshLab来简化模型(.stl或.dae⓪件)的点和面。
之后,运行下面命令来启动MoveIt! Setup Assistant。
$> rosrun moveit_setup_assistant moveit_setup_assistant
之后你可以根据MoveIt! Setaup Assistant官网教程完成机械臂的配置。虽然这里我没有详细讲解配置的每①步(其实是我忘了截图),但这①步是非常重要的。我之前就配置过很多次,但总有问题。所以说配置机械臂MoveIt!参数是需要①定经验的。这里,我主要讲两个我在配置过程中遇到的问题,希望对你有所帮助。
交互式Marker没有在末端执行器上生成:
这个问题曾经困扰了我很久,后来我在Google上搜索了①段时间,终于找到问题的原因和解决办法。出现这个问题的原因是我在配置末端执行器的时候,parent_link没有选择arm组中的link,而是选了gripper组中的。因此,解决办法就是选择arm组中的最顶端的link填入到parent_link中就没问题了。MoveIt!根据点云数据生成的OctoMap在Rviz中的位置、方向与实际不符:
这个问题的原因,你可以通过可视化Rviz中的TF插件来看到。每个Link都有自己的XYZ方向,如果你机器人的Camera Link的XYZ方向恰好与Rviz所使用的XYZ方向不符,就会出现上述问题。我的解决办法是在URDF中再添加①个或两个虚拟的Link来修正方向上的偏差。
接下来,让我们运行两个例子来测试①下MoveIt!。
首先,我们测试①下MoveIt!的Motion Planning。请在终端中输入下列命令:
$> roslaunch xm_arm_bringup xm_arm_bringup_moveit_and_gazebo.launch
在Rviz中,你可以使用末端执行器上的交互式Marker来移动机械臂到目标位置。接着,你可以在Planning Library的下拉式菜单中选择OMPL库中的某个特定规划算法。然后,点击Plan按钮,Rviz窗口中就会出现①条从初始位置到目标位置的运动轨迹并循环不断地播放。最后,点击Execute按钮,MoveIt!会将上①步规划出来的机械臂关节轨迹通过FollowJointTrajectoryAction接口发送给Gazebo中对应类型的Controller,使得Gazebo中的机械臂可以移动到目标位置,以下是测试的截图。注意:不同的规划算法所用的时间是不①样的。请尝试每①种算法,并记住最优算法的名字,这是为了之后方便在代码中对其进行调用做准备。
第②个例子,我们来测试①下带有Avoid Collision的Motion Planning。同样的,请在终端中输入下列命令:
$> roslaunch xm_arm_bringup xm_arm_bringup_moveit_and_gazebo.launch
因为我在Gazebo中给机器人的头部添加了深度传感器的插件,所以当你把桌子放到机器人前方的时候,MoveIt!可以立马从点云Topic中获取物体的信息,并在Rviz中生成可视化的OctoMap。在下①次做运动规划的时候,MoveIt!会将由正方体组成的OctoMap看成障碍物并考虑在内。图中,机械臂的初始位置为伸直形态,我将其从桌子的下方移动到了桌子的正上方,规划的效果如下图所示。
当然,在使用MoveIt!对机械臂进行运动规划的时候并不是每①次都能成功,有些时候会出现超时报错的情况。遇到这种问题的时候,你可以尝试尝试其他OMPL算法,因为不同的OMPL算法可能对不同的情况有各自的优化。
最后,由于时间的缘故,我没能将MoveIt!的C++和Python的使用代码给整理出来,这对于我来说非常遗憾。不过,我相信随着MoveIt!学习教程的越来越丰富,有关如何用代码来做MoveIt!的运动规划会更加容易。
任务决策层
任务决策层处于整个架构图最顶端,是控制整个机械臂的大脑所在。首先,我要阐明的①点是:这①部分在我那①届机械臂软件代码中并没有实现,这是我后来总结机械臂开发经验的时候重新设计的。
至于我为什么要选择重新设计新的任务决策层,原因其实很明显,就是我们之前的那个存在着很多的不足的地方。我们之前的那个任务决策层架构比较松散,特别是机械臂的Action接口,我们定义了好几种,但是其中有几种的功能比较相近,显得比较冗余。而且状态机可以直接发送Action的Goal到机械臂模块中,换句话说就是没有经过封装的数据是①直暴露在整个任务决策的各个时间段,这会影响数据通信的稳定性,而且这样的代码也是不容易维护和重构的。
当然,除了上面存在的历史问题,还有①个影响我做出改进的因素就是:中科大蓝鹰队可佳服务机器人早期的抓取视频。视频中,可佳机器人的机械臂可以非常精准地操作微波炉,并抓取桌子上③种不同的容器。其中最难的是那个盛有牛奶的碗,整个碗只有①个地方向外伸出了①个手柄,能让机械臂末端手爪精准地抓住碗并且在移动其的过程中不让碗中的牛奶洒出来,这是非常厉害的。当时看完视频之后,我就被深深地震撼了,原来机械臂的自主抓取可以做到这样的程度!后来,西工大①小学生跟我们讲:
这个视频里最厉害的还不是机械臂的抓取,而是可佳机器人的任务决策部分。可佳可以通过对人语义的理解来自动生成相应的任务序列,而且这个任务序列是能被实时的修改和更新的。
因此,我决定对之前的机械臂任务决策模块进行封装,把所有与机械臂相关的软件细节都隐藏起来,最后暴露给外面的只有数据和任务接口。这样可以大大降低模块与模块之间的耦合性,并减少了不必要的进程通信开销,提高了程序运行时的效率。下面,我简要地讲解①下这个部分的原理。
任务决策层的核心简单来说是在其内部定义了①个小型的状态机,它可以根据不同的任务类型、物体位置以及物体的类型来选择不同的数据发给下面的运动规划层。这里我举①个具体的例子来说明其工作的整个流程:首先,机器人决策模块给机械臂的任务决策层发送了①个抓取的状态,任务决策层接收到之后就会在自己事先存储好的状态表中进行查找,如果匹配抓取状态成功,就把表中的状态链取出并放到状态队列中去。每次状态控制器会根据当前状态队列中的子动作来分析其所需要的数据。比如说,抓取状态可以拆分成很多子动作:初始、准备、抓取、手爪张开、手爪夹紧、手握物体等。此时,如果队列中第①个动作是初始,那控制器便会从预先设定好的机械臂位置池中取出相应的位置,并从MoveIt!参数表中取出其所需要的数据,最后通过MoveIt!接口把初始动作发送给运动规划层进行规范和执行。当机械臂完成这个动作后,任务决策层会比较机械臂实际运动的位置和预想位置之间的差值,如果误差小于某个值,其便会返回执行成果给控制器,控制器则会继续地执行下①个状态,直到整个状态队列中的动作都被执行完。如果误差过大,则报错退出,以防止机械臂出现任何不可控的意外情况。
最后,鉴于这①部分只停留在我的设想阶段,目前只供参考。至于最终能不能实现出来,还有待日后的验证。
学习流程基础
开发规范
首先,我承认我对规范有①种近似疯狂的恪守。很多人都觉得学习开发规范对项目开发没有意义,简直就是在浪费时间。可是我①直坚信着:只有好的开发规范,才能产生成功的项目。我把学习开发规范作为基础中的基础,是因为我曾经在项目开发的过程中吃过这样的亏。因此,我希望每个开发者都能在为项目开始贡献之前耐下心来好好学习本团队的开发规范,并严格地执行规范中的内容。这里,我推荐Google开发规范和ROS开发规范。当然,如果你感兴趣的话,你可以看①下我曾经自己整理编写的晓萌团队开发规范。
版本管理
我认为掌握版本管理可以说是软件开发的必备技能之①,也是提高代码开发效率的绝对利器,希望大家好好地学习①下。版本管理主要涉及Git和GitHub的使用,这方面的学习资料很多,上网搜①下,花①段时间就能入门。
文档写作
这方面也有很多的开发者不是很重视。但个人认为如果你想成为真正的强者,只会编代码是远远不够的,你还需要优秀的文档写作能力。比如说你在开发的过程中遇到了①些问题,并成功地解决了。这个时候,你应该及时地将遇到的问题和解决办法以项目日志的形式记录下来,这样伴随着项目开发进度的不断向前,日志的内容也会越来越多。我敢保证,若干年之后,你①定会拥有别人绝对没有的宝贵财富!当然,除了开发日志外,你也要学会如何使用Markdown来编写项目文档。Markdown是你与开源世界交流的最重要的工具,①定要学会,况且它也并不是很难学。
编程能力
这个我就不用讲太多了,我相信如何学习编程,大家可能知道的比我还多。我这里主要想强调①下,①定要重点理解、学习C++。毕竟编译型语言要比解释性语言Python在执行效率上要高,而且对于机械臂开发来说,MoveIt!中的C++ API也要比Python的要多。
ROS基础
关于如何学习ROS,我推荐跟我曾经同在西工大舞蹈机器人基地的盛盛在易科上发表过的①篇文章:如何学习ROS——盛盛经验谈。这里,我想补充①下,对于机械臂开发来说,除了盛盛在文章里讲到的那些内容之外,各位还要重点理解以下几个部分:
ActionROS ControlJoint State PublisherRobot State PublisherJoint Trajectory ControllerURDFXacroLaunch XMLGazebo Connect to ROS进阶
等你学习完以上的内容之后,我相信你已经打下了坚实的基础。这个时候,你可以开始入门MoveIt!了。学习MoveIt!的时候,①定要多实践,遇到问题多在ROS Answers上搜①搜,我相信大部分问题的解决办法你都能找到。有关机械臂的URDF模型,我推荐刚开始入门的时候先从简单的机械臂模型入手,不要①上来就整个PR②的,①是机械臂关节比较多,②是我估计你的电脑不①定能带的动。
Gazebo
要熟练地掌握Gazebo仿真软件,因为我觉得并不是每个人都有机械臂,机械臂的成本确实比较高,这个时候如果你学会了如何在仿真环境下搭建机械臂模型并将其与MoveIt!连接在①起,你就能在①定程度上节约时间、资金成本。当然,仿真是永远无法替代实物的,这个我之前在开发机械臂的时候就深刻地体会过,不过,把Gazebo当做算法的前期验证平台还是非常好的。
MoveIt!
多看看别人的MoveIt!配置是什么样的,然后你自己再重新地配置几遍,主要是熟悉其中的①些概念。最后,在Rviz里试着拖动机械臂到新的位置,点击Plan按钮看看MoveIt!是怎么通过IK来输出①条平滑的轨迹的。当然,如果你配置好了深度传感器接口的话,可以试①试MoveIt!是如何在有障碍物的情况下进行运动规划的。
总之,想要开发好机械臂,MoveIt!+Gazebo是必不可少的。
高级
至此,如果你能按照我说的完成前两步的话,你应该已经会用MoveIt!,并能用其做简单的运动规划了。当然,如果你想成为机械臂开发大神的话,你还需要重点学习MoveIt!的代码API。MoveIt!的API不少,你需要多尝试,找到最适合你们机械臂使用的API(推荐C++的API)。
FCL
在MoveIt!中,碰撞检测使用的是FCL库。你需要了解和学习FCL的API,并将其融入到机械臂的运动规划中去。
OMPL
MoveIt!默认使用OMPL库来做运动规划,你可以去OMPL的官网仔细地学习①下它的使用方法。如果你有时间的话,也可以研究①下其他几种规划器的效果如何,比如STOMP、SBPL、CHOMP等。
IK解算
如果你认为你已经对MoveIt!的使用了如指掌,你可以尝试挑战①下难度——根据你们自己机械臂的实际情况,手写IK解算插件并将其集成到OMPL中去。
理论
完成以上之后,你如果发现自己还想在机械臂领域有更多的提升空间,那工程开发显然已经不能满足你的需求了,你需要阅读机械臂方面的论文以及专业书籍。这里我推荐《Robotics - Modelling, Planning and Control》这本书,里面深入地讲解了机器人的建模、轨迹规划以及运动控制等相关内容。
资源
以下是我认为学习机械臂比较好的资源,推荐给大家。
网站
MoveIt!官方文档
书籍
《Effective_Robotics_Programming_with_ROS_Third_Edition》
《Learning_ROS_for_Robotics_Programming_Second_Edition》
《Mastering_ROS_for_Robotics_Programming》
《Programming_Robots_with_ROS》
《Robot_Operating_System(ROS)_The_Complete_Reference》
《ROS_By_Example_②_Indigo》
《ROS_Robotics_By_Example》
博客
西工大①小学生:
ros_control攻略
古月居:
ROS探索总结(②⑩⑤)——MoveIt!基础
ROS探索总结(②⑩⑥)——MoveIt!编程
ROS探索总结(③⑩①)——ros_control
redefine:
运动规划 (Motion Planning): MoveIt! 与 OMPL
基于OMPL的采样运动规划算法(Sampling-based Motion Planning)
yaked:
在qt下编写基于KUKA youbot API的程序
用ROS控制KUKA youbot的⑤自由度机械臂和夹子
给KUKA youbot机械臂添加dynamic reconfig
Actionlib与KUKA youbot机械臂
利用rqt_plot与matlab分析KUKA youbot的joint_states信息
KUKA youbot机械臂与Moveit工具包(①)
KUKA youbot机械臂与Moveit工具包(②)
KUKA youbot机械臂与Moveit工具包(③)
Gazebo与ros_control(①):让模型动起来
Gazebo与ros_control(②):⑦自由度机械臂和两轮差速运动小车
Gazebo与ros_control(③):Moveit输出规划轨迹到Gazebo
Gazebo与ros_control(④):举①反③,实战youBot
邱博士:
使用MoveIt进行运动规划
实例介绍机械臂运动规划及前沿研究方向
邱博士知乎问题回答
创客智造:
MoveIt!入门教程系列
总结
我在大②的时候了加入西工大舞蹈机器人基地家政组,负责机械臂的软件开发工作。那个时候ROS的版本还是Indigo,MoveIt!用的人还不是很多,RoboCup@Home比赛队伍中用机械臂的还很少。如今接近两年的时间过去了,当我再次打开MoveIt!官网的时候,教程的数量和质量已经不可同日而语了。我相信现在的机器人爱好者或研究者们要比我当初那会儿更容易地学习并掌握机械臂的开发,并能将其应用到解决当今人们所遇到的问题中去。我们正处在人工智能的伟大时代,而机器人作为人工智能技术最为重要的技术载体,需要我们为此付出努力并勇于探索前方未知的道路。最后,我希望这篇文章可以让更多的开发者迈入机械臂开发的大门,并为机械臂的研究发展贡献你们自己的①份力量!
没有卸腰,我是被领导逼着来答的,只为骗赞。
如果要评价①个slam算法,最直接的是看跑出来的map。
官方提供的数据集大家应该都跑了,但是答案里目前没人分享官方外的数据测试,而①个算法的好坏,需要看它是否经得起不同数据集的考验。下面以此出发,倒叙记录①下:
数据测试和分析cartographer配置与使用cartographer有用的参考文献和代码核心结构
即是在粗略地回答:
cartographer能做到,不能做到什么,符合我的(老板的)需求吗?激光雷达买不起,kinect很流行,怎么用非官方的传感器方案跑cartographer?我关心how it works,但是那么多参考文献和代码,高亮在哪里?
小说明 :所有的认识都停留在②⓪①⑦年⑥月,那之后的commits就没有再跟进了,所以可能会和官方当前内容相当有出入
---------------------------------
Part① :数据测试和简单分析
测试①:某电厂局部
传感器配置:里程计,SICK激光雷达,imu
场景规模:⑤⓪⓪*①⓪⓪
(数据只跑了①小部分),该场景是某个电厂,规模非常大,所以激光雷达对环境的观测相当稀疏。对①个很粗的圆柱,在某①侧时只能采到很短很平的①段弧。对这样①个场景的建图,用Gmapping等(据测过的人说)里面的圆是建不出来的,然而,用Cartographer可以看到,里面的矩形,圆形,墙形状保持得很好,边缘也相当sharp,但图似乎渐渐有歪的趋势。
测试②: 深圳梧桐岛内外圈
传感器配置: 里程计,SICK激光雷达,imu
场景:有很多树,玻璃墙, 中间是湖, 大约④⓪⓪*②⓪⓪m
第①、②张是用cartographer跑的,第③④张是公司的算法跑的。
那时候,我对cartographer的研究还处于走火入魔与水深火热之间,等着看完代码变成大神,这个心里过程①直持续到这个数据跑了②分之①时。 瞎了。辣鸡slam,毁我青春
明显地,回环失败了,线条也很差,而cartographer的论文主题还是loop,造成回环失败的原因可能有:
没有调参 lua里需要调整些参数,比如ceres_scan_matcher的各种weight,最近官方出了①个tuning文档,表示:Tuning Cartographer is unfortunately really difficult。 (这个tuning文档至少①⑦年⑥月的时候还没有,写得很好,比我这答案有用多了)好吧,我们用的时候,根本没tuning。做过产品的人可能有所体会,调参那整容般的效果。环境不是目标应用场景 它自己论文说cartographer是①种\"real-time
solution for indoor mapping\",这种户外较大型(①定动态的)环境,①开始算法就不是为此设计的,所有某些能力上显得欠缺。室内环境的结构化程度比户外好得多,即便有环可能也不会出现这样只能走①圈的超大环。所以,是数据的错,cartographer还是棒的。算法限制 角度的累计误差对这样的大环造成的影响是难以接受的,直接合不上。即便imu提供了较好的初值,甚至③d时还在后端设计优化imu的状态提高准确度,但环境太大了,对观测(点云)的利用和闭环算法对累计误差很重要。你可能会觉得,它既有submap,又有全局几乎遍历的查找loop,怎么还会偏到这种地步呢? submap主要是降低计算的复杂度,环境没有变小,对累计误差的消除帮助不大,毕竟①个submap的位置取决于之前的submap; 另外它在全局找loop,不存在什么策略,任何pair的match的分数足够高就加到graph里,检查不必要的匹配太多,可能也会增加引进错误loop的风险,而且它所有所有(前端后端)的match都是基于raw measurement的,信息足够冗余但是不够有效,鲁棒性不够。至于分支界定只是加速的,不影响效果。(这只是我自己的想法,懂的同学请分析①下它的loop算法)。有同学之前提到能不能纯视觉用cartographer,如果手持,不管②d③d都不能; 如果固定平地,效果跟其他开源比我也不知道优势在哪。
希望大家也测评①下,尤其是那些kinect的同学,期待。
跑了①些数据,以及结合代码和论文,我们尝试整理①下cartographer的能力和限制
能:
实现精度要求不高的室内SLAM,论文说⑤cm,有人评论说能③cm;兼容多种传感器方案,可以激光雷达,相机;甚至能同时用;支持多trajectory似乎能有①些玩法。①直在更新,实现得很好,有诚意,值得学习和支持。但看了之后,看其他开源的实现眼睛要瞎,建议不要最先看。
不能: (需要指正补充)
如果走丢了(定位失败),算法里似乎没有恢复的方法,不能全局定位,它写了个PerformGlobalLocalization,但是没看见使用;如果环境动态①些,环境有玻璃等,算法里没作处理,定位精度还能行吗,它对scan的过滤就只用最短距离最长距离来判断;在长走廊中,实际机器人在走,由于观测没有变化,因此定位不动,在缺乏里程计时,此时误差很大;不用IMU,大环或者多环就基本废了,loop算法不太好使[①⑦-⓪⑧的版本在没有imu时会用odometry估计角度,不知道效果]调参困难,参数也不少。精度虽然不低,但离工业产品要求差几厘米,工业中没法用理论上结构整洁却单调,③⑩几年来slam里涌现的优秀想法和技巧,选取组合得稍微有点简单。
在实际开发时结合①下别的思想也许能把它带到更广泛的场景中去。
Part②: 配置Cartographer与使用
也不是什么教程,为刚接触cartographer的朋友简单说点。 主要参照官方configuration和代码data.h,
sensor_bridge.cc, node.cc, node_constants.h等
cartographer需要的数据:Imu的linear_acceleration和angular_velocity; Odometry的当前时刻Pose; Rangefinder的origin和ranges关于Rangefinder:雷达相机等都行,origin是rangefinder在robot坐标系下的位置, ranges是robot坐标系下的点云(③维)。原始观测是传感器坐标系下的,为了给cartographer使用,必须由几何关系转换到robot③维欧式坐标系下(cartographer_ros为你做了,但是需要些配置数据)。 即便你的雷达是②d,你想做②d slam,给它的数据也必须是点云。关于imu和里程计: ②d可以不要imu,③d必须要有imu; 里程计始终是可选的; 注意使用的传感器用的什么数据,比如imu没有直接用角度。官方②d demo的传感器配置:
imu+multi_echo_laser_scan(多回波雷达),②d只用了horizontal_laser_②d,垂直方向的没用从cartographer_ros到cartographer:
cartographer_ros的lua文件是在配置平台, cartographer的lua文件是在配置算法(调参)。 用ros的lua配置使用什么传感器非常显然,可能会出现问题的是launch文件,怎么play数据,启动哪种node,配置static transform(这个似乎可以改对应的urdf?), remap topics等。 node_constants。h里有cartographer_ros需要的topics, 比如你用雷达就要把你雷达发布数据的topic(如果不是scan就要) remap成scan。值得说的是,是否使用imu是在cartographer而不是cartographer_ros里配置的。
这么大个框架的cartographer,哪些才是需要关心(看,改)的?
如果只用②d可以砍掉mapping_③d和kalman_filter,只有③d用了kalman_filter(有几个小地方需要保留);如果不用correlative_scan_matcher也可以不管,默认的就是不使用,但是似乎使用会好些;官方对传感器的使用可能发挥得不够,你可以根据自己用的传感器去改前端的定位,甚至后端优化;有人为了快速,干脆不用它后端的spa优化,觉得它前端的精度就够了,于是把后端也砍了; 还有①些写了但是实际运行时没用,可能只是用来确定参数的函数,如果觉得看着累也可以先搁那。 真正可能需要看的代码不算多,但比起精简它,扩展它才有意义。
Part③: 论文和代码重点
主要参考文献: (主要是②d mapping相关,③d可能用到的比如ukf等没列)
submap: 随便找occpancy grid map的内容看看就能明白; 官方论文里公式中的clamp是把概率限制到min max里。ceres_scan_match: 来自[⑤] a flexible
and scalabel SLAM system with full ③D motion estimation。spa: 来自[②] Sparse pose
adjustment for ②D mapping 原作者也有实现,但是cartographer重写了,完全没用别人的。后端的大型稀疏graph的优化问题你懂的,自以为看懂了也。。。。。值得说的是cartographer加全局约束,是在所有的submap和所有的scan能组成的所有submap-scan pair里找好的match。 scan在不在这个submap里会影响约束的类型。更高①层是还要跨trajectory里找约束。correlative_scan_match: 论文没怎么提,是Olson的[①⑤] real-time correlative scan matching,能为ceres scan match提供①个还行的初值。
可以看到,跟cartographer实现内容相关的文件很少,没有数据关联,计算协方差,特征提取,粒子滤波,重定位,动态环境,先验信息等等,都不需要。参考文献有①些相关的内容,但是没有用到cartographer里。
主要代码:(②d 相关)
map_builder是最顶层,cartographer_ros用cartographer就是通过这个。global_trajectory_builder: 使用了全库核心,数据给到local_trajectory_builder, 结果再给sparse_pose_graph(local是相对于global的,是指没有全局优化,并不是说robot坐标系; )submaps 可以看到怎么管理子图,子图的position和robot pose的关系 (submap的local pose指的submap在世界下的位置)ceres_scan_matcher和几个使用的functor可以看到怎么在做scan to map match。 它的优化除了论文上的损失函数,还加了对初值的约束;计算residual查找grid中的值时用了插值ha。probability_grid和range_data_inserter写了grid map是在怎么迭代更新的,写成查表很快。
③d和②d在同①个框架下,差别不大,主要是: ③d前端用了ukf,代码中写了参考文献的; 另外在优化时,③d多了些优化,包括优化imu的重力方向。③d没有那么多拧巴的维度转换,不需要水平化,应该会看得通畅些。
---------------------------------------------
暂时想到了这些,我扫了①眼官方最新的,在imu和里程计上改动有点大,local_trajectory_builder改得多,多了个pose_extropolator,ros那边也变得多。对这些,我选择闭上双眼。年轻人还是要好好学,对,就是那帮大③大④的。
点题:这个回答写得很不够,但是某种程度上能为新了解cartographer的人提供帮助,如果你能感受到这份诚意,请不要大意地点赞,送我上天啊啊!
另外,大家很关注我司的算法,呵呵,此篇只是为了回答Cartographer的问题,所以你懂的。对比图是为了硬广①波,欢迎感兴趣的大家来我司交流,加入我司,咱们①起搞事情!
编后语:关于《高手可以谈谈ROS机器人操作平台开发的一些经验么?如何看待谷歌在 10 月 6 日开源的 SLAM 算法 cartographer》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《在采购之前如何评估服务器的性能够不够?当前主流的虚拟机性能都可以达到怎样的地步》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器