平台Ubuntu20.04 + ROS noetic

程序算法:VINS-mono

阅读本文之前,建议先行了解基本的vscode调试工具与流程,以及如何安装vscode的ROS扩展,详情请参考博文:快速调试ROS通用程序_tanmx219的博客(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 prov

安装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

如何用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]

怎么操作?

编译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理解不到位。

 使用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,没发现什么问题。直接给结果,如下,

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
}

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"
}
],
"version": "2.0.0"
}

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不需要调试,所以我们直接打开一个终端开始运行,euroc.launch打开后会弹出调试窗口,play打开后会有动作,xterm gdb窗口可以看到信息迅速滚动,


​roslaunch vins_estimator vins_rviz.launch​

​roslaunch vins_estimator euroc.launch​

​rosbag play YOUR_PATH_TO_DATASET/MH_01_easy.bag ​


然后就可以启动euroc.launch了。

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


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


多任务调试

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
..............

这时如果启动rosbag play的话,feature_tracker,vins_estimator和pose_graph终端都可以在terminal看到输出信息。

(暂时先写到这里吧,后面有空再来补充,想做个动图放在这里才好,ubuntu下貌似gif动画工具很少。。。。T_T )

参考资料:

​ros项目调试:ROS项目使用GDB调试_Coulson的博客​

​GDB常用命令大全 GDB 命令详细解释_Linlei的专栏​

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

​利用vscode调试VINS-FUSION - 知乎​

​VS Code 调试 VINS-Mono 环境配置_Barry_123的博客​

 ​​如何配置VSCode来调试ROS节点_白夜行的狼​