科学的分析和解决ROS运行中产生的undefined symbol类报错的方法

   在我们运行ROS开源功能包的时候,可能会遇到: undefined symbol类报错,如 slam_gmapping: undefined symbol: _ZN8GMapping 14 sampleGaussianEdm

在这里插入图片描述

   一、报错原因分析

   该问题一般是缺失或者没有找到该功能包所需的某个.so 动态链接库文件。首先,先排除一些比较简单且容易解决的原因,比如


   1、删除该功能包对应到的编译文件,如build和devel文件夹中相关内容,然后重新编译,验证问题是否被解决

   2、尝试检查是否存在版本不匹配问题,可以通过简单的更新功能包版本或者切换成匹配版本,来查看问题是否被解决

   3、使用rosdep工具来检查是否缺失该功能包所需的依赖,若缺失,则安装后,验证问题是否被解决

   4、检查功能包的CMakeLists.txt文件中设定的编译规则是否存在没有包含必要的库或者链接设置的问题,如果你是是下载的某些使用人数比较多的开源功能包,往往不会存在这个问题,可以跳过该步检查。

   5、检查功能包所在的路径是否位于环境变量的路径中,若不在,则添加后,验证问题是否被解决。


   如果,以上检查都没有问题,那么就需要进行科学的深入分析了,也就是本文的核心内容,如下所示:

   1、使用c++filt 工具将报错信息中的符号化名称转换回我们可读的函数名或变量名

   具体而言,在本文的例子中将报错信息undefined symbol: _ZN8GMapping14sampleGaussianEdm中的符号化名称,通过如下指令进行转换

c++filt _ZN8GMapping14sampleGaussianEdm

   执行后,终端返回的信息如下

GMapping::sampleGaussian(double, unsigned long)

   这表明运行报错的原因是系统在寻找 GMapping::sampleGaussian 函数的定义时,未能成功找到

   【补充说明——c++filt 工具】:c++filt 是一个工具,用于解析 C++ 程序中的符号化(mangled)名称,将它们转换回人类可读的函数名或变量名。C++ 的符号化是一种机制,用于在编译时生成每个函数或变量的唯一名称,以此来支持诸如函数重载、命名空间等特性。对于给出的符号 _ZN8GMapping14sampleGaussianEdm,运行 c++filt 命令将解码这个符号化的名称,以便理解它代表的具体函数或变量。这在调试链接错误(如未定义符号错误)时特别有用,因为它可以帮助开发者确定缺失的确切函数或变量。


   2、使用nm工具查找存在GMapping::sampleGaussian定义的动态库文件,来确定是否有正确的库文件包含了所示的函数定义

   具体而言,先进入到报错的功能包所在工作空间存放.so动态链接文件的路径下,其一般在工作空间的/devel/lib文件夹下,如我的位于 /home/gly/catkin_ws/devel/lib/路径下,使用cd指令切换到该路径下

cd /home/gly/catkin_ws/devel/lib/

   然后,在终端执行如下指令,来查找GMapping::sampleGaussian函数存在哪些动态链接库文件中,以及是否被定义

for so in *.so; do
    echo "Checking $so ..."
    nm -C $so | grep GMapping::sampleGaussian && echo "Found in $so"
done

   执行后返回的结果如下:

   虽然,返回了三个结果,但是其在 libgridfastslam.so 以及 libslam_gmapping_nodelet.so 文件中显示为未定义(“U”),在libutils.so文件中是有效定义的,这个libutils.so文件可能就是程序运行所需要的动态链接库文件。


   3、借助GMapping::sampleGaussian所在cpp文件中其他函数,验证上一步找到的libutils.so文件是否就是导致程序运行报错的所需要的文件

   通过vscode或者其他带有查找功能的文件管理软件,浏览该功能包,查找GMapping::sampleGaussian所在的cpp文件,本文中的例子在stat.cpp中,选择该文件中其他任意一个非内置函数,如本文的例子中选择的pf_ran_gaussian函数,如下图所示:

   使用nm工具查找pf_ran_gaussian函数所在的动态库文件,即执行以下指令

for so in *.so; do
    echo "Checking $so ..."
    nm -C $so | grep GMapping::pf_ran_gaussian&& echo "Found in $so"
done

   运行结果如下,可以发现其仅存在于libutils.so文件中,且被成功定义 (T)

在这里插入图片描述

   非常好,现在基本上已经确定slam_gmapping: undefined symbol: _ZN8GMapping14sampleGaussianEdm 问题的原因出在libutils.so文件,现在该文件已经确定是存在,且其路径在ROS的环境变量中,那大概率就是文件冲突原因导致的了。

   4、直接在整个计算机范围为搜索该文件libutils.so

在这里插入图片描述

   使用以下指令查看链接库环境变量优先级

echo $LD_LIBRARY_PATH

   结果如下所示:

