深蓝学院激光slam学习——第二章(里程计标定)习题_白色小靴的博客-程序员宅基地

技术标签: ROS学习  slam学习  

第二章 里程计运动模型及标定

作业要求


  1. 本次的作业为用直接线性方法来对机器人的里程计进行校正。
  2. 给出的文件中包含有本次作业使用的bag数据,路径为odom_ws/bag/odom.bag。
  3. 本次的作业中,需要实现三个函数,分别为:
  4. Main.cpp,第340行中的cal_delta_distance()函数,该函数的功能为给定两个里程计位姿,计算这两个位姿之间的位姿差。
  5. Odom_Calib.cpp,第23行Add_Data()函数,该函数的功能为构建超定方程组Ax=b,具体参考PPT。
  6. Odom_Calib.cpp,第44行 Solve()函数,该函数的功能为对2中构建的超定方程组进行求解。

本次程序的运行过程为:
7. 实现上述的三个函数,并且进行编译。
8. 在odom_ws下,进行source:source devel/setup.bash
9. 运行launch文件:roslaunch calib_odom odomCalib.launch。执行本条指令的时候,必须保证没有任何ros节点在运行,roscore也要关闭。
10. 在3正常的情况下,运行rviz,fix_frame选择为odom_frame。在Add选项卡中增加三条Path消息。一条订阅的topic为:odom_path_pub_;一条订阅的topic为:scan_path_pub_;最后一条为:calib_path_pub_。分别选择不同的颜色。
11. 进入到odom_ws/bag目录下,运行指令:rosbag play –clock odom.bag。
12. 如果一切正常,则能看到运行矫正程序的终端会打印数据,并且rviz中可以看到两条路径。当打印的数据到达一个的数量之后,则可以开始矫正。
13. 矫正的命令为,在calib_flag的topic下发布一个数据:rostopic pub /calib_flag std_msgs/Empty 。
14. 程序矫正完毕会输出对应的矫正矩阵,并且会在rviz中显示出第三条路径,即calib_path。可以观察里程计路径odom_path和矫正路径_calib_path区别来判断此次矫正的效果。
15.


注意事项

(1)
建议自己新建一个工作空间,然后初始化,比如这里我就新建了一个工作空间lidar_space。然后在~/.bashrc中加入

source /home/mjy/dev/lidar_space/devel/setup.bash

建后将功能包calib_odom直接拷贝到此工作空间src之下。

(2)
由于里程代码是跑在indigo上面的,但是我的是ros-kinetic,因此需要改一个地方:
/home/mjy/dev/lidar_space/src/calib_odom/CMakeLists.txt
文件中搜索到indigo的地方,均换为kinetic。

# 第126行
 /opt/ros/kinetic/include/csm
 # 第150行
/opt/ros/kinetic/lib/libcsm.so

如果不修改,则编译的时候会报错:No rule to make target '/opt/ros/indigo/lib/libcsm.so'

(3)
pcl包是依赖Eigen的,而我是新装的eigen,路径在usr/local/include之下,因此pcl是找不到eigen的。
当然如果你是默认eigen,则无须理会。

所以,我这种特殊情况要修改pcl的源代码:

cd /opt/ros/kinetic/share/pcl_conversions/cmake
sudo gedit pcl_conversionsConfig.cmake 
cd /opt/ros/kinetic/share/pcl_ros/cmake
sudo gedit pcl_rosConfig.cmake 

将上述两个文件中的eigen搜寻路径改为自己的。


答案

答案分享给大家:

cal_delta_distance()函数

Eigen::Vector3d  cal_delta_distance(Eigen::Vector3d odom_pose)
{

    static Eigen::Vector3d now_pos,last_pos;
    Eigen::Vector3d d_pos;  //return value
    now_pos = odom_pose;

    //TODO:
    // -------------------------------------------------------------------------------------------------
    // d_pos = last_pos.inverse() * now_pos;
    // d_pos = now_pos - last_pos;是不对的
    d_pos = now_pos - last_pos;
    Eigen::AngleAxisd temp(last_pos(2),Eigen::Vector3d(0,0,1));
    Eigen::Matrix3d trans=temp.matrix().inverse();
    d_pos=trans*d_pos;

    //end of TODO:


    last_pos = now_pos;

    return d_pos;
}


