引言
在写ROS工程代码时,有时候找一个bug非常麻烦,尤其是运行时出错的bug,这时候借助一些调试器可以极大的提高查找bug的效率。
ROS官方列出了许多可用的IDE,如VScode, Qtcreator, Ecllipse, Clion等,而这些不方便快速的调试。
所以,下面介绍如何使用GDB调试器来进行ROS C++项目的调试。
在debug模式编译
编译器有些优化会让debug无法进行。为了避免这种情况,程序编译时要加上debug
选项,让cmake以debug模式编译,不然可能会在gdb调试的时候不能跳转到源代码,只能进入断点。
普通的非ROS程序用gdb怎么调试呢?
编译时
- 方法一:在使用命令行
catkin_make
时加上一个参数:
catkin_make -DCMAKE_BUILD_TYPE=Debug
- 方法二:直接修改
CMakelist.txt
,添加以下代码:
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
运行时
添加GDB调试指令 (launch)
修改ROS launch
文件,在node
标签中添加一句话:
launch-prefix="xterm -e gdb -ex run --args "
修改后的launch
文件如下所示:
<node pkg="waypoint_follower" type="pure_persuit" name="pure_pursuit" output="screen" launch-prefix="xterm -e gdb -ex run --args">
<param name="is_linear_interpolation" value="$(arg is_linear_interpolation)"/>
</node>
这样在执行原来例子的时候,就会先打开一个新的Shell
界面,被调试的程序就在这个Shell
中被执行了。
如果使用的是Python来写ROS,则需要修改调试器为pdb,如下:
launch-prefix="xterm -e python -m pdb "
附:
roslaunch node前缀:
The launch-prefix attribute of the tag that, among other things, makes it easy to debug a ROS node process. Here are some example launch-prefixes you might find useful:
launch-prefix=“xterm -e gdb --args”
: run your node in a gdb in a separate xterm window, manually type run to start itlaunch-prefix=“gdb -ex run --args”
: run your node in gdb in the same xterm as your launch without having to type run to start itlaunch-prefix=“stterm -g 200x60 -e gdb -ex run --args”
: run your node in gdb in a new stterm window without having to type run to start itlaunch-prefix=“valgrind”
: run your node in valgrind。这个valgrind工具可以用于检测内存泄露,并执行性能分析launch-prefix=“xterm -e”
: run your node in a separate xterm window
launch-prefix=“nice” : nice your process to lower its CPU usagelaunch-prefix=“screen -d -m gdb --args”
: useful if the node is being run on another machine; you can then ssh to that machine and do screen -D -R to see the gdb sessionlaunch-prefix=“xterm -e python -m pdb”
: run your python node a separate xterm window in pdb for debugging; manually type run to start it
在使用roslaunch node debug.launch
后会得到:
添加GDB调试指令 (cmd)
跑ros程序的两个方法一个是rosrun
,一个是roslaunch
。
roslaunch
在上文已讲,下面就是使用cmd
去跑rosrun
,首先使用下面语句执行文件:
rosrun --prefix 'gdb -ex run --args' [package_name] [node_name]
执行完上面的语句,你会发现程序直接开始跑了,我还来不及设置断点什么的呢。问题应该出在run那个参数上,不过我暂时没找到替代的,得想想其他办法。
rosrun
其实就相当于直接执行二进制文件,那么我们直接找到catkin_make
产生的二进制文件进行运行不就完了?每一个package
产生的二进制文件存放的位置在:
you_catkin_workspace/devel/lib/your_package_name
cd
进去上面的路径,你应该能看到你在CMakeLists.txt
里通过add_executable
产生的那个二进制文件的名字(就是rosNode
了)。
在terminal
中输入:
gdb node_name
就会发现进入gdb
模式了,terminal
的输出像下面这样:
这时候我们就可以输入命令进行调试了。
调试
设置断点
设置断点的方法为:break <where>
,这个where
指的是程序的哪一行。例如,我在上面的程序的28行注释了一下,我们在terminal
中输入:
break 28
#或
b 28
会看到一则消息关于断点设置的.然后我们就可以跑程序了。在terminal
中输入:
run
#或
r
根据terminal
的输出应该能很轻易的知道28行程序暂停了,断点已经设置成功了。
另外也可以设置断点在某个函数:
break 函数名
#或
b 函数名
这样进入函数的时候程序会暂停。
查看变量值
现在我们要怎么查看某个变量的值呢?print/format <what>
或者display/format <what>
,what
表示是什么变量。我们在terminal
中输入:
print count
#或
p count
便能看到程序中变量count
的值了。
执行下一步
在terminal
中输入next
或n
就可以。
设置被包含的程序的断点
我们写大型程序的时候,一个rosnode
肯定include
了好多文件,上面的break 28
默认在主函数中设置断点了,那么我们想在其他不在同一个cpp
文件中的函数设置断点之类的呢?比如我们在CMakeLists.txt
中编译的时候使用的下面语句:
add_executable(main main.cpp b.cpp c.cpp)
之后使用gdb main
进行调试,如果我们想在b.cpp
中加一个断点,我们只需要在terminal
中特殊指明是哪个cpp
加上行数即可,比如:
break b.cpp:line_number
其中line_number
表示你想在b.cpp
中的哪行代码添加breakpoint。
显示出错的位置
gdb调试出错了,比如出现segmentation fault,通常会自动显示出错位置,输入where
可以显示出更详细的内容。
退出gdb
程序正在运行,按下crtl+c
,在输入q
退出。
程序没有运行,直接输入q
退出。
GDB基本命令
显示被调试文件信息:
查看/修改内存:
断点:
调试运行: