“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历

前言

最近突然沉迷b站up主“城阳电工电路”的视频,看着每一次排查电路问题的过程,就好像自己debug程序问题的感受,代入感非常强烈。最近编译一个ros项目时,由于版本不一致的原因,也遇到了不少编译错误。让我最后非常有成就感的是,这一次的debug过程脑子全程在线,没有卡壳,从假设到验证,层层递进,直达问题根源,而且大部分的错误都是用这一个思路解决的。最后解决问题的时候,真就感觉仿佛“名侦探”断案,脑海中闪过那句经典名言——“新几次瓦一字莫黑道次!”。来跟我复现一下这一气呵成的一次debug过程吧!

开端

在编译github上的一个ros仓库时,由于作者使用的是Ubuntu 16.04的ROS版本kinetic,而我自己则是18.04的melodic的ROS版本,编译时自然而然就出现了问题。

“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第1张图片
从error的地方可以看到报错原因是“执行了一个不可用的变换转换”,乍一听云里雾里不知所云。不过上一行就提示了出错代码段的位置位于hand_eye_move.cpp的132行,不如先去看一下源代码再判断。

在这里插入图片描述
可以看到132行是visual_tools对象调用了publishText()方法,其中第一个参数text_pose我们可以从这个函数的形参类型中知道它是Eigen库中Affine3d类型的矩阵,后面三个参数,一个是字符串,另外两个看起来也像是属性描述之类的作用,似乎都不太重要。联想到我们报错的问题,大概率是这个矩阵变量的问题。从函数的形参里可以知道visual_toolsmoveit_visual_tools::MoveItVisualTools类中的一个对象,而在编译前安装过ros-melodic-moveit-visual-tools这个工具,是不是可能随着版本的更新,这个对象中的方法原型发生了变化导致了现在的报错呢?那么不如我们接着往下,去看一下publishText()这个方法的函数原型吧。

发展

这个时候疑惑的地方来了,打开了MoveItVisualTools类所在的头文件moveit_visual_tools.h,用CLion左边栏的Structure功能去看有哪些方法,竟然没有publishText()这个方法。

“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第2张图片
我用字母表顺序排列所有的方法名,很显然没有,顿时感觉很奇怪,不过很快想到,也许这个包在版本迭代过程中进行了大更新,把函数名都修改了。顺着这个想法,我直接奔着ros-melodic-moveit-visual-tools这个包的github仓库看一下moveit_visual_tools.h文件的历史提交。

“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第3张图片
从2014年首次提交到2015年最后一次,一共也就这几次提交,索性全部找一遍,当然我直接先去看了最初的提交版本。令我惊讶的是,最初的版本和现在版本的函数类别数量差不多,并且没有我们要找的publishText(),我又去看了另外的提交版本,也没有。那publishText()这个方法没有,其他调用的方法比如deleteAllMarkers()有没有呢?找了一遍,还是没有。抱着疑惑的心情,我想,既然moveit_visual_tools.h中没有定义publishText()deleteAllMarkers()等这几个的方法,而且编译时报错也不像是缺少头文件的样子,那我倒要看看这几个方法在哪个文件里。这时就要祭出万能的Linux shell了,用find和xargs的管道,找出包含“publishText()”字段的文件。想到大概率还是ros原生的方法,查找目录就定在ros的安装目录/opt/ros,直接执行find /opt/ros/ | xargs grep -ril "publishText"

在这里插入图片描述
有结果打印就是振奋人心的,什么???竟然在rviz_visual_tools.h里。满怀期待同时又很不解,直接打开文件看方法原型。
“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第4张图片瞧瞧,这不就来了吗?有了函数原型,我们可以很明显地看到有关pose这个形参的类型定义是不相同的,出错源代码中是Affine3d,而在这里则是Isometry3d。凭借“多年”debug的直觉,可以确定问题出在这里了,不过为了验证一下自己的猜想,我又跑到github上去看了下rviz_visual_tools.h的历史提交,果不其然,在publishText()这一方法的首次提交的commit中,看到了最初的函数原型。
“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第5张图片
从912行看到,pose形参的最初类型就是Affine3d,和我们的猜想一致,确定是在版本迭代过程中,publishText()方法的第一个形参类型发生了变化,实际上如果用原先类型Affine3d定义一个矩阵变量,作为参数传入现在的Isometry3d定义的函数中时,的确可能会执行某种conversion操作,报之前的错误也不足为奇了。

高潮

到了这里,依然有个疑问,为什么原先类的定义中没有。。。马萨卡!(PS:此时一道闪电划过脑壳)
“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第6张图片我知道犯人是谁了,不是,我知道为什么了。

“名侦探”兔哥上线——记一次从蛛丝马迹中debug问题的经历_第7张图片【沉睡的小五郎】犯人就是“继承(Inheritance)”!moveit_visual_tools.h中的类MoveItVisualTools应该继承了rviz_visual_tools.h的定义,调用的publishText()是父类的方法,只要查看moveit_visual_tools.h文件的开头,真相就会大白!

在这里插入图片描述

结局

此时此刻,犯人(我)直接跪下,痛苦流涕,“是我太菜了,C++学艺不精,呜哇呜哇~”。
将原先使用Affine3d定义的矩阵变量修改为Isometry3d之后,编译就通过了。

在这里插入图片描述

总结

柯南入戏太深了属于是233。回顾这一次debug的过程,如果对ros或c++的实践经历更加丰富,其实很容易想到调用了父类的方法,奈何自己学艺不精,阅历尚浅,才有了这次虽然很爽但是又很显笨拙的debug经历。不过自我感觉这次的debug实践还是比较考验思路和能力的,因此就有感而发记录下来,当然自己还需要学习的地方还有很多很多,还需要再接再厉!

你可能感兴趣的:(SLAM&VIO,c++,linux)