ROS卡车手推车。 第7部分。机器人的本地化:映射,AMCL,房间地图上的参考点

系列文章:
8.我们从电话控制ROS控制,GPS节点
7.机器人本地化:映射,AMCL,房间地图上的参考点
6.带轮编码器的里程表,房间地图,激光雷达
5.我们在rviz和凉亭中工作:xacro,新传感器。
4.使用rviz和gazebo编辑器创建机器人仿真。
3.加速,更换相机,固定步态
2.软件
1.铁

上一次,在安装了廉价激光雷达RPlidar-A1之后,我们设法构建了一个带有里程表的房间地图。 但是,尽管拥有卡片并通过光学传感器调整了里程表,但机器人在环境中仍然感到不安全。
相反,他根本看不到她。 而且他沿着完成的地图远行,障碍物不适合他。 这既令人愉悦又令人痛苦。 一方面,您不必担心障碍物和旅行,无论您想去哪里,另一方面,也不太可能去另一个房间或厨房。 因此,我们将讨论使用ROS提供的算法以及我们的绅士的激光雷达和编码器在太空中对机器人的定位。 但是在我们直接进行本地化之前,让我们谈谈另一个ROS程序包,该程序包还允许您构建房间的2D地图,有时它对他来说比上一篇文章中的ROS程序包更好。 了解gmapping。

RM氏族作图


我们将不会是原创,我们将使用有关该主题的Habr已有文章的发展,但是我们将扩展,更新和加深其中的信息。 这篇文章称为使用Laser_scan_matcher在不使用测距法的情况下在ROS中构建地图和定位移动机器人

部分操作(高负载应用程序-rviz)将在计算机(机器人外部)上执行,其余操作(运动驱动程序,激光雷达发射节点)将在机器人上执行。

首先,根据上述文章的情况(本文为靛蓝)在计算机上安装用于ROS动力学的laser_scan_matcher:

sudo apt-get install ros-kinetic-laser-scan-matcher 

现在运行。

用机器人在激光雷达上点头:

 roslaunch rplidar_ros rplidar.launch 

在计算机上:

 roslaunch laser_scan_matcher demo.launch 

*无需运行roscore,因为每次加载机器人时,主节点都会启动。

在起始rviz中,将看到房间的轮廓以及其中的垃圾:

图片

我们将需要laser_scan_matcher与gmapping ROS软件包一起使用。 无需自身安装gmapping,它已经作为ROS Kinetic的一部分位于虚拟机上。 检查系统中的软件包:



现在,让我们在计算机上(而不是在机械手上)使用gmapping创建启动文件,如上面的文章所示:

 roscd roscd rosbots_description/launch nano my_gmapping_launch.launch     

代号
 <?xml version="1.0"?> <launch> <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.0 0.0 0.0 0.0 0.0 0.0 /base_link /laser 40" /> <node pkg="laser_scan_matcher" type="laser_scan_matcher_node" name="laser_scan_matcher_node" output="screen"> <param name="fixed_frame" value = "odom"/> <param name="use_odom" value="true"/> <param name="publish_odom" value = "true"/> <param name="use_alpha_beta" value="true"/> <param name="max_iterations" value="10"/> </node> <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen"> <param name="map_udpate_interval" value="1.0"/> <param name="delta" value="0.02"/> </node> </launch> 


从代码中可以看到,作者启动了3个节点:tf,laser_scan_matcher和gmapping。

让我们再次在机器人上运行激光雷达:

 roslaunch rplidar_ros rplidar.launch 

在计算机上,新烘焙的启动文件和rviz编辑器:

 roslaunch rosbots_description my_gmapping_launch.launch 

 rosrun rviz rviz 

在rviz中,我们得到的图片类似于在上一篇有关“机器人手推车”的文章中构建地图时获得的图片。 只有这次gmapping包有效。

我必须承认,它并不会很糟糕。 如果当激光雷达绕其轴旋转时hector_slam在地图上留下了许多工件,则这次几乎没有工件:



