翟帅帅 958ebd5926 | ||
---|---|---|
.. | ||
Image | ||
README.md |
README.md
一.ROS
1.栅格地图格式
机器人导航所使用的地图数据,是ROS系统中的map_server节点,在话题/map中发布的数据。
消息类型是nav_msgs消息包的OccupancyGrid(占据栅格),小格子+数字,数字表示是否有障碍物。
栅格地图:
在地面画上栅格,然后根据栅格中是否有障碍物给栅格填色。然后把障碍物移走,剩下的就是栅格地图。
栅格划分可大可小,栅格越小,区域划分就越精细,越接近障碍物轮廓。理论上栅格足够小,栅格就可以无限趋近于障碍物轮廓。但是栅格变小,就会使栅格的数量变多,机器人的计算量就会变大。所以一般会给栅格设置一个合适的尺寸。
栅格尺寸:单个栅格的边长,体现了地图的精细程度,用来表示栅格地图的分辨率。ros中分辨率默认0.05m。
栅格数组+行列数信息,就可以表述一个栅格地图。这个就是OccupancyGrid消息包中的数据内容。
2.c++节点发布地图
地图样式:
实现步骤:
首先创建软件包:
完整代码:
#include <ros/ros.h>
#include <nav_msgs/OccupancyGrid.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "map_pub_node");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<nav_msgs::OccupancyGrid>("/map", 10);
ros::Rate r(1);
//构建地图消息包,并对其进行赋值
while (ros::ok())
{
//创建地图消息包
nav_msgs::OccupancyGrid msg;
//header
//坐标系设置为map
msg.header.frame_id = "map";
//时间戳设置为当前时间
msg.header.stamp = ros::Time::now();
//描述信息 info
//原点位置
msg.info.origin.position.x = 0;
msg.info.origin.position.y = 0;
msg.info.resolution = 1.0; //分辨率
msg.info.width = 4; //地图长度
msg.info.height = 2; //地图高度
//地图数据赋值 data
msg.data.resize(4*2); //地图大小
msg.data[0] = 100;
msg.data[1] = 100;
msg.data[2] = 0;
msg.data[3] = -1;
//发送赋值的消息包
pub.publish(msg);
r.sleep();
}
return 0;
}
地图赋值,注意起始点位置为0开始:
修改编译规则:
add_executable(map_pub_node src/map_pub_node.cpp)
target_link_libraries(map_pub_node
${catkin_LIBRARIES}
)
catkin_make编译,没有报错即成功编译。
然后启动roscore,另一个终端启动刚刚的节点:
再启动rviz,订阅/map:
发现可以正常显示地图。
3.Hector_Mapping
wiki:hector_mapping - ROS Wiki
Hector_Mapping是开源的一个软件包,可以在只有激光雷达的情况下获取实际的地图。在上面的网站中,有一个样例视频。
流程:
运行仿真环境:roslaunch wpr_simulation wpb_stage_slam.launch
打开rviz,添加机器人、雷达、地图,订阅相应节点。
打开wps_robot_steering控制机器人,直到完全扫描出地图:
实测:运行之前写的避障算法也可以成功躲开障碍物,完成构图。
编译成功后,尝试运行:roslaunch slam_pkg hector.launch
4.里程计
在机器人建图的过程中,如果有一段长直的路,周围的参照物始终不变,那么激光雷达会认为参照物不表,机器人没有动,建图就不会再继续进行。
对于机器人来说,激光雷达虽然没有识别特征,但是轮子还在运动。此时里程计(odometry)就可以计算位移信息,位移=圈数*周长。里程计不是硬件设备,而是软件算法,在机器人的驱动节点中运行,根据电机转动数据计算位移信息,并将位移信息以TF消息包的形式发送到TF话题中。但是这个只是数值计算,轮子可能在真实情况出现变化,从而产生误差,此时就应该通过激光雷达等方式继续吻合障碍物的特征。
Gmapping:
里程计输出的是odom到base_footprint的TF(计算的机器人位移),已经和机器人的底盘投影中心连接上,无法再从base_footprint到机器人地盘再插入新的TF。如下图:
因此,slam一般会迁就里程计。在计算的过程中,slam节点最终要输出的是map到base_footprint,所以slam移动了绿色部分的TF到odom节点之前,也就是右边框出的部分。
这样map到odom的TF和里程计的TF一连起来,就形成了map到base_footprint的TF:
这个就是Gmapping的核心算法。
在hector中,直接将雷达点云贴合障碍物轮廓得出的机器人位移作为最终结果。在TF树中是下面这一段:
在gmapping中,机器人的位移主要由里程计推算,激光点阵只适用于修正里程计的误差。而在hector中,只使用雷达点云和障碍物配准的方法进行定位,但是在输出时,也会输出一段map到odom的TF,用于修正里程计不断增长的TF,使base_footprint和scanmatcher_frame保持一致,但是实际上是为了保持一致而保持一致。
可以使用指令roslaunch wpr_simulation wpb_corridor_gmapping.launch
roslaunch wpr_simulation wpb_corridor_hector.launch来进行对比。
里程计的思想就是利用不同形式的定位方法,减少单一SLAM算法的缺陷,减少误差或增加稳定性。
5.Gmapping进行SLAM建图
gmapping软件包:
可以看到gmapping订阅的话题只有两个:
1.tf:坐标系转换关系,有两个。
①雷达坐标系到底盘坐标系的base_link,但是雷达坐标系没有规定具体名称,需要跟雷达数据包的header里的frame_id保持一致。
②里程计输出的TF。
2.scan:激光雷达的数据话题。
gmapping输出的话题有3个:
其中,第三个是机器人定位置信度,值越大,错误的可能性越大。
运行gmapping的需求列表:
首先,运行仿真环境:roslaunch wpr_simulation wpb_stage_robocup.launch
然后运行gmapping软件包的slam_gmapping节点:rosrun gmapping slam_gmapping
然后启动rviz,添加机器人模型、雷达、地图,
之后使用键盘控制机器人,使用gmapping算法建图。rosrun wpr_simulation keyboard_vel_ctrl。
二.LD14的配置与使用
把激光雷达LD14按照文档接线,使用测试软件检验,发现雷达可以正常使用。
使用LD14在小车上进行cartographer建图。用键盘操控小车在办公室运动,然后得到办公室的地图:
为了清楚显示建图结果,只保留了TF坐标系和路径,以及地图和激光雷达点阵。可以看到在室内可以正常完成建图操作,部分没有显示的边缘是因为玻璃透光,导致距离过远没有办法接收到反射回来的激光。