当前位置: 首页 > news >正文

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 ./<file>.deb

# If you're on an older Linux distribution, you will need to run this instead:
# sudo dpkg -i <file>.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的内容如下,

<launch>
    <arg name="config_path" default = "$(find feature_tracker)/../config/euroc/euroc_config.yaml" />
	  <arg name="vins_path" default = "$(find feature_tracker)/../config/../" />
    
    <node name="feature_tracker" pkg="feature_tracker" type="feature_tracker" output="log">
        <param name="config_file" type="string" value="$(arg config_path)" />
        <param name="vins_folder" type="string" value="$(arg vins_path)" />
    </node>

    <node name="vins_estimator" pkg="vins_estimator" type="vins_estimator" output="screen">
       <param name="config_file" type="string" value="$(arg config_path)" />
       <param name="vins_folder" type="string" value="$(arg vins_path)" />
    </node>

    <node name="pose_graph" pkg="pose_graph" type="pose_graph" output="screen">
        <param name="config_file" type="string" value="$(arg config_path)" />
        <param name="visualization_shift_x" type="int" value="0" />
        <param name="visualization_shift_y" type="int" value="0" />
        <param name="skip_cnt" type="int" value="0" />
        <param name="skip_dis" type="double" value="0" />
    </node>

</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<std::string>(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 <node> 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 <filename>": 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

相关文章:

  • Windows 10上安装ROS noetic平台
  • Ubuntu查看环境变量
  • 四元素(四元数quaternion)的理解
  • SLAM算法资料收集
  • Ubuntu查看网卡信息
  • GDB最常用的命令
  • Ubuntu20.04+vscode快速调试ROS通用程序
  • ROS-Tutorials:rviz之Markers: Sending Basic Shapes (C++,附vscode调试说明)
  • Qt Creator 的下载与安装
  • Ubuntu20.04突然丢失网络时恢复的办法
  • Linux设置访问权限
  • ROS noetic view_frames TypeError: cannot use a string pattern on a bytes-like object
  • ROS noetic [turtle1_tf_broadcaster-4] process has died
  • Ubuntu下使用unzip或p7zip解压带密码的zip文件
  • libcurl: (51) SSL: no alternative certificate subject name
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • centos安装java运行环境jdk+tomcat
  • classpath对获取配置文件的影响
  • Go 语言编译器的 //go: 详解
  • idea + plantuml 画流程图
  • Java|序列化异常StreamCorruptedException的解决方法
  • leetcode98. Validate Binary Search Tree
  • Vue全家桶实现一个Web App
  • zookeeper系列(七)实战分布式命名服务
  • 设计模式(12)迭代器模式(讲解+应用)
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 运行时添加log4j2的appender
  • 智能合约开发环境搭建及Hello World合约
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • puppet连载22:define用法
  • Spring第一个helloWorld
  • 树莓派用上kodexplorer也能玩成私有网盘
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​插件化DPI在商用WIFI中的价值
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #微信小程序:微信小程序常见的配置传值
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • (1)(1.13) SiK无线电高级配置(五)
  • (12)Hive调优——count distinct去重优化
  • (JS基础)String 类型
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (转)http协议
  • (转)IOS中获取各种文件的目录路径的方法
  • (转)jQuery 基础
  • (转)拼包函数及网络封包的异常处理(含代码)
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET 中创建支持集合初始化器的类型
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • .net实现客户区延伸至至非客户区
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • [APIO2015]巴厘岛的雕塑