在房间中旅行后,还会保存构造的地图:
rosrun map_server map_saver -f map-1 ,其中map-1是要保存的地图的名称。

使用amcl进行本地化


用于确定机器人在地图上的位置的算法称为AMCL。 AMCL使用多粒子过滤器来跟踪机器人在地图上的位置。 在我们的机器人中,我们使用ROS包(http://wiki.ros.org/amcl)实施AMCL。

为我们的机器人运行AMCL。

为此,在项目文件夹中的计算机上,创建另一个启动文件。

叫他

amcl-2.launch
 <launch> <param name="/use_sim_time" value="false"/> <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.0 0.0 0.0 0.0 0.0 0.0 /base_link /laser 40" /> <node pkg="laser_scan_matcher" type="laser_scan_matcher_node" name="laser_scan_matcher_node" output="screen"> <param name="fixed_frame" value = "odom"/> <param name="use_alpha_beta" value="true"/> <param name="max_iterations" value="10"/> </node> <node name="map_server" pkg="map_server" type="map_server" args="/home/pi/catkin_ws/src/rosbots_description/maps/map-3.yaml"/> <node pkg="amcl" type="amcl" name="amcl" output="screen" > <!-- Publish scans from best pose at a max of 10 Hz --> <param name="odom_model_type" value="diff"/> <param name="odom_alpha5" value="0.1"/> <param name="transform_tolerance" value="0.2" /> <param name="gui_publish_rate" value="10.0"/> <param name="laser_max_beams" value="30"/> <param name="min_particles" value="500"/> <param name="max_particles" value="5000"/> <param name="kld_err" value="0.05"/> <param name="kld_z" value="0.99"/> <param name="odom_alpha1" value="0.2"/> <param name="odom_alpha2" value="0.2"/> <!-- laser, translation std dev, m --> <param name="laser_min_range" value="-1"/> <param name="laser_max_range" value="-1"/> <param name="odom_alpha3" value="0.8"/> <param name="odom_alpha4" value="0.2"/> <param name="laser_z_hit" value="0.5"/> <param name="laser_z_short" value="0.05"/> <param name="laser_z_max" value="0.05"/> <param name="laser_z_rand" value="0.5"/> <param name="laser_sigma_hit" value="0.2"/> <param name="laser_lambda_short" value="0.1"/> <param name="laser_lambda_short" value="0.1"/> <param name="laser_model_type" value="likelihood_field"/> <!-- <param name="laser_model_type" value="beam"/> --> <param name="laser_likelihood_max_dist" value="2.0"/> <param name="update_min_d" value="0.2"/> <param name="update_min_a" value="0.5"/> <param name="odom_frame_id" value="odom"/> <param name="base_frame_id" type="str" value="base_link" /> <param name="global_frame_id" type="str" value="map" /> <param name="resample_interval" value="1"/> <param name="transform_tolerance" value="0.1"/> <param name="recovery_alpha_slow" value="0.0"/> <param name="recovery_alpha_fast" value="0.0"/> <param name="use_map_topic" value="true" /> <param name="first_map_only" value="true" /> </node> </launch> 


该代码与已经提到的文章完全相同,除了:
-排除了启动hokuyo激光雷达的节点(在机器人上运行)
-房间地图的路径和名称不同(map-3.yaml)
该代码运行4个节点:
-tf
-map_server
-laser_scan_matcher
-amcl
amcl节点使用map_server发布的地图进行后续的机器人本地化。

运行启动文件并查看结果。

但是对于机器人:

 roslaunch rplidar_ros rplidar.launch 

在计算机上:
第一终端: roslaunch rosbots_description amcl-2.launch
第二终端: roslaunch rosbots_description rviz.launch

rviz启动后,此编辑器中的下一步将是以下步骤:
-将显示添加到rviz:
•LaserScan
•地图
•PoseArray


-在初始阶段将机器人本地化,因为启动amcl时不知道机器人在哪里启动,在哪里。 需要“初始初始化”。
为此,在rviz中,您需要选择“ 2D姿势估计”,并在显示机器人的窗口中使用绿色箭头指示其位置:



必须通过选择rviz中的“地图”框架来完成此操作:



在终端中,我们获得机器人的坐标(姿势):

 [ INFO] [1572374324.454855505]: Setting pose (1572374324.454806): -0.014 -0.012 0.655 

您可以反复使用地图上的绿色箭头在地图上设置机器人的位置。
希望地图上来自激光雷达的数据(红色边框)与房间墙壁的实际位置一致或接近:



在rviz可视化窗口中,我们获得了机器人*周围的特征红色箭头:



*作为机器人,我们有一个明确的轴(整个绘制的rviz模型仍处于隐藏状态)。
**如果未出现箭头,则可以尝试删除并重新检查添加到rviz的PoseArray显示。

尽管我们直接在地图上指示了机器人所处的位置,但系统仍然假定它可以位于绘制红色箭头的那些地方。 这是机器人在地图上的可能位置。 大量箭头及其在地图上的分散指示系统仍然不知道机器人的确切位置。 但是,在射手较密集的地方,机器人的可能性更大。

为了使系统更准确地准确了解机器人的位置,您需要在带有正在运行的节点的地图上行驶,这些节点确定了机器人的位置。 我们有以下几种设置:激光雷达和编码器。
但是,我们仅使用发射的激光雷达在地图上旅行,同时找出是否有可能仅借助其(激光雷达)帮助才能可靠地定位机器人。
--
在地图上骑机器人
在机器人上:

 rosrun rosbots_driver part2_cmr.py 

在计算机上:

 rosrun teleop_twist_keyboard teleop_twist_keyboard.py /cmd_vel:=/part2_cmr/cmd_vel 


在旅途中,amcl将开始阅读主题/扫描,/地图/ tf,并在主题/ amcl_pose和/ particlecloud中发布机器人的位置。

在旅行时,您会发现箭头的数量减少了,并且在与机器人实际位置的某个点上,箭头越来越凝聚:


图片显示了模型的运行方式(以连接树的形式)。 而且还可以看出,激光雷达无法准确地应付房间内边界不明确的局限性。

amcl节点代码中的其他参数是什么意思?


按照惯例,它们分为基本(常规),过滤器参数(过滤器),激光参数(激光雷达)(激光参数)。

关键参数:
  • odom_model_type(默认值:“ diff”):确定要使用的里程表模型。 我们有差异,这意味着差异。 可以更改为“全向”,“差异校正”或“全向校正”。
  • odom_frame_id(默认值:“ odom”):定义与里程表关联的框架(阅读主题)。 它通常在odom主题中发布。
  • base_frame_id(默认值:“ base_link”):机械手底座的框架。
  • global_frame_id(默认值:“ map”):地图的框架,通常地图服务器将其发布到主题地图中
  • use_map_topic(默认值:false):确定是通过主题还是通过调用服务来加载地图(我们记住,除了ROS中的主题之外,还有服务和操作。


过滤参数
这些选项使您可以自定义粒子过滤器的工作方式。

  • min_particles(默认值:100):设置过滤器的最小粒子数。 我们有500。
  • max_particles(默认值:5000):设置过滤器的最大粒子数。
  • kld_err(默认值:0.01):设置真实分布与计算的分布之间的最大允许误差。 我们有0.05
  • update_min_d(默认值:0.2):设置机器人更新过滤器必须行进的线性距离(以米为单位)。
  • update_min_a(默认值:pi / 6.0):设置机器人为了更新过滤器而必须移动的角距离(以弧度为单位)。 我们有0.5
  • resample_interval(默认值:2):设置重新获取之前所需的过滤器更新数。 我们有1。
  • transform_tolerance(默认值:0.1):已发布的转换应标上日期的时间(以秒为单位),以指示此转换将来有效。
  • gui_publish_rate(默认值:-1.0):发布扫描和路径以进行可视化的最大速度(以Hz为单位)。 如果该值为-1.0,则禁用此功能。 我们有10个


激光(激光)参数(激光参数)
这些参数使您可以配置amcl与激光雷达激光器的交互方式。

  • laser_min_range(默认值:-1.0):要考虑的最小扫描范围; -1.0将使用激光报告中指定的最小范围。
  • laser_max_range(默认值:-1.0):要考虑的最大扫描范围; -1.0将使用最大激光范围。
  • laser_max_beams(默认值:30):更新滤镜时,每次扫描将使用多少个均匀分布的光束。
  • laser_z_hit(默认值:0.95):机械手模型的z_hit组件的权重。
  • laser_z_short(默认值:0.1):机械手模型的z_short组件的权重。
  • laser_z_max(默认值:0.05):机械手模型的z_max组件的权重。
  • laser_z_rand(默认值:0.05):机械手模型的z_rand组件的权重。


让我们看看min_particles和max_particles参数的影响。 如果减小它们的值,则在启动启动文件时,可视化编辑器中的粒子数将明显减少。

所有参数都承载语义负载,但是很难分析在文章中更改每个参数的效果。

房间地图上的参考点


这个名称很吸引人,并且暗示了在此特定时刻机器人在地图上的位置。

他们是干什么的? 为了了解机器人是从房间中的A点到达厨房中的B点。

机器人的位置(姿势)数据可以通过amcl工作节点(在上一篇文章中开始)获得。

并查看主题/ amcl_pose:

 rostopic echo -n1 /amcl_pose 

*键n1-用于“固定”主题中的消息流。



让我们创建一个服务,当该服务被调用时,它将放弃机器人的位置(坐标),以便每次它都不关注主题时。

1.创建一个新的ros包。

 cd catkin_ws/src catkin_create_pkg get_pose rospy cd get_pose/src 

2.在文件夹中,创建文件:

get_pose_service.py
 #! /usr/bin/env python import rospy from std_srvs.srv import Empty, EmptyResponse # Import the service message python classes generated from Empty.srv. from geometry_msgs.msg import PoseWithCovarianceStamped, Pose robot_pose = Pose() def service_callback(request): print "Robot Pose:" print robot_pose return EmptyResponse() # the service Response class, in this case EmptyResponse def sub_callback(msg): global robot_pose robot_pose = msg.pose.pose rospy.init_node('service_server') my_service = rospy.Service('/get_pose_service', Empty , service_callback) # create the Service called get_pose_service with the defined callback sub_pose = rospy.Subscriber('/amcl_pose', PoseWithCovarianceStamped, sub_callback) rospy.spin() # mantain the service open. 


*不要忘记使其可执行chmod + x get_pose_service.py
3.让我们使用节点代码为文件创建启动:

 cd .. mkdir launch && cd launch 

纳米

get_pose_service.launch
 <launch> <node pkg="get_pose" type="get_pose_service.py" name="service_server" output="screen"> </node> </launch> 


4.别忘了重建柳絮:

 cd catkin_ws catkin_make 

现在,我们将重新启动所有内容,包括新的启动文件。

但是对于机器人:

 roslaunch rplidar_ros rplidar.launch 

在计算机上:

 1- : roslaunch rosbots_description amcl-2.launch 2- : roslaunch rosbots_description rviz.launch 3- : roslaunch get_pose get_pose_service.launch 

我们转向新服务,该服务应为我们提供机器人在地图上的当前位置(我们将其称为ROS服务):

 rosservice call /get_pose_service 

在运行启动get_pose的终端中,我们将获取机器人在地图上的坐标:



可能的错误。

[rviz.launch]既不是软件包[rosbots_description]中的启动文件,也不是[rosbots_description]作为启动文件名
解决方案:

 cd catkin_ws source devel/setup.bash 

Source: https://habr.com/ru/post/zh-CN472984/


All Articles