Ubuntu20.04+gdb/vscode调试ROS(VINS-Mono)程序

平台Ubuntu20.04 + ROS noetic

程序算法:VINS-mono

在阅读本文之前,建议先行了解基本的vscode调试工具与流程,以及如何安装vscode的ROS扩展,详情请参考博文:Ubuntu20.04+vscode快速调试ROS通用程序_tanmx219的博客-CSDN博客(PlaceHolder.....)这里假设你已经安装好了ROS noetic和git。(1) 安装vscode和extensionsubuntu上如何安装vscode可以参考官网,Running Visual Studio Code on Linux需要安装的vscode扩展如下,C/C++ (c++ intellisense and configuration help) -> MandatoryClangd (Alternative intellisense provhttps://blog.csdn.net/tanmx219/article/details/122799015

安装vscode

Ubuntu上安装vscode可参考官网,

Running Visual Studio Code on Linux我

我把其实的安装那段摘录如下,

Debian and Ubuntu based distributions#

The easiest way to install Visual Studio Code for Debian/Ubuntu based distributions is to download and install the .deb package (64-bit), either through the graphical software center if it's available, or through the command line with:

sudo apt install ./.deb

# If you're on an older Linux distribution, you will need to run this instead:
# sudo dpkg -i .deb
# sudo apt-get install -f # Install dependencies

Note that other binaries are also available on the VS Code download page.

Installing the .deb package will automatically install the apt repository and signing key to enable auto-updating using the system's package manager. Alternatively, the repository and key can also be installed manually with the following script:

wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/
sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list'
rm -f packages.microsoft.gpg

Then update the package cache and install the package using:

sudo apt install apt-transport-https
sudo apt update
sudo apt install code # or code-insiders

怎么操作?

编译vins-mono

过程和使用gdb调试没什么不同,主要是生成带调试符号的二进制文件(库文件或可执行文件),

catkin_make -DCMAKE_BUILD_TYPE=Debug

或者,直接在vscode中修改各个CMmakeLists.txt,

set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fPIC")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")

这里顺带说明一下,用