在这里插入图片描述

   可以发现确实是存在多个同名文件,/home/gly/motionplanning_ws中的内容是我近期新加入的,且其环境变量的优先级高于openslam_gmapping功能包所在的工作空间/home/gly/catkin_ws环境变量的优先级,这样就说的通,为啥gampping建图突然就不能用了,因为,我在一个具有更高优先级的工作空间环境变量中新加入的程序中也存在一个libutils.so文件,且与openslam_gmapping功能包所需的文件不是同一个文件,这样程序在运行时,优先搜索到了这个错误的同名链接文件,这个文件中当然没有所需的sampleGaussian等函数的相关内容。


   二、解决方法

   找到原因后,接下来的解决方法就很简单了,/home/gly/motionplanning_ws中的内容是我需要的,显然并不能采取删除来解决该问题,比较理想的方式是调整工作空间优先级,根据个人的情况,可以采用临时调整和长久调整两种模式


   1、在调整之前还有两个非常重要的概念需要区分: ROS_PACKAGE_PATH 和LD_LIBRARY_PATH

LD_LIBRARY_PATHROS_PACKAGE_PATH 是两个不同的环境变量,它们在 UNIX 和 Linux 系统中用于不同的目的,尤其是在使用 ROS(Robot Operating System)时。

LD_LIBRARY_PATH

  • 用途LD_LIBRARY_PATH 是一个环境变量,用于指定动态链接器搜索动态库(.so 文件)时的目录路径。当程序运行时,动态链接器会在这些路径中查找所需的动态库文件。
  • 作用范围:它影响的是程序运行时的库加载行为,不仅限于ROS,适用于所有使用动态库的程序。
  • 特点:修改 LD_LIBRARY_PATH 可以解决库版本冲突或确保程序使用特定版本的库,但是不当的使用可能会导致系统或其他程序的运行问题。

ROS_PACKAGE_PATH

  • 用途ROS_PACKAGE_PATH 是一个特定于 ROS 的环境变量,用于指示 ROS 系统在哪些目录下查找 ROS 包。这个变量包含了一系列目录,ROS 工具(如 roscd, rospack, rosrun 等)会在这些目录中搜索包。
  • 作用范围:它仅影响 ROS 工具和运行时系统寻找和管理 ROS 包的行为,与动态链接库的加载无关。
  • 特点:正确设置 ROS_PACKAGE_PATH 对于 ROS 节点和程序能够找到其依赖的包至关重要。它确保了 ROS 工具和运行时环境可以在你的工作空间中找到并正确使用 ROS 包。

总结

   - LD_LIBRARY_PATH 关注的是程序运行时动态库的加载,它告诉动态链接器在哪些额外的目录中查找库文件。- ROS_PACKAGE_PATH 关注的是 ROS 环境中包的查找,它告诉 ROS 在哪些目录中查找 ROS 包。

   两者都是环境变量,但服务于不同的目的,分别影响动态库的加载和ROS包的查找。在使用 ROS 进行开发时,正确配置这两个环境变量对于确保程序的正确编译和运行非常重要。

   所以我们需要调节的事LD_LIBRARY_PATH,而不是ROS_PACKAGE_PATH!!!


   2、方法一:临时调整

   在你想要运行gmapping建图的终端执行以下指令(工作空间路径需要根据自己情况修改),来仅在该终端下将gmapping建图所在的工作空间

export LD_LIBRARY_PATH=/home/gly/catkin_ws/devel/lib:$LD_LIBRARY_PATH

   这个命令将 /home/gly/catkin_ws/devel/lib 添加到 LD_LIBRARY_PATH 的开头,确保了动态链接器首先搜索这个目录。请注意,这种更改只对当前终端会话有效。关闭终端或开启新的会话都将丢失这个设置。

   3、方法二:长久调整

   如果你希望这个设置在所有会话中都有效,可以通过修改.bashrc文件中关于环境变量的配置,你可以选择手动打开该文件,在文件末尾加入如下语句,然后保存

export LD_LIBRARY_PATH=/home/gly/catkin_ws/devel/lib:$LD_LIBRARY_PATH

   当然,你可以选择直接在终端执行如下语句,自动将其添加到.bashrc文件中

echo 'export LD_LIBRARY_PATH=/home/gly/catkin_ws/devel/lib:$LD_LIBRARY_PATH' >> ~/.bashrc

   使用如下指令,分别打印出修改前后的动态链接库路径如下所示

   然后,我成功运行了gmapping建图,如下所示,问题成功解决

在这里插入图片描述


   4、除了上面介绍的删除冲突文件或者修改动态链接库优先级的方法外,其实也可能通过修改功能包的CMakeLists.txt文件中关于生成.so文件的命名相关的语句,然后重新编译,通过来改名来彻底解决同名冲突问题。


   注:本文还存在另外一个记录了我探索和总结以上方法过程的版本,其更加详细,但概括总结性不如本文,其链接如下:

   https://blog.youkuaiyun.com/qq_44339029/article/details/137290086


在这里插入图片描述


