sl-perception c620dc51a7 feat: Add Issue #363 — P0 person tracking for follow-me mode
Implements real-time person detection + tracking pipeline for the
follow-me motion controller on Jetson Orin Nano Super (D435i).

Core components
- TargetTrack.msg: bearing_deg, distance_m, confidence, bbox, vel_bearing_dps,
  vel_dist_mps, depth_quality (0-3)
- _person_tracker.py (pure-Python, no ROS2/runtime deps):
  · 8-state constant-velocity Kalman filter [cx,cy,w,h,vcx,vcy,vw,vh]
  · Greedy IoU data association
  · HSV torso colour histogram re-ID (16H×8S, Bhattacharyya similarity)
    with fixed saturation clamping (s = (cmax−cmin)/cmax, clipped to [0,1])
  · FollowTargetSelector: nearest person auto-lock, hold_frames hysteresis
  · TENTATIVE→ACTIVE after min_hits; LOST track removal after max_lost_frames
    with per-frame lost_age increment across all LOST tracks
  · bearing_from_pixel, depth_at_bbox (median, quality flags)
- person_tracking_node.py:
  · YOLOv8n via ultralytics (TRT FP16 on first run) → HOG+SVM fallback
  · Subscribes colour + depth + camera_info + follow_start/stop
  · Publishes /saltybot/target_track at ≤30 fps
- test/test_person_tracker.py: 59/59 tests passing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:19:02 -05:00

69 lines
3.4 KiB
Python

from setuptools import setup
import os
from glob import glob
package_name = 'saltybot_bringup'
setup(
name=package_name,
version='0.1.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'),
glob('launch/*.launch.py')),
(os.path.join('share', package_name, 'config'),
glob('config/*.yaml')),
(os.path.join('share', package_name, 'behavior_trees'),
glob('behavior_trees/*.xml')),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='sl-perception',
maintainer_email='sl-perception@saltylab.local',
description='SaltyBot sensor bringup and SLAM launch files',
license='MIT',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'depth_confidence_filter = saltybot_bringup.depth_confidence_filter_node:main',
'camera_health_monitor = saltybot_bringup.camera_health_node:main',
'scan_height_filter = saltybot_bringup.scan_height_filter_node:main',
# LIDAR object clustering + RViz visualisation (Issue #239)
'lidar_clustering = saltybot_bringup.lidar_clustering_node:main',
# Floor surface type classifier (Issue #249)
'floor_classifier = saltybot_bringup.floor_classifier_node:main',
# Visual odometry drift detector (Issue #260)
'vo_drift_detector = saltybot_bringup.vo_drift_node:main',
# Depth image hole filler (Issue #268)
'depth_hole_fill = saltybot_bringup.depth_hole_fill_node:main',
# HSV color object segmenter (Issue #274)
'color_segmenter = saltybot_bringup.color_segment_node:main',
# Motion blur detector (Issue #286)
'blur_detector = saltybot_bringup.blur_detect_node:main',
# Terrain roughness estimator (Issue #296)
'terrain_roughness = saltybot_bringup.terrain_rough_node:main',
# Sky detector for outdoor navigation (Issue #307)
'sky_detector = saltybot_bringup.sky_detect_node:main',
# Wheel encoder differential drive odometry (Issue #184)
'wheel_odom = saltybot_bringup.wheel_odom_node:main',
# Appearance-based person re-identification (Issue #322)
'person_reid = saltybot_bringup.person_reid_node:main',
# Dynamic obstacle velocity estimator (Issue #326)
'obstacle_velocity = saltybot_bringup.obstacle_velocity_node:main',
# Lane/path edge detector (Issue #339)
'path_edges = saltybot_bringup.path_edges_node:main',
# Depth-based obstacle size estimator (Issue #348)
'obstacle_size = saltybot_bringup.obstacle_size_node:main',
# Audio scene classifier (Issue #353)
'audio_scene = saltybot_bringup.audio_scene_node:main',
# Face emotion classifier (Issue #359)
'face_emotion = saltybot_bringup.face_emotion_node:main',
# Person tracking for follow-me mode (Issue #363)
'person_tracking = saltybot_bringup.person_tracking_node:main',
],
},
)