NOTE · Autonomous Systems

ROS1、catkin 与 PX4:历史工程的可验证排障链

面向 ROS Noetic 历史工程,按环境、依赖、构建、运行图和 ABI 逐层定位问题。

ROS Noetic 和 ROS1 已结束官方支持,不再获得常规安全更新、新修复或新二进制。新项目应优先评估 ROS 2;必须复现 ROS1 工程时,则把操作系统、ROS、Gazebo、PX4、CUDA/OpenCV 和编译器视为一个不可随意拆开的版本集合。参见 ROS 官方 Noetic EOL 说明

一些历史教程推荐第三方“一键安装”脚本,并使用 HTTP 下载后直接在当前 shell 执行。本文不提供这种可复制命令:无论脚本作者是否可信,下载内容都可能变化,直接 source 还会继承当前 shell 权限。历史工程应优先使用已归档的 ROS 软件源、项目自己的容器或虚拟机定义和锁定提交;操作前保存镜像或快照。

1. 先确认当前 shell 到底加载了什么

printenv ROS_DISTRO
printenv ROS_PACKAGE_PATH
command -v roscore
python3 --version
rospack profile

工作空间示例:

source /opt/ros/noetic/setup.bash
source ~/catkin_ws/devel/setup.bash
rospack find PACKAGE_NAME

rospack find 找不到包,先检查:

  1. 包是否真的在当前工作空间的 src 下;
  2. package.xml 与目录结构是否完整;
  3. 当前 shell 是否 source 了正确的 setup.bash
  4. 是否同时 source 了多个互相覆盖的工作空间。

不要把个人绝对路径写进公共 launch 文件或 .bashrc;优先使用 $(find package_name)、环境变量或工作空间相对路径。

旧 XTDrone 工程里常见的 Resource not found 也先按这条链检查。原错误明确混入了另一台机器的 overlay:

ROS path [0]=/opt/ros/melodic/share/ros
ROS path [1]=/home/<other-user>/catkin_ws/src

看到错误输出列出另一个用户的工作空间,通常说明当前 shell source 了错误 overlay,而不只是“缺一个包”。GAZEBO_MODEL_PATHGAZEBO_PLUGIN_PATH 只有在项目确实使用非标准资源目录时才添加,并应在启动脚本中局部设置,不永久拼接未知路径。

2. catkin 构建:固定一种工具和根目录

catkin_make 应在工作空间根目录执行:

cd ~/catkin_ws
catkin_make
source devel/setup.bash

catkin build 属于 catkin_tools 的另一套工作流:

cd ~/catkin_ws
catkin config --cmake-args -DCMAKE_BUILD_TYPE=Release
catkin build PACKAGE_NAME
source devel/setup.bash

同一个工作空间里不要无意识地交替使用两套工具。遇到错误先保存完整的第一处编译错误、CMake 配置和包版本,而不是立即删除整个 builddevel

依赖检查:

rosdep check --from-paths src --ignore-src

若决定让 rosdep 安装缺失依赖,应先确认发行版软件源和锁定版本,再执行:

rosdep install --from-paths src --ignore-src -r -y

3. xacro 与 launch 文件

Noetic 中优先调用 xacro 可执行程序,不依赖旧的 xacro.py 路径:

<param
  name="robot_description"
  command="$(find xacro)/xacro '$(find ROBOT_PACKAGE)/urdf/robot.xacro'" />

单独验证生成结果:

rosrun xacro xacro PATH_TO_FILE.xacro > /tmp/robot.urdf
check_urdf /tmp/robot.urdf

这能把 xacro 语法/资源路径问题与 launch、Gazebo 问题分开。

一个具体案例是 Noetic 工程仍调用 $(find xacro)/xacro.py,错误中记录了当时的工程路径:

/home/<user>/catkin_ws/src/catvehicle/urdf/catvehicle1-3.xacro
/home/<user>/PX4_Firmware/launch/outdoor3_ugv.launch

把 launch 中的 $(find xacro)/xacro.py 改成发行版实际提供的 $(find xacro)/xacro 是有价值的,但还应先单独运行上面的生成命令;如果 URDF 本身、包资源或宏参数错误,只换可执行文件名并不会修好。