<think>嗯,用户遇到了一个ROS中的问题,报错是“process has died [pid 12125, exit code -6, ...”。我需要帮他们分析可能的原因。首先,exit code -6通常表示程序异常终止,可能涉及段错误者内存问题。接下来,我应该考虑几个常见的原因: 1. **段错误(Segmentation Fault)**:这是最常见的导致exit code负数的情况,比如-6。可能是程序访问了无效的内存地址,比如空指针者越界访问。需要检查代码中的指针数组操作。 2. **依赖缺失版本不匹配**:ROS节点可能依赖某些库,如果这些库没有正确安装者版本不对,会导致崩溃。用户需要确认所有依赖项是否安装正确,特别是动态链接库是否存在问题。 3. **ROS通信问题**:节点可能因为无法连接到其他节点服务而崩溃。比如,话题服务的名称不匹配,者主节点(roscore)没有运行。需要检查网络配置节点名称是否正确。 4. **资源限制**:比如内存不足文件描述符耗尽。尤其是在处理大量数据长时间运行时容易出现这种情况,可以使用系统工具监控资源使用情况。 5. **配置文件参数错误**:启动文件(launch file)参数服务器中的错误配置可能导致节点初始化失败。检查YAML配置launch文件中的参数是否正确。 接下来,用户需要按照步骤排查: - **查看日志文件**:日志路径已经给出,用户应该用`less``cat`查看具体的错误信息,比如堆栈跟踪,这能帮助定位问题。 - **GDB调试**:如果日志不够详细,使用gdb附加到进程运行core dump分析,查看崩溃时的堆栈信息。 - **valgrind检查内存泄漏**:内存错误可能不会立即显现,使用valgrind工具可以帮助发现潜在的内存问题。 - **检查ROS环境**:确认roscore是否运行,话题服务是否正确,使用`rostopic list``rosservice list`验证。 - **更新重新安装**:确保所有软件包依赖都是最新的,有时候重新编译安装可以解决链接问题。 用户可能对ROS的内部机制不太熟悉,所以需要解释清楚每一步的作用,比如如何检查日志,如何使用调试工具。同时,可能需要提醒他们注意代码中的潜在错误,尤其是在最近是否有修改过相关节点。另外,如果问题出现在特定硬件上,可能需要检查硬件连接驱动程序是否正确安装。</think>这个报错信息表明ROS节点`wheeltec_robot_node`异常终止。以下是逐步排查分析的步骤: --- ### **1. 核心原因分析(exit code -6)** - **负数的退出码**通常表示进程因信号(Signal)被终止。`exit code -6`对应`SIGABRT`信号(实际信号号为`6`),代表进程主动调用`abort()`终止。 - **常见触发场景**: - 内存操作错误(如双重释放、堆栈溢出) - 断言失败(`assert()`条件不满足) - 未捕获的C++异常(如`std::bad_alloc`) --- ### **2. 关键排查步骤** #### **(1) 查看完整日志文件** ```bash less /home/wheeltec/.ros/log/2ee376d8-0f66-11f0-a616-9061ae4857a6/wheeltec_robot-2.log ``` - 重点关注日志中的 **`Backtrace`(堆栈跟踪)**,它会指向代码崩溃的具体位置。 #### **(2) 检查常见代码问题** - **硬件驱动问题**: - 检查机器人底盘串口权限:`ls -l /dev/ttyUSB*` - 确认串口设备号是否与代码匹配(如`/dev/ttyUSB0`)。 - **ROS通信配置**: - 检查`launch`文件中参数是否正确定义(如话题名称、波特率)。 - 使用`rostopic echo``rostopic list`验证话题是否正常发布。 #### **(3) 使用GDB调试** - 修改`launch`文件添加调试参数: ```xml <node pkg="turn_on_wheeltec_robot" type="wheeltec_robot_node" name="wheeltec_robot" output="screen" launch-prefix="xterm -e gdb --args"> ``` - 重新运行节点,观察GDB输出的崩溃位置。 #### **(4) 内存泄漏检测** ```bash valgrind --leak-check=full /home/wheeltec/wheeltec_robot/devel/lib/turn_on_wheeltec_robot/wheeltec_robot_node ``` - 检查输出中是否有`Invalid read/write``definitely lost`等关键字。 --- ### **3. 高频问题场景** | 问题型 | 典型表现 | 解决方法 | |------------------|------------------------------|------------------------------| | 串口权限不足 | 日志中提示`Permission denied`| 执行`sudo chmod 666 /dev/ttyUSB*` | | 话题未订阅/发布 | 节点等待超时后崩溃 | 检查依赖节点是否启动 | | 动态库缺失 | 启动时报`undefined symbol` | 重新编译更新依赖包 | --- ### **4. 附加建议** - **更新代码仓库**: ```bash cd ~/wheeltec_robot/src && git pull && catkin_make ``` - **检查系统资源**: ```bash dmesg | tail # 查看内核日志是否有OOM(内存不足)记录 ``` --- 通过上述步骤,可逐步定位到具体原因。若堆栈信息指向特定函数(如驱动读写函数),需重点检查相关代码段的资源管理边界条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕羽★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值