一开始以为要求逆运算,但实际上这是个二维平面的运动,所以之间位姿相减就可以
在这里插入图片描述

2020.7.24更正

十分感谢评论区chyou510的更正!
直接相减求位姿差是在世界坐标系中的结果,而激光雷达的scan-matching的位姿差需要以上一时刻的位姿作为参考系,因此需要将直接相减的结果做一次旋转。这个是我一开始没有考虑周全。

Add_Data()函数


bool OdomCalib::Add_Data(Eigen::Vector3d Odom,Eigen::Vector3d scan)
{

    if(now_len<INT_MAX)
    // if(now_len<data_len)
    {
        //TODO: 构建超定方程组
        Eigen::Matrix<double,3,9> temp_A;
        Eigen::Vector3d temp_b;
        temp_A << Odom(0), Odom(1),Odom(2),0,0,0,0,0,0,
            0,0,0,Odom(0), Odom(1),Odom(2),0,0,0,
            0,0,0,0,0,0,Odom(0), Odom(1),Odom(2);
        temp_b << scan(0),scan(1),scan(2);

        // 给到A和B
        A.block<3,9>(3*now_len,0) = temp_A;
        b.block<3,1>(3*now_len,0) = temp_b;

        //end of TODO
        now_len++;
        return true;
    }
    else
    {
        return false;
    }
}

Eigen块赋值操作 学习:https://www.cnblogs.com/wangxiaoyong/p/8906213.html
或我的blog:https://blog.csdn.net/weixin_44684139/article/details/105514563

Solve()函数

Eigen::Matrix3d OdomCalib::Solve()
{
    Eigen::Matrix3d correct_matrix;

    //TODO:求解线性最小二乘

    Eigen::Matrix<double,9,1> X_ = A.colPivHouseholderQr().solve(b);
    correct_matrix << X_(0),X_(1),X_(2),X_(3),X_(4),X_(5),X_(6),X_(7),X_(8);
    //end of TODO

    return correct_matrix;
}

因为是超定方程,并且直接套公式的话容易放大误差,因此用到了QR分解求线性方程组。colPivHouseholderQr()

然后编译—roslaunch–rviz–rostopic pub这些都按照作业要求走即可。

rviz画面,中间蓝线为标定矫正后的结果。
在这里插入图片描述

标定结果:

correct_matrix:
   0.946384    -1.64479   0.0124617
 -0.0709081    -1.04267  0.00173608
-0.00674715   0.0415879   0.0619791
calibration over!!!!
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44684139/article/details/105515431

智能推荐

Devops学习笔记02-程序员宅基地

核心价值:让运维团队将运维服务转换为运维能力提供给开发团队,让开发团队像引用代码一样引用运维能力。运维团队通过对环境代码的改善将运维是所关注的稳定性、性能、安全性等要求作为约束传导给开发团队。开发团队利用这种能力将业务价值更快的交付给用户,最终实现研发和运维的整体敏捷。幂等性——Idempotence & 描述性配置Descri..._devops学习

OpenCv基础学习笔记之一[highgui_c.h]_highgui_c.hwenjianxiazai-程序员宅基地

Ex01#include "cv.h"#include "highgui.h"int main(){ IplImage *srcImage; if ((srcImage = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE)) == NULL) // if((srcImage=cvLoadImage("lena.jpg_highgui_c.hwenjianxiazai

操作系统Linux环境下动态分区存储管理的内存分别配回收_按下面要求给出linux系统代码: 为了实现动态多分区的分配和回收,主要解决四个问题_坚果的博客的博客-程序员宅基地

