高通 Follow Me 跟随机器人踩坑实录:从编译失败到机器人不动,如何逐层排查 ROS 2 + YOLO + Re-ID + RGB-D + PID

上一篇我们基于 Qualcomm qrb_ros_samples中的 sample_followme 搭建了一套人物跟随机器人:

RGB Camera
    ↓
YOLOv8
    ↓
Person Detection
    ↓
Re-ID
    ↓
Depth
    ↓
Distance + Angle
    ↓
PID
    ↓
/cmd_vel
    ↓
Robot Base

架构看起来非常清晰。

真正开始部署以后,却很容易遇到这样的情况:

colcon build 成功
但是找不到 person_tracker_node

YOLO 已经检测到人
但是机器人就是不初始化

RGB 有数据
Depth 也有数据
Tracker 却完全没反应

/cmd_vel 明明有输出
机器人就是不走

机器人终于开始走了
结果左右疯狂摇头

跟了十几秒
突然开始跟另一个人

这种系统最忌讳的调试方式就是:

看到机器人不动,就开始到处改 PID、改 YOLO、重装 ROS。

Follow Me 本质上是一条串联系统。

真正高效的排障方法只有一个:

从数据源开始,沿数据流逐层检查,找到第一处断点。


01 先建立正确的排障思路

我们先不要看任何具体报错。

Follow Me 可以按照故障域拆成 8 层:

L1
Build

L2
Camera

L3
YOLO

L4
Sync

L5
Re-ID

L6
Tracking

L7
PID / cmd_vel

L8
Robot Base

对应关系:

层级负责内容常见故障
L1 Build编译/依赖executable 不存在
L2 CameraRGB + Depth没图、没深度、时间戳异常
L3 YOLOPerson Detection没有 /yolo_detect_result
L4 Sync三路数据同步每个 Topic 都有,Callback 不触发
L5 Re-ID人物身份Service 不存在、匹配失败
L6 Tracking目标初始化人看得见但锁不上
L7 ControlPID抖动、方向反、速度异常
L8 Base底盘/cmd_vel 有但车不走

因此排障原则应该始终是:

Build
 ↓
Sensor
 ↓
Detection
 ↓
Synchronization
 ↓
Re-ID
 ↓
Target
 ↓
Control
 ↓
Base

前一层没有通过,不要调后一层。


02 第一件事不是改代码,而是冻结版本

Qualcomm qrb_ros_samples 当前明确说明 main 是持续开发分支,稳定版本应优先参考 jazzy-rel。因此如果直接长期追踪 main,某天重新拉取后出现行为变化并不奇怪。

项目开始时建议立刻记录:

cd ~/qrb_ws/src/qrb_ros_samples

git branch --show-current

git rev-parse HEAD

保存:

git rev-parse HEAD > BUILD_COMMIT.txt

再记录:

echo $ROS_DISTRO

uname -a

lsb_release -a

完整保存:

{
    echo "===== Git ====="
    git rev-parse HEAD

    echo "===== ROS ====="
    echo "$ROS_DISTRO"

    echo "===== Kernel ====="
    uname -a

    echo "===== OS ====="
    lsb_release -a
} > environment_snapshot.txt

以后如果出现:

同样的板子
同样的命令
之前能跑
现在不能跑

至少可以先回答:

软件版本到底是不是“同样的”。


03 故障 1:编译成功,但找不到 person_tracker_node

这是当前源码里最值得记录的一个坑。

现象

执行:

colcon build

没有明显报错。

加载:

source install/setup.bash

再执行:

ros2 pkg executables follow_me

结果:

没有 person_tracker_node

或者:

ros2 launch follow_me person_tracking.launch.py

提示:

executable 'person_tracker_node' not found

第一步:确认源码到底有没有

ls \
~/qrb_ws/src/qrb_ros_samples/robotics/sample_followme/src/

可以看到:

person_tracker_node.cpp
template_pool.cpp
pid_controller.cpp
depth_processor.cpp
state_machine.cpp

所以不是:

源码没下载完整

第二步:检查 CMake

打开:

grep -n \
"person_tracker_node" \
~/qrb_ws/src/qrb_ros_samples/robotics/sample_followme/CMakeLists.txt

问题就出来了。

当前 main 分支里:

# find_package(qrb_ros_people_reid REQUIRED)

以及整个:

# add_executable(person_tracker_node ...)

编译块都是注释状态;package.xmlqrb_ros_people_reid 依赖同样被注释。换句话说,源码文件存在,Launch 文件也尝试启动这个 executable,但默认 CMake 并没有把它编译出来。


修复前先检查 Re-ID 依赖

源码中直接:

#include <qrb_ros_people_reid/srv/compute_similarity.hpp>
#include <qrb_ros_people_reid/srv/extract_feature.hpp>

同时创建:

/extract_feature
/compute_similarity

两个客户端。

所以不要直接把 CMake 注释全部取消。

先检查:

ros2 pkg prefix qrb_ros_people_reid

如果能够找到:

/opt/ros/jazzy/...

或者你的 Workspace 路径,再继续。

如果得到:

Package 'qrb_ros_people_reid' not found

当前问题属于:

依赖缺失

而不是:

Follow Me 编译问题

先准备与当前 Qualcomm Robotics 软件环境匹配的 Re-ID Package。


修复 CMake

确认依赖已经存在后:

find_package(qrb_ros_people_reid REQUIRED)

恢复:

add_executable(person_tracker_node
  src/person_tracker_node.cpp
  src/template_pool.cpp
  src/pid_controller.cpp
  src/depth_processor.cpp
  src/state_machine.cpp
)

ament_target_dependencies(
  person_tracker_node

  rclcpp
  std_msgs
  sensor_msgs
  geometry_msgs
  vision_msgs
  cv_bridge
  image_transport
  message_filters
  qrb_ros_people_reid
)

target_link_libraries(
  person_tracker_node
  ${OpenCV_LIBRARIES}
)

rosidl_get_typesupport_target(
  cpp_typesupport_target
  ${PROJECT_NAME}
  rosidl_typesupport_cpp
)

target_link_libraries(
  person_tracker_node
  "${cpp_typesupport_target}"
)

install(
  TARGETS person_tracker_node
  DESTINATION lib/${PROJECT_NAME}
)

同时在 package.xml 恢复:

<depend>qrb_ros_people_reid</depend>

清理旧构建结果

不要只:

colcon build

建议针对包清一次:

cd ~/qrb_ws

rm -rf \
    build/follow_me \
    install/follow_me

重新:

source /opt/ros/jazzy/setup.bash

colcon build \
    --packages-select follow_me \
    --symlink-install

然后:

source install/setup.bash

验证:

ros2 pkg executables follow_me

应该出现:

follow_me person_tracker_node

这一关通过以后才继续。


04 故障 2:RGB 正常,但 Follow Me 永远不工作

这是第二个很隐蔽的问题。

现象

你能看到:

ros2 topic hz \
    /camera/color/image_raw

有稳定输出。

YOLO 也正常。

但 Tracker:

没有锁人
没有 Visualization
没有 cmd_vel

第一反应:检查 Depth

Follow Me 并不是普通二维目标跟踪。

官方 README 明确要求同时输入:

/camera/color/image_raw
/camera/depth/image_raw
/yolo_detect_result

并且目标初始化还依赖 1.5~3.0m 的实际深度。

执行:

ros2 topic list | grep depth

然后:

ros2 topic hz \
    /camera/depth/image_raw

如果:

WARNING: topic does not appear to be published yet

问题已经找到。


05 一个容易忽略的 Launch 配置冲突

上一篇项目中我们使用:

ros2 launch \
    sample_object_detection \
    launch_with_orbbec_camera.py

看上去:

YOLO
+
Orbbec

都启动了。

但是当前 Launch 文件实际给 Orbbec 的参数包含:

"depth_registration": "false",
"enable_depth": "false",
"enable_point_cloud": "false",

也就是说:

这个 Object Detection 示例本身并不打算提供 Follow Me 所需的 Depth。

