ROS2 人体追踪功能包:将 LiDAR 点云投影到相机图像,在 YOLO11 检测框内采样深度,估算目标 3D 位置与速度。
LiDAR ─────────────────────────────────────────────────────┐
PointCloud2 │
▼
RGB Camera ──► YOLO11 tracker ──► 2D bboxes ──► PositionEstimator ──► 3D pos / vel
Image (track IDs) (depth sampling)
│
DepthProjector
(lidar → image plane)
每帧处理流程(YOLO 与点云投影并行执行):
-
点云投影(
DepthProjector)
将 LiDAR 坐标系点云经外参矩阵lidar_to_camera变换到相机坐标系,再通过内参K+ 畸变系数投影到像素平面,得到稀疏深度图Nx6 [u, v, depth_cam, xl, yl, zl]。 -
YOLO 追踪(
YoloTracker)
YOLO11 仅检测class=0(person),persist=True保持跨帧稳定 track ID。 -
3D 位置估算(
PositionEstimator)
对每个 YOLO 框:- 筛选投影坐标落在框内的点;
- 前景截取:
depth <= d_min + depth_window(默认 0.8 m),排除背景; - 对前景点在 LiDAR 坐标系下取均值,得到 3D 质心。
-
速度估算(
TrackManager)
维护每个 track ID 的位置历史(默认 5 帧),用首尾差分Δpos / Δt估算速度向量(m/s)。超过 1 秒未更新的 ID 自动清除。
rclpy sensor_msgs geometry_msgs visualization_msgs
std_msgs cv_bridge message_filters
| 库 | 用途 |
|---|---|
ultralytics |
YOLO11 推理 |
opencv-python |
图像处理、投影 |
numpy |
向量化点云解析 |
注意:本包不依赖
sensor_msgs_py,点云解析通过np.frombuffer向量化实现。
默认路径为 /home/jiewang/ros2_ws/src/human_tracking_3d/models/yolo11s.pt,可在 params.yaml 中修改 yolo_model 字段。首次运行如无本地模型,ultralytics 会自动下载。
cd /home/jiewang/ros2_ws
colcon build --packages-select human_tracking_depth
source install/setup.bash配置文件:config/params.yaml
human_tracking_depth_node:
ros__parameters:
# ── 话题 ──────────────────────────────────────────────────────────────────
image_topic: "/camera/camera/color/image_raw"
pointcloud_topic: "/livox/lidar"
# ── 相机内参(RealSense D435 @ 1280×720) ─────────────────────────────────
camera_fx: 909.783
camera_fy: 909.004
camera_cx: 650.365
camera_cy: 381.295
image_width: 1280
image_height: 720
# 畸变系数 [k1, k2, p1, p2, k3](无畸变填零)
dist_coeffs: [0.0, 0.0, 0.0, 0.0, 0.0]
# ── LiDAR 到相机外参(行优先 4×4 齐次矩阵) ───────────────────────────────
lidar_to_camera: [
0.0, -1.0, 0.0, 0.0,
0.0, 0.0,-1.0, 0.0,
1.0, 0.0, 0.0, -0.05,
0.0, 0.0, 0.0, 1.0
]
# ── YOLO ──────────────────────────────────────────────────────────────────
yolo_model: "/path/to/yolo11s.pt"
yolo_conf: 0.5
# yolo_device:
# "" → ultralytics 自动选择(有 GPU 时优先使用)
# "cpu" → 强制 CPU 推理(避免与其他节点抢 VRAM)
# "0" → 强制 GPU 0
yolo_device: ""
# ── 点云空间滤波 ────────────────────────────────────────────────────────────
pc_z_min: -1.0 # LiDAR 坐标系 Z 轴下界(m)
pc_z_max: 2.0 # LiDAR 坐标系 Z 轴上界(m)
pc_range_max: 15.0 # XY 平面最大水平距离(m)
# ── 3D 位置估算 ─────────────────────────────────────────────────────────────
min_lidar_points: 3 # bbox 内至少需要的投影点数
depth_window: 0.8 # 前景深度带宽(m,从最近点开始)
# ── 速度估算 ────────────────────────────────────────────────────────────────
velocity_history: 5 # 每个 track 保留的位置历史帧数相机内参:可从 camera_info 话题读取,或使用 camera_calibration 工具标定。
ros2 topic echo /camera/camera/color/camera_info --once
# 从 K 矩阵提取:[fx,0,cx,0,fy,cy,0,0,1]LiDAR-Camera 外参:lidar_to_camera 是将 LiDAR 坐标系点变换到相机坐标系的 4×4 矩阵 T_cam_lidar,满足:
p_camera = T_cam_lidar · p_lidar
可通过手动量取安装偏移、或使用标定板联合标定工具(如 lidar_camera_calibration)获得。
ros2 launch human_tracking_depth human_tracking_depth.launch.pyros2 launch human_tracking_depth human_tracking_depth.launch.py \
image_topic:=/camera/color/image_raw \
pointcloud_topic:=/velodyne_pointsros2 launch human_tracking_depth human_tracking_depth.launch.py \
params_file:=/path/to/my_params.yamlros2 run human_tracking_depth human_tracking_depth_node \
--ros-args --params-file /home/jiewang/ros2_ws/src/human_tracking_depth/config/params.yaml| 话题 | 类型 | 说明 |
|---|---|---|
human_tracking_depth/depth_image |
sensor_msgs/Image |
相机图像叠加 Jet 着色深度点(近→远:蓝→红) |
human_tracking_depth/detection_image |
sensor_msgs/Image |
YOLO 检测框 + 3D 位置/速度文字标注 |
human_tracking_depth/projected_cloud |
sensor_msgs/PointCloud2 |
能投影到图像内的 LiDAR 点,按深度着色(XYZRGB) |
human_tracking_depth/markers |
visualization_msgs/MarkerArray |
球体、文字标签、速度箭头(LiDAR 坐标系) |
每个追踪目标最多 3 个 Marker(namespace / ID 唯一):
| namespace | 类型 | 内容 |
|---|---|---|
human_pos |
SPHERE (0.3 m) | 3D 质心球 |
human_label |
TEXT_VIEW_FACING | ID:N\n(x, y, z) m\nV m/s |
human_vel |
ARROW | 速度方向箭头(速度 > 0.05 m/s 时显示) |
启动 RViz2:
rviz2添加以下显示项(Add → By topic):
| 话题 | Plugin | 备注 |
|---|---|---|
/human_tracking_depth/depth_image |
Image | 深度叠加图 |
/human_tracking_depth/detection_image |
Image | YOLO 检测框 + 3D 标注 |
/human_tracking_depth/projected_cloud |
PointCloud2 | 设置 Color Transformer = RGB8 |
/human_tracking_depth/markers |
MarkerArray | 3D 球/文字/箭头 |
Fixed Frame:设置为 LiDAR 的 frame_id(通常为 livox_frame 或 lidar_link),与 pc_msg.header.frame_id 一致。
# 查看话题频率
ros2 topic hz /camera/camera/color/image_raw
ros2 topic hz /livox/lidar
# 若频率差异较大(>5倍),考虑增大 slop 参数(代码中 ApproximateTimeSynchronizer slop=0.2)订阅 depth_image 话题,观察相机图中的投影点:
- 点应落在物体表面,不应出现系统性偏移
- 若所有点偏移方向一致 →
lidar_to_camera平移部分有误 - 若点呈旋转错位 →
lidar_to_camera旋转部分有误
ros2 run rqt_image_view rqt_image_view
# 选择 /human_tracking_depth/depth_imageros2 topic echo /human_tracking_depth/markers --field markers[0].text
# 应输出类似:ID:1\n(2.30, 0.10, 0.05) m\n0.00 m/s若 3D 位置异常:
pos_3d坐标在 LiDAR 坐标系下,Z 轴朝上(通常)- 检查
min_lidar_points:若目标遮挡严重,可降低至 1~2 - 检查
depth_window:若目标前后有障碍物,可缩小至 0.3~0.5 m
ros2 topic echo /human_tracking_depth/detection_image --no-arr | grep -c header
# 每帧打印一次,确认节点在运行查看节点日志(含 YOLO 加载信息):
ros2 run human_tracking_depth human_tracking_depth_node \
--ros-args --log-level DEBUG若 markers 更新缓慢或消失,通常是时间戳不匹配导致 ApproximateTimeSynchronizer 无法配对:
ros2 topic echo /camera/camera/color/image_raw --field header.stamp --no-arr
ros2 topic echo /livox/lidar --field header.stamp --no-arr两者时间戳差值应 < 0.2 s(slop 值)。
检查订阅话题是否匹配:
ros2 topic list | grep -E "image_raw|lidar"
# 确认与 params.yaml 中的 image_topic / pointcloud_topic 一致将 yolo_device 改为 "cpu":
yolo_device: "cpu"或同时运行其他 GPU 节点时,设置 yolo_device: "1" 指定另一块 GPU。
- 确认
pc_range_max覆盖目标距离(默认 15 m) - 确认
pc_z_min/pc_z_max包含 LiDAR 安装高度范围 - 检查
lidar_to_camera旋转矩阵是否正确(行列顺序、坐标轴方向)
快速验证旋转:以 LiDAR 前方 2 m、正中央一点 [2, 0, 0] 为例,手算变换后相机 Z > 0 且 u/v 应在图像中央附近。
增大 velocity_history(默认 5,可调到 8~10),或在 TrackManager 中对速度向量做指数滑动平均(EMA)。
Marker 使用 pc_msg.header.frame_id(LiDAR 原始坐标系)。确保 RViz2 的 Fixed Frame 设置为相同 frame id,并且 TF 树中有对应变换。
所有模块文件顶部需要:
from __future__ import annotations编译后重新 source install/setup.bash。
human_tracking_depth/
├── config/
│ └── params.yaml # 所有可调参数
├── human_tracking_depth/
│ ├── __init__.py
│ ├── human_tracking_depth_node.py # 主节点(订阅/发布/协调)
│ ├── depth_projector.py # LiDAR → 图像平面投影
│ ├── position_estimator.py # bbox 内深度采样 → 3D 质心
│ ├── yolo_tracker.py # YOLO11 追踪封装
│ └── track_manager.py # 速度估算 + ID 生命周期管理
├── launch/
│ └── human_tracking_depth.launch.py
├── package.xml
└── setup.py