4. 运行图排查

rosnode list
rosnode info /NODE_NAME
rostopic list
rostopic info /TOPIC_NAME
rostopic hz /TOPIC_NAME
rostopic echo -n 1 /TOPIC_NAME
rosservice list

数据链路至少核对:

  • 发布者和订阅者是否存在;
  • 消息类型是否一致;
  • 时间戳是否推进;
  • frame_id 与 TF 树是否一致;
  • 频率和延迟是否满足控制回路;
  • 多机命名空间是否真正隔离。

只看到 topic 名称并不能证明数据有效。

5. 命令行调用 ROS 服务

先获取服务类型和请求结构:

rosservice info /SERVICE_NAME
rosservice type /SERVICE_NAME
rossrv show PACKAGE_NAME/ServiceType

无字段请求:

rosservice call /SERVICE_NAME "{}"

带字段请求:

rosservice call /SERVICE_NAME "{field_name: value}"

复杂消息先用 rossrv show 展开字段,再按照 YAML 结构填写。飞行控制服务还应在调用前核对模式、解锁状态、坐标系、单位和失联保护;“服务返回成功”不等于飞行行为安全。

Turtlesim 完整例子

下面用安全的教学例子说明流程。先在测试环境启动 turtlesim_node,再查看服务:

rosservice list
rosservice info /turtle1/teleport_absolute
rosservice type /turtle1/teleport_absolute
rossrv show turtlesim/TeleportAbsolute

该服务的请求字段通常是 xytheta。确认类型输出一致后调用:

rosservice call /turtle1/teleport_absolute "{x: 2.0, y: 3.0, theta: 1.57}"

这里 theta 使用弧度。这个例子验证的是服务发现、类型和 YAML 请求格式,不代表真实机器人服务可以跳过状态检查。

6. Gazebo、PX4 与感知包的版本冲突

以下症状经常来自版本集合不一致:

  • 找不到 gazebo_rosConfig.cmake
  • PX4/SITL 插件编译失败;
  • 旧 CMakeLists 固定了 GPU 架构;
  • Darknet、OpenCV 和 cv_bridge 的 ABI 不一致;
  • Python 包与系统 C++ 库来自不同前缀。

先收集:

gazebo --version
pkg-config --modversion opencv4
python3 -c 'import cv2; print(cv2.__version__, cv2.__file__)'
nvcc --version
cmake --version

再检查 CMake 实际找到的 include/library 路径和编译架构。不要把以下做法当作通用修复:

  • 手工覆盖 /opt/ros 中自动生成的 CMake 配置;
  • 把一长串本机绝对 .so 路径写死;
  • 为解决一个包而降级整机 OpenCV;
  • 没有备份就清空整个工作空间的构建产物;
  • 从 HTTP 下载未知脚本后直接 source 执行。

如果项目必须依赖旧 ABI,最可复现的方式通常是锁定容器/虚拟机镜像或单独的构建环境,并把补丁保存在版本库中。

旧工程中的具体症状

以下内容按“症状 → 证据”整理;不提供风险较高的整机覆盖配方:

  • Could not find gazebo_rosConfig.cmake:先用 rospack find gazebo_rosrosdep check 和 CMake 输出确认包是否存在、当前发行版是什么以及搜索前缀来自哪里。不要因为错误文本出现 gazebo_ros 就跨发行版安装一个同名二进制包。
  • FAILED: external/Stamp/sitl_gazebo/...-configure:保存 CMake 的第一处错误,核对 PX4 提交、Gazebo 主版本、编译器和子模块状态;最后一行的 stamp 失败不是根因。
  • Gazebo 界面不显示激光射线:可视化开关与传感器是否发布有效数据是两件事。检查对应 topic 类型、频率、时间戳和 frame,再处理 GUI 显示。
  • Python 报 (e_errno, msg, *_) = e.args 一类解包错误:通常应检查脚本预期的 Python/依赖版本和真实异常对象,不直接把这一行改成“能运行”的固定索引。
  • Fast-Planner 或其他老包编译失败:先确认仓库提交、ROS/Gazebo/Eigen/PCL 组合以及第一处编译错误。旧博客标题不能替代构建日志。