同时它的 YOLO Preprocess 明确订阅的是 /camera/color/image_raw

因此如果机械地把:

Object Detection 教程
+
Follow Me 教程

拼起来,很可能就出现:

RGB ✅
YOLO ✅
Depth ❌
Follow Me ❌

更合理的修法

把:

Camera

和:

YOLO

拆开启动。

结构改为:

Orbbec Driver
   │
   ├── RGB
   └── Depth

RGB
 ↓
YOLO

RGB + Depth + YOLO Result
 ↓
Follow Me

也就是:

Orbbec

RGB

Depth

YOLO

Follow Me

这样摄像头是否打开 Depth,不再受 Object Detection Demo 的 Launch 配置影响。


06 故障 3:RGB、Depth、YOLO 全都有,但 Tracker 还是没反应

这是最容易让人怀疑人生的一类问题:

ros2 topic hz /camera/color/image_raw

正常。

ros2 topic hz /camera/depth/image_raw

正常。

ros2 topic hz /yolo_detect_result

也正常。

但是:

person_tracker_node

就是没有进入正常处理。

这时候先不要动 Re-ID。


根因:三路消息没有同步成功

当前源码不是三个普通 Subscriber。

而是:

message_filters::Synchronizer<SyncPolicy>

把:

RGB
+
Depth
+
Detection

三个消息匹配成同一组数据后,才调用:

syncCallback(...)

当前 Synchronizer Queue 设置为 100,同时代码实际执行:

sync_->setMaxIntervalDuration(
    rclcpp::Duration::from_seconds(0.01)
);

也就是最大时间窗口约:

10 ms

值得注意的是,紧接着的日志文字却写着 queue_size=20, max_interval=0.5s,与真正设置值并不一致,因此调试时应该相信实际构造和参数,而不是单看日志输出。


为什么 YOLO 特别容易导致错位

Camera 采集:

t = 10.000

经过:

Resize
↓
Tensor
↓
QNN
↓
YOLO Postprocess

Detection 出来的时候,现实时间可能已经:

t = 10.040

甚至:

10.100

如果 Detection Header 时间戳又没有正确继承源图像时间:

RGB   10.000
Depth 10.004
YOLO  10.061

而同步窗口只有:

0.010s

那就永远凑不出一组。


怎么确认是不是同步问题

分别查看:

ros2 topic echo \
    /camera/color/image_raw \
    --field header
ros2 topic echo \
    /camera/depth/image_raw \
    --field header
ros2 topic echo \
    /yolo_detect_result \
    --field header

不要比较你看到消息的时间。

比较:

header.stamp

临时扩大同步窗口

调试阶段可以尝试:

sync_->setMaxIntervalDuration(
    rclcpp::Duration::from_seconds(
        0.05
    )
);

也就是:

50 ms

如果仍然无法匹配,再结合实测时间戳调整。

但不要简单写:

1.0s

因为过大的窗口可能把:

旧 YOLO BBox
+
新 RGB
+
新 Depth

错误地组合。

结果就是:

人明明站在这里,Depth 却在读取半秒前另一个位置。


07 故障 4:Depth 有数据,但是距离明显不对

典型表现:

真实距离:2m
系统显示:7m

或者

真实距离:3m
系统显示:0.4m

第一反应通常是:

Depth Camera 不准

其实未必。


先理解源码怎么取 Depth

当前实现先根据 RGB 图像尺寸和 Depth 图像尺寸计算:

scale_x = depth_width / rgb_width
scale_y = depth_height / rgb_height

然后把 RGB Bounding Box 按比例映射到 Depth Image,再读取整个区域里的有效深度并取中位数;16UC1 按毫米转成米,32FC1 按米直接读取,并过滤 0.1~10m 之外的值。

也就是说:

RGB BBox
   ↓
尺寸缩放
   ↓
Depth BBox

这是一个重要前提:

RGB 与 Depth 必须在空间上基本对齐。


如果没有 RGB-D Registration

你在 RGB 看到:

┌───────────┐
│  Person   │
└───────────┘

但是 Depth 中人物实际上偏了几十个像素:

               ┌───────────┐
               │  Person   │
               └───────────┘

