Kinect ROS Gmapping 2D地图
在ROS下手持kinect构建2D地图(--由于只有一个kinect,没有可移动的底盘或者小车,于是就手持kinect --).
环境及设备为: linux14.04, ROS-indigo.kinect一代.
主要内容:
(一) 准备工作:搭建熟悉ROS系统,
(二) 安装kinect驱动,将深度图转为伪激光图(安装depthimage_to_laserscan包.)
(三) 熟悉理解ROS下构建2d地图原理
(四)代码实现
-------------------------------------------------------------
(一) 准备工作:搭建熟悉ROS系统,
1 熟悉ROS操作系统. 首先练习了两遍wiki的20偏开始文档.了解了工作间的创建,package的创建,node,topic,launch文件,msg,发布和订阅.然后,又下载了一本ROS by example的电子书,跟着做了前七章的内容,对ROS系统更加熟悉. 后面在群里发现一本更适合新手的书:<<机器人操作系统(ROS)浅析 [美] Jason M. O'Kane 著 肖军浩 译>>,内容相当于是对wiki的20篇开始文档的详解,特别不错.
(二) 安装kinect驱动,将深度图转为伪激光图
2.1 在ros indigo 中安装kinect一代的驱动,当时也折腾了两天,主要是找的博客不太合适....最后还是请求外援才搞定的..后来发现好像也不用那么麻烦.当时主要按照这个博客中的步骤安装的:http://blog.csdn.NET/zqxf123456789/article/details/52015850
2.2安装depthimage_to_laserscan包. 源码编译,注意版本....
$.git clone --branch indigo-devel https://github.com/ros-perception/depthimage_to_laserscan
$catkin_make
$source devel/setup.bash
$rospack profile
启动命令
$roslaunch openni_launch openni.launch
$rosrun depthimage_to_laserscan depthimage_to_laserscan image:=/camera/depth/image_raw
$rviz
在rviz中Fixed Frame选择camera_depth_optical_frame,Add选择By topic,选择LaserScan,在LaserScan中的Color Transformer中选择AxisColor。
会看到距离近的物体的点是红色,距离远的是紫色。
(三) 熟悉理解ROS下构建2d地图原理
转自知乎大神的回答:链接:https://www.zhihu.com/question/37143050/answer/103899813 ros中常用的2d slam算法主要有gmapping和hector_slam,其中hector_slam是个性能非常好的算法,但是作者在论文中说的很明白,hector_slam通过最小二乘法匹配扫描点,且依赖高精度的激光雷达数据,但是不需要里程计。因此扫描角很小且噪声较大的kinect是不行的,我试过,匹配的时候会陷入局部点,地图非常混乱gmapping是一个比较早的算法,核心思想是粒子滤波并且需要里程计,但并不要求很高性能的传感器,初学者一般都是先来玩这个,不过请注意一点,gmapping只是mapping,定位还需要amcl这个蒙特卡洛算法包配合使用,最后才能接入navigation stack..
gmapping的wiki这样写道
因此,gmapping需要的里程计odom便是通过我们自己发布tf树的形式告诉gmapping,而我们该如何获得这个里程计,这就需要我们自己完成这一部分了,通常做法是在移动平台上安装电机编码器与电子罗盘,在移动平台上的嵌入式
因此,gmapping需要的里程计odom便是通过我们自己发布tf树的形式告诉gmapping,而我们该如何获得这个里程计,这就需要我们自己完成这一部分了,通常做法是在移动平台上安装电机编码器与电子罗盘,在移动平台上的嵌入式 单片机(此处与ros无关)内完成里程计的制作与pid调试,然后,再用树莓派连接单片机串口,单片机将里程计与航向角发给树莓派,树莓派上需要自己写一个nod.
总结如下:
1.单片机与树莓派之前完成数据与控制通信
2.树莓派上写出一个发布tf的node
对没错,如果只是gmapping那么就只需要做这两点!!!
(四)代码实现.
主要是根据 古月居的博客 :http://www.guyuehome.com/column/ros-explore ----ros探索总结系列 (十六)到(二十二) .的博客.
最后,写了自己的myodom节点模拟机器人运动,提供gmapping需要的base_link和odom的关系,写了tf_broadcaster节点,发布gmapping需要的tf关系.详细代码如下:
4.1在catkin_ws中创建myodom包,添加 myodom.cpp文件,修改CMakiists.txt,修改package.xml.
myodom.cpp文件为:
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>
int main(int argc, char** argv)
{
ros::init(argc, argv, "odometry_publisher");
ros::NodeHandle n;
ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
tf::TransformBroadcaster odom_broadcaster;
double x = 0.0;
double y = 0.0;
double th = 0.0;
double vx = 0.01;
double vy = -0.01;
double vth = 0.01;
ros::Time current_time, last_time;
current_time = ros::Time::now();
last_time = ros::Time::now();
ros::Rate r(1.0);
while(n.ok())
{
ros::spinOnce(); // check for incoming messages
current_time = ros::Time::now();
//compute odometry in a typical way given the velocities of the robot
double dt = (current_time - last_time).toSec();
double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
double delta_th = vth * dt;
x += delta_x;
y += delta_y;
th += delta_th;
//since all odometry is 6DOF we'll need a quaternion created from yaw
geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
//first, we'll publish the transform over tf
geometry_msgs::TransformStamped odom_trans;
odom_trans.header.stamp = current_time;
odom_trans.header.frame_id = "odom";
odom_trans.child_frame_id = "base_link";
odom_trans.transform.translation.x = x;
odom_trans.transform.translation.y = y;
odom_trans.transform.translation.z = 0.0;
odom_trans.transform.rotation = odom_quat;
//send the transform
odom_broadcaster.sendTransform(odom_trans);
//next, we'll publish the odometry message over ROS
nav_msgs::Odometry odom;
odom.header.stamp = current_time;
odom.header.frame_id = "odom";
//set the position
odom.pose.pose.position.x = x;
odom.pose.pose.position.y = y;
odom.pose.pose.position.z = 0.0;
odom.pose.pose.orientation = odom_quat;
//set the velocity
odom.child_frame_id = "base_link";
odom.twist.twist.linear.x = vx;
odom.twist.twist.linear.y = vy;
odom.twist.twist.angular.z = vth;
//publish the message
odom_pub.publish(odom);
last_time = current_time;
r.sleep();
}
}
CmakeList.txt为:
cmake_minimum_required(VERSION 2.8.3)
project(myodom)
find_package(catkin REQUIRED COMPONENTS nav_msgs roscpp tf)
catkin_package( )
include_directories( ${catkin_INCLUDE_DIRS})
add_executable(myodom src/myodom.cpp)
target_link_libraries(myodom ${catkin_LIBRARIES})
package.xml文件内容为:
<?xml version="1.0"?>
<package>
<name>myodom</name>
<version>0.0.0</version>
<description>The myodom package</description>
<maintainer email="zhao@todo.todo">zhao</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>nav_msgs</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>tf</build_depend>
<run_depend>nav_msgs</run_depend>
<run_depend>roscpp</run_depend>
<run_depend>tf</run_depend>
<export>
</export>
</package>
----最后catkin_make 得到myodom可运行节点.------
4.2 同样创建settf包,添加tf_broadcaster.cpp .修改相应的CMakeList.txt package.xml.
----tf_broadcaster.cpp文件为:---------(注意修改古月君博客中的base_laser,改为camera_link.有试过改成camera_depth_optical_frame,运行不成功)
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
int main(int argc, char** argv)
{
ros::init(argc, argv, "robot_tf_publisher");
ros::NodeHandle n;
ros::Rate r(100);
tf::TransformBroadcaster broadcaster;
while(n.ok())
{
broadcaster.sendTransform(tf::StampedTransform(tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0.1, 0.0, 0.2)),ros::Time::now(),"base_link", "camera_link"));
r.sleep();
}
}
------------同样catkin_make得到可运行节点tf_broadcaster.
4.3 最后运行一系列的节点:
$roscore
$rosrun myodom myodom
$rosrun settf tf_broadcaster
$roslaunch opnni_launch openni.launch
$rosrun depthimage_to_laserscan depthimage_to_laserscan image:=/camera/depth/image_raw
$rosrun gmapping slam_gmapping scan:=scan
$rviz
4.4 最后效果图:
更多推荐
所有评论(0)