Darknet ROS、CUDA 与 OpenCV 的历史 ABI 案例

旧机在 /home/<user>/catkin_ws/src/darknet_ros/darknet_ros/CMakeLists.txt 中曾出现 nvcc fatal: Unsupported gpu architecture 'compute_89',当时使用 CUDA 11.7,随后通过把架构改成 compute_86、源码安装 OpenCV 3.4.14、覆盖 cv_bridgeConfig.cmake 和写死本机动态库路径来推进编译。路径和版本作为历史证据保留,但这套过程不能作为通用方案:

  1. GPU 的实际计算能力、NVCC 支持的 code 列表和项目 CMake 声明必须同时匹配;把 89 改成 86 可能只是生成兼容代码,不代表解决了工具链版本问题。
  2. OpenCV 4.x+ requires enabled C++11 support 首先指向编译标准/构建配置,不自动推出“必须降级到 OpenCV 3.4.14”。
  3. _IplImage::_IplImage(cv::Mat&) 属于旧 C API 与新版 OpenCV 的兼容边界;临时宏只能服务锁定源码,不能证明 ABI 完整一致。
  4. /opt/roscv_bridge 配置由软件包管理,手工写入 /usr/local/lib/libopencv_*.so 会让升级、卸载和复现失去一致性。

恢复这类工程时先收集:

nvidia-smi
nvcc --version
nvcc --list-gpu-code
pkg-config --modversion opencv4
python3 -c 'import cv2; print(cv2.__version__, cv2.__file__)'
rospack find cv_bridge
ldd DEVEL_SPACE/lib/LIBRARY_NAME.so

DEVEL_SPACELIBRARY_NAME 是占位符。结合 CMake cache、编译命令和 ldd 判断实际头文件/动态库来源,再决定是补项目源码、锁容器还是重建单独前缀。不要卸载整机 Python OpenCV,也不要覆盖 /opt/ros

7. 日志

rosclean check
du -sh ~/.ros/log

rosclean purge 会删除 ROS 日志,确认不再需要排查证据后才执行。遇到 logging 配置错误时,应先核对 ROS_HOME、文件存在性和权限,不要未经确认就在 /etc 创建或覆盖配置。

遇到 WARNING: cannot load logging configuration file, logging is disabled 时,有人会直接在 /etc/ros 复制 python_logging.conf。更稳妥的顺序是先记录当前解析位置:

printf 'ROS_HOME=%s\n' "${ROS_HOME:-$HOME/.ros}"
test -r /opt/ros/noetic/etc/ros/python_logging.conf
find "${ROS_HOME:-$HOME/.ros}" -maxdepth 2 -type f -name '*logging*.conf' -print 2>/dev/null

然后结合启动日志确认它究竟请求哪个路径、由哪个用户运行、是否是环境变量或权限问题。只有确认发行版规范和目标路径后才复制配置,并保留回滚;不能把创建 /etc/ros 当成所有 logging warning 的答案。

GeographicLib 数据下载慢、PX4 子模块缺失等问题依赖具体 PX4 提交。优先使用该提交自带的安装脚本或文档并核对下载文件;不要从第三方帖子复制镜像 URL 后直接覆盖系统数据集。

8. 不建议沿用的做法

  • 第三方 HTTP 一键安装脚本;
  • 故障日志中的个人主目录已泛化;工程路径只作为上下文,不写成可移植配置;
  • 覆盖 /opt/ros、硬编码本机 OpenCV 动态库的步骤;
  • 未经证实的“装某个包即可”结论;
  • 与特定实验机器绑定的 CUDA 架构和删除命令;
  • 旧截图和身份页脚。

保留下来的重点是故障分层:shell 环境 → 依赖 → 构建 → ROS 图 → 坐标/时间/ABI。

9. 版本化资料入口

旧 CSDN/Cnblogs 错误链接不再作为解决方案正文,但错误字符串和案例已经保留,便于按锁定版本继续检索。

参考资料与书签

以下 14 条只用于锁定旧 ROS1/PX4 工程时检索。ROS Noetic 已 EOL,第三方一键脚本和跨版本包安装尤其不能直接执行;先核对发行版、仓库提交、脚本内容、HTTPS、依赖和可回滚镜像。