那么代码按照 RGB BBox 去 Depth 中取值时,可能读到:

背景墙
地面
桌子

最后 Median 再稳定,也只是:

非常稳定地得到错误距离。


怎么快速确认

建议先做可视化:

RGB BBox
   ↓
映射到 Depth
   ↓
把映射区域画出来

调试代码可以临时加入:

cv::rectangle(
    depth_debug_image,
    cv::Point(x1, y1),
    cv::Point(x2, y2),
    cv::Scalar(255),
    2
);

然后对比 RGB 和 Depth 中框的位置。

如果明显错位:

先修 RGB-D Alignment / Registration,不要调 PID。


08 故障 5:Re-ID 服务找不到

现象

节点启动时出现:

service not available

或者:

ros2 service list | grep feature

什么都没有。


Follow Me 实际依赖什么

官方 README 明确把 Re-ID 定义成外部服务,并需要:

/extract_feature
/compute_similarity

两个接口。

源码里同样直接创建:

/extract_feature

/compute_similarity

客户端。

首先:

ros2 service list | grep -E \
"extract_feature|compute_similarity"

如果没有:

先修 Re-ID Service

而不是:

改 Tracker

再看节点和 Package

ros2 pkg prefix \
    qrb_ros_people_reid

如果存在:

ros2 node list

找到对应 Re-ID 节点。

然后:

ros2 service type \
    /extract_feature

以及:

ros2 service type \
    /compute_similarity

确保服务类型与 Follow Me 使用的接口完全一致。


09 故障 6:YOLO 看到了 person,但机器人死活不锁定

这是最常见的:

“所有东西都正常,就是不开始跟。”

先不要怀疑 Re-ID。

目标初始化本身就设置了很严格的条件。


当前初始化条件

源码会把图像中央:

宽度 25% ~ 75%
高度 25% ~ 75%

定义为中心区域。

只有 Person Bounding Box 中心点位于这个区域,并且 Depth 处于:

1.5m ~ 3.0m

之间,才会成为 Candidate。

最后还要求:

Candidate 数量必须恰好 = 1

否则不会初始化。


所以以下情况全部不会开始 Follow

人离机器人 4m

不会。

人距离 1m

不会。

人在画面最左侧

不会。

画面中央站了两个人

也不会。


开 DEBUG 日志

执行:

ros2 launch follow_me \
    person_tracking.launch.py \
    use_sim_time:=false \
    log_level:=DEBUG

你可能直接看到:

Target is not in the center region

或者:

Distance is (...), not initialize.

或者:

Multiple candidates (...) in center region

这些正是源码已有的判断。


正确测试姿势

第一次测试时:

空旷场地

仅一人

站机器人正前方

距离约 2m

保持几秒

比一群人围着机器人测试靠谱得多。


10 故障 7:机器人一开始跟对了,后来开始跟错人

这通常属于:

Re-ID / Template 漂移

问题。


当前 Re-ID 并不是只保存一个模板

源码中存在:

Initial Template
+
Latest Template

当前候选人物先按照与上一帧 Bounding Box 的 IoU 从大到小排序,再提取 Feature,与 Initial 和 Latest Template 进行比较。匹配成功后才更新当前目标。

模板逻辑大致是:

Initial
长期身份锚点

Latest
适应近期外观变化

一个特别容易误解的问题:similarity 越小越匹配

README 把接口称为:

ComputeSimilarity

但当前 Follow Me 的实际判断是:

similarity <= match_threshold

而模板更新也是:

similarity <= update_threshold

漂移判断则是:

similarity > drift_threshold

也就是说,从当前 Tracker 的使用方式看,这个返回值的行为更接近:

distance

即:

越小越相似

而不是传统意义上:

cosine similarity 越大越相似

这一点从当前 TemplatePool 实现可以直接看到。


为什么换 Re-ID 模型后特别容易出错

假设你自己实现:

score = cosine_similarity(a, b)

得到:

0.95 = 非常像
0.10 = 很不像

但 Follow Me 原逻辑仍然:

if (score <= 0.3) {
    matched = true;
}

那结果就彻底反了:

不像的人 → MATCH
很像的人 → Reject

换模型后必须先做分数标定

在真正接机器人前,先收:

同一个人 100 对
不同人 100 对

统计:

Same Person Score Distribution

Different Person Score Distribution

例如:

同一个人:
0.05 ~ 0.21

不同人:
0.48 ~ 0.93

再设置:

template_update_threshold: 0.10
match_threshold: 0.30
drift_threshold: 0.60

而不是直接照抄默认参数。


11 故障 8:有 /cmd_vel,但机器人不动

这个问题要先区分:

控制算法有没有算速度

和:

底盘有没有收到它能理解的速度

是两件事。


查看 Follow Me 输出类型

当前 README 和源码中,Follow Me 的 /cmd_vel 类型都是:

geometry_msgs/msg/TwistStamped

源码实际发布的也是:

geometry_msgs::msg::TwistStamped

并把:

linear.x
angular.z

写入其中。

检查:

ros2 topic type /cmd_vel

再检查 Robot Base 需要什么

当前 Qualcomm qrb_ros_robot_base 文档定义的 /cmd_vel 订阅类型为:

geometry_msgs::msg::Twist

而不是 TwistStamped

这意味着可能出现:

Follow Me:

/cmd_vel
TwistStamped
       ↓
       X

Robot Base:

/cmd_vel
Twist

Topic 名完全一样,

消息类型却不一样。

ROS 不会自动帮你转换。


ros2 topic info 一眼确认

ros2 topic info /cmd_vel -v

重点看:

Type

Publisher

Subscriber

如果看到:

Publisher:
TwistStamped

Subscriber:
Twist

已经找到根因。


推荐加一个 Adapter

不要为了适配某一个底盘,把 Follow Me 主逻辑改得乱七八糟。

例如让 Follow Me:

/follow_me/cmd_vel
TwistStamped

然后:

Adapter

转换成:

/cmd_vel
Twist

Python:

import rclpy

from rclpy.node import Node

from geometry_msgs.msg import (
    Twist,
    TwistStamped,
)


class CmdVelAdapter(Node):

    def __init__(self):

        super().__init__(
            "cmd_vel_adapter"
        )

        self.publisher = (
            self.create_publisher(
                Twist,
                "/cmd_vel",
                10,
            )
        )

        self.subscription = (
            self.create_subscription(
                TwistStamped,
                "/follow_me/cmd_vel",
                self.callback,
                10,
            )
        )

    def callback(self, msg):

        cmd = Twist()

        cmd.linear.x = (
            msg.twist.linear.x
        )

        cmd.angular.z = (
            msg.twist.angular.z
        )

        self.publisher.publish(cmd)


def main():

    rclpy.init()

    node = CmdVelAdapter()

    rclpy.spin(node)

    node.destroy_node()

    rclpy.shutdown()


if __name__ == "__main__":
    main()

接口关系变成:

Follow Me
TwistStamped
     ↓
Adapter
     ↓
Twist
     ↓
Robot Base

干净得多。


12 故障 9:机器人终于动了,但疯狂左右摇摆

终于来到 PID。

注意:

PID 应该是排障链的倒数第二层,而不是第一层。

如果:

Depth 都是错的

你怎么调 PID 都没意义。


当前控制逻辑

距离误差:

distance_error
=
current_distance
-
target_distance

角度误差:

angle_error
=
target_angle

当前源码使用两个独立 PID,并对速度进行上下限限制;角速度控制特别取 -angle_error,因为 ROS 中正角速度表示左转,而画面右侧目标对应正图像角误差。

默认配置为:

linear_kp: 0.5
linear_ki: 0.0
linear_kd: 0.1

angular_kp: 2.0
angular_ki: 0.0
angular_kd: 0.2

max_linear_speed: 0.5
max_angular_speed: 0.5

左右摆动

表现:

← → ← → ← → ← →

优先:

降低 angular_kp

例如先:

angular_kp: 1.0

同时考虑:

angular_kd: 0.25

建议增加角度死区