set(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -g -ggdb")

set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")

没看出有什么区别,指令($env | grep CXX)找了一下,什么也没找到,也没看到VINS-Mono中哪里有定义,不知道是不是我对cmake理解不到位。

如果纯粹使用gdb的话,这里就可以开始调试了,注意要source setup.bash先,然后逐个打开terminal用gdb调试节点。

我个人更偏向于使用vscode这种IDE调试的方式,所以下面重点讲解,

 使用vscode调试node

我的vins-estimator下面euroc.launch的内容如下,


    
	  
    
    
        
        
    

    
       
       
    

    
        
        
        
        
        
    

 可以看到有3个节点,vs这个IDE大家应该都会用,配置C++配置文件的过程就不多讲了,配置和参考中给出的稍有不同,有些默认的参数我没有修改,比如cStandard,没发现什么问题。当然你也可以选不同的编译器,对vins_mono和vins_fusion,一般cStandard是c11,cppStandard是c++17。

快捷键ctrl+shift+p,找到C/C++ :Edit configurations (JSON),添加c_cppproperties.json文件,这个文件应该是指定一些路径和语言标准,如下,

c_cpp_properties.json

{
    "configurations": [
        {
            "name": "Linux",
            "browse": {
                "databaseFilename": "",
                "limitSymbolsToIncludedHeaders": true
            },
            "includePath": [
                "${workspaceFolder}/**",
                "/opt/ros/noetic/include/**",
                "/usr/include/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu17",
            "cppStandard": "gnu++14",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}

快捷键ctrl+shift+p,找到Tasks:Configure Task,添加tasks.json文件,这个文件指定一些catkin_make的编译参数。

注意这里的定义"-DCMAKE_BUILD_TYPE=Debug", 

tasks.json

{
    "tasks": [
        {
            "label": "prerun",
            "type": "shell",
            "command": "source ./devel/setup.sh && export ROS_MASTER_URI=http://localhost:11311/ "
        },
        {
            "label": "catkin_make", //代表提示的描述性信息
            "type": "shell",  //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
            "command": "catkin_make",//这个是我们需要运行的命令
            "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
            "group": {"kind":"build","isDefault":true},
            "presentation": {
                "reveal": "always"//可选always或者silence,代表是否输出信息
            },
            "problemMatcher": "$msCompile"
        },
        {
            "label": "compound_build",
            "dependsOn": [
                "catkin_make",
                "prerun"
             ]
        }
    ],

    "version": "2.0.0"
}

附加说明

tasks可以附加取launch.json的preLaunchTask指令中(下面的例子里没有填)。

如果需要在launch之前运行tasks.json里的任务,就可以加上这一条,比如这里tasks.json里有一个名字叫"catkin_make",你可以通过

"preLaunchTask": "catkin_make"

这样的语句使程序在启动前都编译一次源码。

如果要运行全部task,可以通过下面的指令实现

"preLaunchTask": "compound_build"

 

launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "feature_tracker",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/devel/lib/feature_tracker/feature_tracker",
            "args": ["_config_file:=${workspaceFolder}/src/VINS-Mono/config/euroc/euroc_config.yaml", "_vins_folder:=${workspaceFolder}/src/VINS-Mono/"],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: g++ 生成活动文件",
            "miDebuggerPath": "/usr/bin/gdb"
        },
        {
            "name": "vins_estimator",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/devel/lib/vins_estimator/vins_estimator",
            "args": ["_config_file:=${workspaceFolder}/src/VINS-Mono/config/euroc/euroc_config.yaml", "_vins_folder:=${workspaceFolder}/src/VINS-Mono/"],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        },
        {
            "name": "pose_graph",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/devel/lib/pose_graph/pose_graph",
            "args": ["_config_file:=${workspaceFolder}/src/VINS-Mono/config/euroc/euroc_config.yaml", "_visualization_shift_x:=0", "_visualization_shift_y:=0", "_skip_cnt:=0", "_skip_dis:=0"],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ],
    "compounds": [
        {
            "name": "tracker/estimator/pose",
            "configurations": [
                "feature_tracker",
                "vins_estimator",
                "pose_graph"
            ]
        }
      ]
}

这里要注意,如果老是碰到下面的错误,

Unable to open 'raise.c': Unable to read file '/build/glibc-eX1tMB/glibc-2.31/sysdeps/unix/sysv/linux/raise.c'
 (Error: Unable to resolve nonexistent file '/build/glibc-eX1tMB/glibc-2.31/sysdeps/unix/sysv/linux/raise.c').

    config_file = readParam(n, "config_file");
"/home/matthew/projects/vinsmono/src/vins-mono/config/euroc/euroc_config.yaml"

那十有八九是配置不正确,例如在参考贴里用的vins-mono,但我的地址是VINS-Mono,所以就报错了,总之就是要和实际使用的地址一致。

vscode打的主文件夹,以我自己的文件夹结构为例,打开的是,

/home/matthew/projects/vinsmono/src/VINS-Mono

启动调试

因为viz和play都不需要调试,在这种情况下,所以我们分别打开两个终端输入下面前两条语句开始运行,运行euroc.launch打开后会弹出调试窗口,

roslaunch vins_estimator vins_rviz.launch

rosbag play YOUR_PATH_TO_DATASET/MH_01_easy.bag

roslaunch vins_estimator euroc.launch

这里play最后实际运行的是文件包,以我自己的运行为例,

rosbag play ~/downloads/vinsmono/machine_hall/MH_01_easy/MH_01_easy.bag

 要说明的是,如果你想在调试模式下看到和运行release模式一样的效果,你必须同时开始vins_estimator中的全部任务,也就是下面的多任务模式,否则你只能一个个节点地调试。

多任务调试

launch.json中有一段多任务调试代码,

  "compounds": [
        {
            "name": "tracker/estimator/pose",
            "configurations": [
                "feature_tracker",
                "vins_estimator",
                "pose_graph"
            ]
        }
      ]

如果启动这个的话,会有三个线程(三个terminal)同时启动调试。可能是我对源码了解不够深入,原始的pose graph还没有看到输出,不知道是否还需要一些其他配置,我自己在pose_graph_node.cpp中加了一句打印输出的语句,这样终端就不停有信息输出了,知道程序已经进入了主线程循环(不然没有任何信息输出),

 printf("--------------%d--------------\n", pose_dbg++);

其process的代码运行如下,

static int pose_dbg = 0;  // <------------added definition
void process()
{
    if (!LOOP_CLOSURE)
        return;
    while (true)
    {
        .......
        m_buf.unlock();

        if (pose_msg != NULL)
        {
            printf("--------------%d--------------\n", pose_dbg++); 
            //printf(" pose time %f \n", pose_msg->header.stamp.toSec());
            //printf(" point time %f \n", point_msg->header.stamp.toSec());
            //printf(" image time %f \n", image_msg->header.stamp.toSec());
            // skip fisrt few
..............

调试时首先打开两个终端,分别输入下面这两条语句,

roslaunch vins_estimator vins_rviz.launch

rosbag play YOUR_PATH_TO_DATASET/MH_01_easy.bag

然后再启动这个tracker/estimator/pose的compound节点,此时feature_tracker,vins_estimator和pose_graph每个节点都会打开一个终端,可以在terminal看到输出信息。

如果你不需要显示的话,那个viz其实不是必要的。可以不用启动。

现在,你可以愉快地用vscode调试VINS_Mono这样的程序啦。

暂时先写到这里吧,本来想做个动图放在这里,ubuntu下貌似gif动画工具很少。>T_T< 。

参考:如何用gdb调试ROS程序

官方的办法,

How to Roslaunch Nodes in Valgrind or GDB

Description: When debugging roscpp nodes that you are launching with roslaunch, you may wish to launch the node in a debugging program like gdb or valgrind instead. Doing this is very simple.
Keywords: roslaunch, valgrind, gdb, pdb
Tutorial Level: INTERMEDIATE
Next Tutorial: Profiling roslaunch nodes

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 it

  • launch-prefix="gdb -ex run --args" : run your node in gdb in the same xterm as your launch without having to type run to start it

  • launch-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 it

  • launch-prefix="valgrind" : run your node in valgrind

  • launch-prefix="xterm -e" : run your node in a separate xterm window

  • launch-prefix="nice" : nice your process to lower its CPU usage

  • launch-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 session

  • launch-prefix="xterm -e python -m pdb" : run your python node a separate xterm window in pdb for debugging; manually type run to start it

  • launch-prefix="yappi -b -f pstat -o ": run your rospy node in a multi-thread profiler such as yappi.

  • launch-prefix="/path/to/run_tmux": run your node in a new tmux window; you'll need to create /path/to/run_tmux with the contents:

    • #!/bin/sh
      
      tmux new-window "gdb --args $*"

Obtaining core dumps

To obtain core dumps when processes crash, first set the core file size limit. To check the limits, run:

$ ulimit -a
core file size          (blocks, -c) 0           #  <-- Prevents core dumps
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Set the core size to unlimited:

ulimit -c unlimited

Now crashing processes will attempt to create core files. Currently (2010-07-02) they will fail to create the file because the default roslaunch working directory, $ROS_HOME, contains a directory named "core". This directory prevents the core dump from being created.

To allow core dumps to be created, set the core filename to use the process pid by default. Run the following as root:

echo 1 > /proc/sys/kernel/core_uses_pid

Now core dumps will show up as $ROS_HOME/core.PID

Error shooting

  • If you get error like below one, you should try to launch node in another windows with gdb.link

  • launch-prefix="xterm -e gdb --args"

[tcsetpgrp failed in terminal_inferior: Inappropriate ioctl for device]

参考资料

ros项目调试:ROS项目使用GDB调试_Coulson的博客-CSDN博客_ros程序调试

GDB常用命令大全 GDB 命令详细解释_Linlei的专栏-CSDN博客_gdb 命令

ROS在线调试(使用GDB) - 古月居

利用vscode调试VINS-FUSION - 知乎

VS Code 调试 VINS-Mono 环境配置_Barry_123的博客-CSDN博客_vscode调试vins

 如何配置VSCode来调试ROS节点_白夜行的狼-CSDN博客_vscode调试ros

你可能感兴趣的:(SLAM,ROS,自动驾驶,ROS,SLAM)