今天上机要求Linux下实现动态分区存储管理的内存分别配回收现在把源码贡献出来#include<stdlib.h> #include <stdio.h> #include <string.h>#define MAX 600 //设置总内存大小为512k struct partition { char pn[10];//分区名字 ..._按下面要求给出linux系统代码: 为了实现动态多分区的分配和回收,主要解决四个问题

centos7防火墙配置以及缓存清空_firewall清空规则-程序员宅基地

一.centos7使用firewalld1、firewalld的基本使用启动: systemctl start firewalld关闭: systemctl stop firewalld查看状态: systemctl status firewalld 开机禁用 : systemctl disable firewalld开机启用 : systemctl enable fire..._firewall清空规则

python二进制转十进制编程_python 二进制与十进制之间的转换-程序员宅基地

1、十进制 与 二进制之间的转换(1)、十进制转换为二进制,分为整数部分和小数部分整数部分方法:除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权上的数。这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数读起,一直到最前面的一个余数。下面举例:例:将十进制的168转换为二进制得出结果 将十进制的168转换为二进制,(10101000)2168..._python二进制转十进制

使用element-ui 菜单栏(el-menu)点击两次才高亮的bug-程序员宅基地

解决方法:使用路由的name属性设置给index和default-active。原因:default-active和index属性不一致导致的。

随便推点

关于张老师Java视频学习(五)-程序员宅基地

Java基础知识加强视频的学习:一、知识点:17、透析反射的基础_Class类: P224 & P457 (1)、得到一个类的字节码有两种情况,一种是,类的字节码已经加载到内存中,则使用:对象名.getClass()方法,即可得到该对象的类的字节码。 另一种是,类的字节码还未加载到内存中,那么,我们使用Class方法:Class.forName("类名"),利用类加载器加载,放入缓存中,并返回该类的字节码。 (2)、得到各个字节码的Class对象: 1、类名.Class 2、对象名.getClass

linux setsockopt函数-程序员宅基地

<div id="article_content" class="article_content clearfix"> <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-b5506197d8.css"> <div id="content_views" class._linux setsockopt

win11 python调用dll问题:FileNotFoundError: Could not find module ‘xxx.dll‘ (or one of its dependencies)_酷酷的橙007的博客-程序员宅基地

系统环境:win11/Python3.8/pycharm今天在用Python调用一个用c++编写的动态链接库dll文件一直报如下错误:FileNotFoundError: Could not find module 'xxx.dll' (or one of its dependencies). Try using the full path with constructor syntax.之前一直以为是调用文件路径的问题,或者是Python3.8对于调用dll文件的保护问题,按照网上许多方法都没有

Java工程师必备知识!Spring(1)_"<property name=\"studentmapper\" ref=\"\"></prope_程序员呼呼的博客-程序员宅基地

<property name="studentMapper" ref="studentMapper"></property></bean><!-- 批量产生mapper对象在IOC中的id值默认就是接口名--><bean id="mappers" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFac._""

Java语言中Object对象的hashCode()取值的底层算法是怎样实现的?,object hashcode_native javaobject 取值-程序员宅基地

http://www.bkjia.com/ASPjc/919437.html Java语言中,Object对象有个特殊的方法:hashcode(), hashcode()表示的是JVM虚拟机为这个Object对象分配的一个int类型的数值,JVM会使用对象的hashcode值来提高对HashMap、Hashtable哈希表存取对象的使用效率。 关于Object对象的h_native javaobject 取值

Fedora构建Nginx-程序员宅基地

Fedora构建Nginx1、Fedora Fedora 怎样设置终端快捷键 https://jingyan.baidu.com/article/cb5d61053598ed005d2fe05c.html 设置root 登录进入终端,直接输入 sudo passwd root 输入普通用户密码 输入你要设置的root密码 重复root密码[lym@bogon ~]$ s...

推荐文章

热门文章

相关标签