例如:

constexpr double ANGLE_DEAD_ZONE =
    3.0 * M_PI / 180.0;

if (
    std::abs(angle_error)
    < ANGLE_DEAD_ZONE
) {
    angle_error = 0.0;
}

这样人在:

±3°

之内时,不需要机器人持续:

左一点
右一点
左一点
右一点

13 故障 10:机器人在 2 米附近不断前后抽动

原理相同。

例如:

1.97m
→ 后退

2.02m
→ 前进

1.98m
→ 后退

一直切换。

建议:

constexpr double DISTANCE_DEAD_ZONE =
    0.08;

if (
    std::abs(distance_error)
    < DISTANCE_DEAD_ZONE
) {
    distance_error = 0.0;
}

也就是:

1.92m ~ 2.08m

都认为:

够近了,不动。

14 故障 11:机器人偶尔突然“抽一下”

这时候要检查:

dt

当前 PID 导数项:

(error - previous_error) / dt

而源码中的 dt 根据两次处理帧时间计算。

如果:

某次处理:
dt = 0.1s

下一次:
dt = 0.005s

同样的误差变化除以非常小的 dt

Derivative

会突然非常大。


建议增加 dt 保护

dt = std::clamp(
    dt,
    0.02,
    0.30
);

避免:

极小 dt

造成微分项尖峰。


15 故障 12:目标突然消失后机器人还在移动?

这个必须当作安全问题,而不是普通 Bug。

当前源码在:

Detection 为空

或:

Re-ID 匹配失败

时会调用:

stopRobot()

将线速度和角速度都设置为 0。

所以如果实际机器人:

目标丢失后还继续走

建议立即检查:

ros2 topic echo /cmd_vel

分两种情况。

情况 A:Follow Me 已经输出 0

linear = 0
angular = 0

但机器人继续走。

那么问题在:

Robot Base
控制器
通信延迟
底盘 Watchdog

情况 B:Follow Me 仍输出非零

才继续查:

Tracker State
Re-ID
Detection
Callback

这两种问题不能混在一起。


16 最有用的排障泳道图

真正现场调试,可以直接按照下面这张图。

Robot Base PID Tracker Re-ID Synchronizer YOLO Camera Robot Base PID Tracker Re-ID Synchronizer YOLO Camera RGB 有吗? Depth 有吗? RGB person 有吗? RGB + Depth Detection 时间戳匹配吗? 同步帧 Candidate = 1? Extract Feature Feature Compute Similarity Score Target Match? Distance + Angle PID cmd_vel 消息类型一致? 机器人运动

一旦卡住:

就停在当前泳道,不要继续向后查。


17 一键健康检查脚本

项目实际调试时,我更建议准备一个:

followme_doctor.sh

而不是每次手敲十几个命令。

#!/usr/bin/env bash

echo "================================="
echo " Follow Me System Health Checker "
echo "================================="

echo
echo "[1] Environment"
echo "ROS_DISTRO=${ROS_DISTRO:-NOT_SET}"
echo "ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-NOT_SET}"

echo
echo "[2] Package"

if ros2 pkg prefix follow_me \
    >/dev/null 2>&1; then

    echo "[OK] follow_me"

else

    echo "[MISS] follow_me"
fi

echo
echo "[3] Executable"

if ros2 pkg executables follow_me \
    | grep -q person_tracker_node; then

    echo "[OK] person_tracker_node"

else

    echo "[MISS] person_tracker_node"
fi

echo
echo "[4] Camera"

TOPICS="$(ros2 topic list)"

check_topic () {

    if echo "$TOPICS" \
        | grep -qx "$1"; then

        echo "[OK] $1"

    else

        echo "[MISS] $1"
    fi
}

check_topic \
    "/camera/color/image_raw"

check_topic \
    "/camera/depth/image_raw"

check_topic \
    "/camera/color/camera_info"

echo
echo "[5] YOLO"

check_topic \
    "/yolo_detect_result"

echo
echo "[6] Re-ID Services"

SERVICES="$(ros2 service list)"

for srv in \
    /extract_feature \
    /compute_similarity
do

    if echo "$SERVICES" \
        | grep -qx "$srv"; then

        echo "[OK] $srv"

    else

        echo "[MISS] $srv"
    fi

done

echo
echo "[7] Follow Me"

check_topic \
    "/target_visualization"

check_topic \
    "/cmd_vel"

echo
echo "[8] cmd_vel Type"

ros2 topic type \
    /cmd_vel \
    2>/dev/null || true

echo
echo "================================="
echo " Finished"
echo "================================="

运行:

chmod +x followme_doctor.sh

./followme_doctor.sh

比起:

机器人不工作

这个脚本至少会快速把问题缩小成:

Build
Camera
YOLO
Re-ID
Tracker
Control

中的一层。


18 最终完整排障决策树

Follow Me 不工作

person_tracker_node 存在?

修 CMake / Re-ID Dependency

RGB 有数据?

检查 Camera

Depth 有数据?

检查 enable_depth

YOLO 有 person?

检查 Model / QNN / Threshold

三路时间戳接近?

修 Timestamp / Sync Window

Re-ID Service 存在?

修 qrb_ros_people_reid

Target 初始化?

检查中心区域 / 1.5~3m / Candidate 数

Re-ID Match?

检查 Feature / Threshold / Score 方向

有 cmd_vel?

检查 Depth / Angle / PID

cmd_vel Type 匹配?

TwistStamped → Twist Adapter

机器人运动正常?

检查 Robot Base / Control Mode

运动稳定?

PID / Dead Zone / dt 调优

FOLLOW ME PASS

这张图基本可以作为整个项目的现场排障手册。


19 推荐的最终验收矩阵

不要以:

机器人跟过一次人

作为项目完成标准。

建议至少覆盖:

测试操作预期
Camera检查 RGB稳定输出
Depth2m 目标测试距离基本正确
YOLO人进入画面检测 person
Sync连续运行Callback 稳定
Init单人中央 2m成功锁定
Reject两人中央不初始化
Re-ID第二人经过保持原目标
Occlusion短暂遮挡停止/恢复目标
Distance人后退Robot 前进
Angle人向左Robot 左转
Stop人消失速度归零
Pause调用 Pause立即停车
Finish调用 Finish停车并清除 Target
Interface检查 cmd_velPublisher/Subscriber 类型一致
Stability连续跟随无明显左右/前后震荡

20 最后再总结一次:不要“猜 Bug”

这次 Follow Me 部署过程中最有价值的并不是解决某一个:

enable_depth=false

或者:

TwistStamped != Twist

的问题。

真正值得留下来的,是这套工程排障方法。

以后不管面对:

SLAM
Nav2
机械臂
VLM
视觉检测
语音
机器人 Agent

都可以使用同样的方法:

定义完整数据流
       ↓
找到系统边界
       ↓
给每层定义输入和输出
       ↓
从最上游逐层验证
       ↓
找到第一个异常节点
       ↓
只解决这一层
       ↓
重新验证
       ↓
再继续向下

而不是:

机器人不动
       ↓
改 PID

还不动
       ↓
换模型

还不动
       ↓
重装 ROS

还不动
       ↓
开始怀疑硬件

对于这次 Qualcomm Follow Me 来说,最终完整排障路径就是:

源码是否真正编译
        ↓
RGB 是否正常
        ↓
Depth 是否正常
        ↓
YOLO 是否检测 Person
        ↓
RGB / Depth / Detection 是否同步
        ↓
Re-ID Service 是否存在
        ↓
目标是否满足初始化条件
        ↓
Re-ID 是否正确匹配
        ↓
距离和方向是否正确
        ↓
PID 是否产生合理速度
        ↓
cmd_vel 类型是否与底盘匹配
        ↓
真实机器人是否正确执行

只要按照这条链排查,一个原本看起来像“整个系统都坏了”的问题,最终通常都能被缩小成一个非常具体的点:

一条 Topic
一个 Timestamp
一个 Launch 参数
一个依赖
一个消息类型
或者一个阈值。

这才是机器人复杂系统真正高效的排错方式。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