Skip to content

hhanoo/AprilTag_Pose_ROS2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

56 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

AprilTag Pose ROS2

AprilTag ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ 6-DOF ํฌ์ฆˆ ์ถ”์ • ์‹œ์Šคํ…œ

ROS2 C++ Python OpenCV Docker License


๋ชฉ์ฐจ


๋ฐ๋ชจ

ROS2 Graph

Launch_ROS_Graph


๊ฐœ์š”

ํ”„๋กœ์ ํŠธ ๋ชฉ์ 

AprilTag Pose ROS2๋Š” ROS2 ํ˜ธํ™˜ RGB ์นด๋ฉ”๋ผ์™€ AprilTag ๋งˆ์ปค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํƒ€๊ฒŸ ๊ฐ์ฒด์˜ 6์ž์œ ๋„(6-DOF) ์œ„์น˜์™€ ์ž์„ธ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถ”์ •ํ•˜๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ๋‹ค์ค‘ ๋งˆ์ปค ์œตํ•ฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜(Multi-tag PnP)์„ ์ ์šฉํ•˜์—ฌ ๋‹จ์ผ ๋งˆ์ปค ๋Œ€๋น„ ๋†’์€ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ•˜๋ฉฐ, SLERP ๊ธฐ๋ฐ˜ ์ฟผํ„ฐ๋‹ˆ์–ธ ํ•„ํ„ฐ๋กœ ์•ˆ์ •์ ์ธ ํฌ์ฆˆ ์ถœ๋ ฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ตฌ์„ฑ์š”์†Œ

  • apriltag_pose_estimator (C++): AprilTag ๊ฒ€์ถœ, ๋‹ค์ค‘ ๋งˆ์ปค ํฌ์ฆˆ ์œตํ•ฉ, SLERP ํ•„ํ„ฐ๋ง
  • apriltag_pose_visualizer (Python): ์‹ค์‹œ๊ฐ„ ๊ฒ€์ถœ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™”, Roll/Pitch/Yaw ๊ณ„์‚ฐ, 3D ์‚ฐ์ ๋„
  • apriltag_pose_estimator_msgs (C++): ROS2 ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€ ๋ฐ ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค

์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„๋Š” ๋ณธ ํŒจํ‚ค์ง€์— ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. sensor_msgs/Image + CameraInfo๋ฅผ ํผ๋ธ”๋ฆฌ์‹œํ•˜๋Š” ROS2 ์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ๋ณ„๋„๋กœ ์‹คํ–‰ํ•˜์„ธ์š”.

์ ์šฉ ๊ฐ€๋Šฅ ์˜์—ญ

  • ๋กœ๋ด‡ ๋น„์ „ ์‹œ์Šคํ…œ์˜ ๊ฐ์ฒด ์œ„์น˜ ์ถ”์ 
  • ์ž์œจ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์œ„ํ•œ ๊ณต๊ฐ„ ์ธ์‹
  • ์‚ฐ์—… ์ž๋™ํ™” ์‹œ์Šคํ…œ์˜ ์ •๋ฐ€ ํฌ์ง€์…”๋‹
  • AR/VR ๋งˆ์ปค ๊ธฐ๋ฐ˜ ์œ„์น˜ ์ถ”์ •
  • ์—ฐ๊ตฌ ๊ฐœ๋ฐœ ๋ฐ ๊ต์œก

์ฃผ์š” ๊ธฐ๋Šฅ

  • ๋‹ค์ค‘ ๋งˆ์ปค PnP ์œตํ•ฉ: ๋ณต์ˆ˜์˜ AprilTag ์ฝ”๋„ˆ๋ฅผ ๋™์‹œ์— ํ™œ์šฉํ•˜์—ฌ ๋‹จ์ผ ๋งˆ์ปค ๋Œ€๋น„ ํ–ฅ์ƒ๋œ 6-DOF ํฌ์ฆˆ ์ถ”์ •
  • SLERP ์ฟผํ„ฐ๋‹ˆ์–ธ ํ•„ํ„ฐ: Gimbal lock ์—†๋Š” ํšŒ์ „ ๋ณด๊ฐ„๊ณผ ์ ์‘ํ˜• EMA๋กœ ํ”„๋ ˆ์ž„ ๊ฐ„ ์ง€ํ„ฐ ์–ต์ œ (์—ฐ์† 5ํ”„๋ ˆ์ž„ ๋ฏธ๊ฒ€์ถœ ์‹œ ์ž๋™ ๋ฆฌ์…‹๋˜์–ด ์žฌ๋“ฑ์žฅ ์‹œ ์˜› pose์™€ ๋ธ”๋ Œ๋”ฉ ๋ฐฉ์ง€)
  • Reprojection Error ๊ธฐ๋ฐ˜ ์ด์ƒ์น˜ ์ œ๊ฑฐ: 15ํ”ฝ์…€ ์ž„๊ณ„๊ฐ’์œผ๋กœ ๋ถˆ๋Ÿ‰ ๊ฒ€์ถœ ์ž๋™ ํ•„ํ„ฐ๋ง (์ด์ „ ์œ ํšจ pose ์žฌ์‚ฌ์šฉ์€ ์—ฐ์† 5ํ”„๋ ˆ์ž„์œผ๋กœ ์ œํ•œ, ์žฌ์‚ฌ์šฉ pose๋Š” ์ถ• ์‹œ๊ฐํ™” ์ œ์™ธ)
  • ๊ณ ์„ฑ๋Šฅ C++ ํŒŒ์ดํ”„๋ผ์ธ: ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ์— ์ ํ•ฉํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๊ตฌํ˜„ (5-8ms/frame @ 1280x720)
  • Multi-Group ๋™์‹œ ์ถ”์ •: ํ•œ ์นด๋ฉ”๋ผ ํ”„๋ ˆ์ž„์—์„œ ์—ฌ๋Ÿฌ ๋งˆ์ปค ๊ทธ๋ฃน์˜ base pose๋ฅผ ๋™์‹œ์— publish (๊ทธ๋ฃน๋ณ„ ๋…๋ฆฝ SLERP ํ•„ํ„ฐ)
  • YAML ๊ธฐ๋ฐ˜ ์œ ์—ฐํ•œ ์„ค์ •: ๋งˆ์ปค ID, ํฌ๊ธฐ, ๊ทธ๋ฃน๋ณ„ ์˜คํ”„์…‹์„ ์„ค์ • ํŒŒ์ผ๋กœ ๊ด€๋ฆฌ
  • ์‹ค์‹œ๊ฐ„ 3D ์‹œ๊ฐํ™”: ์œ„์น˜(tvec) ๋ฐ ํšŒ์ „(RPY) ํžˆ์Šคํ† ๋ฆฌ์˜ 3D ์‚ฐ์ ๋„์™€ ํ†ต๊ณ„ ์˜ค๋ฒ„๋ ˆ์ด
  • ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค: ์˜จ๋””๋งจ๋“œ ํฌ์ฆˆ ์ฟผ๋ฆฌ๋ฅผ ์œ„ํ•œ ROS2 ์„œ๋น„์Šค ์ œ๊ณต
  • Docker ์ง€์›: ๋นŒ๋“œ ๋ฐ ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ ํฌํ•จ, ์›ํด๋ฆญ ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ

์‹œ์Šคํ…œ ๊ตฌ์กฐ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      AprilTag Pose ROS2 System                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

        ROS2 RGB Camera
              โ”‚
              โ”‚ USB 3.0
              โ–ผ
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚  Camera Driver Node   โ”‚
    โ”‚  - Camera streaming   โ”‚
    โ”‚  - Intrinsics publish โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚  sensor_msgs/Image
                โ”‚  sensor_msgs/CameraInfo
                โ”‚
                โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                โ”‚                                     โ”‚ sensor_msgs/Image
                โ–ผ                                     โ–ผ
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ apriltag_pose_        โ”‚  TagDetection  โ”‚ apriltag_pose_        โ”‚
    โ”‚ estimator             โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ visualizer            โ”‚  (Python)
    โ”‚  - Tag detection      โ”‚                โ”‚  - Overlay drawing    โ”‚
    โ”‚  - Multi-tag PnP      โ”‚                โ”‚  - RPY calculation    โ”‚
    โ”‚  - SLERP filtering    โ”‚                โ”‚  - 3D scatter plots   โ”‚
    โ”‚  - Outlier rejection  โ”‚                โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚  /target_poses        (PoseArray, group_names order)
                โ”‚  /group_names         (latched CSV)
                โ”‚  /group_status        (per-group valid bits)
                โ”‚  /detection_image     (BGR8 overlay)
                โ”‚  /tag_detections      (raw, debug โ€” visualizer ์ž…๋ ฅ)
                โ–ผ
         Service Client
    (target_point_pose query, group_name dispatch)

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

AprilTag_Pose_ROS2/
โ”œโ”€โ”€ apriltag_pose_estimator/                    # ํฌ์ฆˆ ์ถ”์ • ํŒจํ‚ค์ง€ (C++)
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ pose_estimator_node.cpp             # ROS2 ๋…ธ๋“œ ๊ตฌํ˜„
โ”‚   โ”‚   โ”œโ”€โ”€ april_tag_detector.cpp              # AprilTag ๊ฒ€์ถœ ๋ž˜ํผ
โ”‚   โ”‚   โ”œโ”€โ”€ multi_tag_pose_estimator.cpp        # ๋‹ค์ค‘ ๋งˆ์ปค PnP ์œตํ•ฉ
โ”‚   โ”‚   โ”œโ”€โ”€ slerp_pose_filter.cpp               # ์ฟผํ„ฐ๋‹ˆ์–ธ SLERP ํ•„ํ„ฐ
โ”‚   โ”‚   โ””โ”€โ”€ main.cpp                            # ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ
โ”‚   โ”œโ”€โ”€ include/apriltag_pose_estimator/
โ”‚   โ”‚   โ”œโ”€โ”€ pose_estimator_node.hpp
โ”‚   โ”‚   โ”œโ”€โ”€ april_tag_detector.hpp
โ”‚   โ”‚   โ”œโ”€โ”€ multi_tag_pose_estimator.hpp
โ”‚   โ”‚   โ”œโ”€โ”€ slerp_pose_filter.hpp
โ”‚   โ”‚   โ””โ”€โ”€ tag_config.hpp                      # ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”‚   โ””โ”€โ”€ pose_estimator.yaml                 # ์„ค์ • ํŒŒ์ผ
โ”‚   โ”œโ”€โ”€ launch/
โ”‚   โ”‚   โ””โ”€โ”€ apriltag_estimator.launch.py        # ๋Ÿฐ์น˜ ํŒŒ์ผ
โ”‚   โ”œโ”€โ”€ scripts/
โ”‚   โ”‚   โ””โ”€โ”€ jitter_probe.py                     # ์„œ๋น„์Šค ์‘๋‹ต ์ง€ํ„ฐ ์ธก์ • ์Šคํฌ๋ฆฝํŠธ
โ”‚   โ”œโ”€โ”€ test/
โ”‚   โ”‚   โ””โ”€โ”€ test_multi_tag_pose_estimator.cpp   # estimator ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (gtest)
โ”‚   โ”œโ”€โ”€ CMakeLists.txt
โ”‚   โ””โ”€โ”€ package.xml
โ”œโ”€โ”€ apriltag_pose_estimator_msgs/               # ์ปค์Šคํ…€ ์ธํ„ฐํŽ˜์ด์Šค
โ”‚   โ”œโ”€โ”€ msg/
โ”‚   โ”‚   โ””โ”€โ”€ TagDetection.msg
โ”‚   โ”œโ”€โ”€ srv/
โ”‚   โ”‚   โ””โ”€โ”€ TargetPointPose.srv
โ”‚   โ”œโ”€โ”€ CMakeLists.txt
โ”‚   โ””โ”€โ”€ package.xml
โ”œโ”€โ”€ apriltag_pose_visualizer/                   # ์‹œ๊ฐํ™” ํŒจํ‚ค์ง€ (Python)
โ”‚   โ”œโ”€โ”€ apriltag_pose_visualizer/
โ”‚   โ”‚   โ””โ”€โ”€ pose_visualizer_node.py
โ”‚   โ”œโ”€โ”€ setup.py
โ”‚   โ””โ”€โ”€ package.xml
โ”œโ”€โ”€ realsense-ros/                              # RealSense ROS2 ๋“œ๋ผ์ด๋ฒ„ (์™ธ๋ถ€ ์ €์žฅ์†Œ, git ๋ฏธ์ถ”์ )
โ”œโ”€โ”€ docker/                                     # Docker ํ™˜๊ฒฝ
โ”‚   โ”œโ”€โ”€ Dockerfile
โ”‚   โ”œโ”€โ”€ build.sh
โ”‚   โ”œโ”€โ”€ run.sh
โ”‚   โ”œโ”€โ”€ entrypoint.sh
โ”‚   โ”œโ”€โ”€ commands.sh
โ”‚   โ””โ”€โ”€ config.sh.example
โ””โ”€โ”€ docs/
    โ””โ”€โ”€ launch_ros_graph.png

๋น ๋ฅธ ์‹œ์ž‘

Option 1: Docker (๊ถŒ์žฅ)

# 1. Docker ์ด๋ฏธ์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ
docker pull hhanoo/project:apriltag-pose-ros2-humble

# 2. ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ (X11 ํฌ์›Œ๋”ฉ ํฌํ•จ)
cd AprilTag_Pose_ROS2/docker
./run.sh

# 3. ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ ๋นŒ๋“œ (RealSense ๋“œ๋ผ์ด๋ฒ„๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ํฌํ•จ๋˜์–ด ์žˆ์Œ)
cd /ros2_ws
colcon build

# 4. ์‹คํ–‰ (ํ„ฐ๋ฏธ๋„ 2๊ฐœ)
ros2 launch <your_camera_driver> ...   # ์‚ฌ์šฉ ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„ (RealSense๋Š” ๋ฏธ๋ฆฌ ์ •์˜๋œ run-camera ์‚ฌ์šฉ)
run-estimator                          # ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py

Option 2: Native

# 1. ์˜์กด์„ฑ ์„ค์น˜ ๋ฐ ๋นŒ๋“œ (์‚ฌ์šฉ ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„๋Š” ์‚ฌ์ „ ์„ค์น˜ ํ•„์š”)
cd ~/ros2_ws
rosdep install --from-paths src --ignore-src -r -y
colcon build
source install/setup.bash

# 2. ์‹คํ–‰ (ํ„ฐ๋ฏธ๋„ 2๊ฐœ)
ros2 launch <your_camera_driver> ...
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py

์‹œ์Šคํ…œ ์š”๊ตฌ์‚ฌํ•ญ

ํ•„์ˆ˜

ํ•ญ๋ชฉ ์š”๊ตฌ์‚ฌํ•ญ
OS Ubuntu 22.04 LTS
ROS2 Humble
Python 3.10+
C++ C++17 (GCC 9+, Clang 10+)

ํ•˜๋“œ์›จ์–ด

ํ•ญ๋ชฉ ์‚ฌ์–‘
Camera ROS2 ํ˜ธํ™˜ RGB ์นด๋ฉ”๋ผ (sensor_msgs/Image + CameraInfo ํผ๋ธ”๋ฆฌ์‹œ)
USB USB 3.0 ํฌํŠธ (ํ•„์ˆ˜)
CPU ๋ฉ€ํ‹ฐ์ฝ”์–ด ํ”„๋กœ์„ธ์„œ (Intel i5+ ๊ถŒ์žฅ)
RAM 4GB ์ด์ƒ (8GB ๊ถŒ์žฅ)

์†Œํ”„ํŠธ์›จ์–ด ์˜์กด์„ฑ

์‹œ์Šคํ…œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ:

  • libapriltag-dev - AprilTag C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • libopencv-dev - OpenCV 4.x
  • libeigen3-dev - Eigen3 ์„ ํ˜•๋Œ€์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ์‚ฌ์šฉ ์นด๋ฉ”๋ผ์— ๋งž๋Š” ROS2 ๋“œ๋ผ์ด๋ฒ„ (๋ณ„๋„ ์„ค์น˜)

Python ํŒจํ‚ค์ง€:

  • numpy (<2.0, cv_bridge ํ˜ธํ™˜)
  • dt-apriltags (==3.1.7)
  • opencv-python (==4.10.0.84)
  • matplotlib (3D ์‹œ๊ฐํ™”)

์„ค์น˜

Method 1: Docker (๊ถŒ์žฅ)

Docker๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์˜์กด์„ฑ์ด ์ž๋™์œผ๋กœ ์„ค์น˜๋ฉ๋‹ˆ๋‹ค.

# 1. Docker ์ด๋ฏธ์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ
docker pull hhanoo/project:apriltag-pose-ros2-humble

# 2. ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
cd AprilTag_Pose_ROS2/docker
./run.sh
์ง์ ‘ ๋นŒ๋“œ (๊ฐœ๋ฐœ์ž์šฉ)
# 0. ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋กœ ์ด๋™
cd AprilTag_Pose_ROS2/docker

# 1. ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ ํ›„ IMAGE_NAME์„ ๋กœ์ปฌ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ
cp config.sh.example config.sh
# config.sh์—์„œ IMAGE_NAME="apriltag-pose-ros2-humble" ๋กœ ์ˆ˜์ •

# 2. Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ
./build.sh

# 3. ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
./run.sh

Method 2: Native

1. ROS2 Humble ์„ค์น˜

ROS2 Humble ๊ณต์‹ ์„ค์น˜ ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

2. ์‹œ์Šคํ…œ ์˜์กด์„ฑ ์„ค์น˜

sudo apt update
sudo apt install -y \
  build-essential cmake git \
  python3-pip python3-colcon-common-extensions python3-rosdep \
  libapriltag-dev libopencv-dev libeigen3-dev

์‚ฌ์šฉ ์นด๋ฉ”๋ผ์— ๋งž๋Š” ROS2 ๋“œ๋ผ์ด๋ฒ„๋Š” ๋ณ„๋„๋กœ ์„ค์น˜ํ•˜์„ธ์š”.

3. Python ํŒจํ‚ค์ง€ ์„ค์น˜

pip3 install \
  setuptools==58.2.0 packaging==21.3 wheel \
  'numpy>=1.21.0,<2.0' \
  dt-apriltags==3.1.7 \
  opencv-python==4.10.0.84

4. ROS ์˜์กด์„ฑ ์„ค์น˜

cd ~/ros2_ws
rosdep update
rosdep install --from-paths src --ignore-src -r -y

๋นŒ๋“œ

์ „์ฒด ๋นŒ๋“œ

cd ~/ros2_ws
colcon build --symlink-install
source install/setup.bash

ํŠน์ • ํŒจํ‚ค์ง€ ๋นŒ๋“œ

colcon build --symlink-install --packages-select apriltag_pose_estimator
source install/setup.bash

๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ

colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release

ํด๋ฆฐ ๋นŒ๋“œ

cd ~/ros2_ws
rm -rf build install log
colcon build --symlink-install
source install/setup.bash

์‹คํ–‰

์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ฐ˜๋“œ์‹œ ์ค€์ˆ˜ํ•˜์„ธ์š”. apriltag_estimator.launch.py์—๋Š” ์นด๋ฉ”๋ผ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ „์ฒด ์‹œ์Šคํ…œ ์‹คํ–‰

# ํ„ฐ๋ฏธ๋„ 1: ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„ ์‹คํ–‰ (๋จผ์ €)
source ~/ros2_ws/install/setup.bash
ros2 launch <your_camera_driver> ...

# ํ„ฐ๋ฏธ๋„ 2: AprilTag ํฌ์ฆˆ ์ถ”์ •๊ธฐ ์‹คํ–‰
source ~/ros2_ws/install/setup.bash
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py

# ํ„ฐ๋ฏธ๋„ 3 (์„ ํƒ): ์‹œ๊ฐํ™” ๋…ธ๋“œ ์‹คํ–‰
source ~/ros2_ws/install/setup.bash
ros2 run apriltag_pose_visualizer pose_visualizer_node

๊ฐœ๋ณ„ ๋…ธ๋“œ ์‹คํ–‰

# ์ปค์Šคํ…€ ์นด๋ฉ”๋ผ ํ† ํ”ฝ ์ง€์ •
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py \
  camera_topic:=camera/camera/color/image_raw \
  camera_info_topic:=camera/camera/color/camera_info

# ํƒœ๊ทธ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ€๊ฒฝ
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py \
  tag_size:=0.05 \
  tag_family:=tag36h11

# ์ปค์Šคํ…€ ์„ค์ • ํŒŒ์ผ ์‚ฌ์šฉ
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py \
  config_file:=/path/to/custom_config.yaml

# GUI ์œˆ๋„์šฐ ๋น„ํ™œ์„ฑํ™” (Docker / headless ํ™˜๊ฒฝ)
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py \
  show_service_result_window:=false

Docker ์‹คํ–‰

๊ถŒ์žฅ: ์ง์ ‘ docker exec๋กœ ์ปจํ…Œ์ด๋„ˆ์— ์ง„์ž…ํ•˜์ง€ ๋ง๊ณ  ํ•ญ์ƒ run.sh๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
run.sh๋Š” ๋„์ปค ์ด๋ฏธ์ง€ ํ™•์ธ ยท X11 ๊ถŒํ•œ ยท ๋งˆ์šดํŠธ ยท ํ˜ธ์ŠคํŠธ ๊ถŒํ•œ ๋ณต์›(HOST_UID/HOST_GID) ยท ๊ธฐ์กด ์ปจํ…Œ์ด๋„ˆ ์žฌ์‚ฌ์šฉ์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

docker pull hhanoo/project:apriltag-pose-ros2-humble
cd docker
./run.sh

# ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€
cd /ros2_ws
colcon build && source install/setup.bash
ros2 launch <your_camera_driver> ...   # ์‚ฌ์šฉ ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„ (RealSense๋Š” run-camera ์‚ฌ์šฉ)

์ „์ฒด command ์ •์˜๋Š” commands.sh๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Command ์„ค๋ช… ์ฐธ๊ณ 
build ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋นŒ๋“œ colcon build --symlink-install + overlay ์ž๋™ source
run-tests ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์‹คํ–‰ colcon test (apriltag ํŒจํ‚ค์ง€) + ๊ฒฐ๊ณผ ์š”์•ฝ
run-camera RealSense ์นด๋ฉ”๋ผ ์‹คํ–‰ rs_launch.py (1280x720x30, depth ๋น„ํ™œ์„ฑ)
run-estimator ํฌ์ฆˆ ์ถ”์ •๊ธฐ ์‹คํ–‰ apriltag_estimator.launch.py
run-visualizer ์‹œ๊ฐํ™” ๋…ธ๋“œ ์‹คํ–‰ pose_visualizer_node.py
echo-pose ํฌ์ฆˆ ํ† ํ”ฝ ๋ชจ๋‹ˆํ„ฐ๋ง --
call-pose ํฌ์ฆˆ ์„œ๋น„์Šค ํ˜ธ์ถœ TargetPointPose.srv
cmd-help ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ command ๋ชฉ๋ก ์ปจํ…Œ์ด๋„ˆ ์ ‘์† ์‹œ ์ž๋™ ์ถœ๋ ฅ

run-camera๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค์— ํฌํ•จ๋œ realsense-ros ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์นด๋ฉ”๋ผ๋ฅผ ์“ธ ๊ฒฝ์šฐ ํ•ด๋‹น ROS2 ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜์„ธ์š”
(estimator ๊ตฌ๋… ํ† ํ”ฝ: camera/color/image_raw, camera/color/camera_info).


์‚ฌ์šฉ๋ฒ•

์›Œํฌํ”Œ๋กœ์šฐ

์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ํ™•์ธ โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ ์‹œ์Šคํ…œ ์‹คํ–‰ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ ํ† ํ”ฝ ๋ชจ๋‹ˆํ„ฐ๋ง โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ ์„œ๋น„์Šค ํ˜ธ์ถœ
       โ”‚                  โ”‚                  โ”‚                  โ”‚
  ์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„        launch x2          topic echo        service call
    ์ง„๋‹จ ๋„๊ตฌ          (cam + est)       /target_poses    /target_point_pose

1. ์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ํ™•์ธ

์‚ฌ์šฉ ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„์˜ ์ง„๋‹จ ๋„๊ตฌ๋กœ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

2. ์‹œ์Šคํ…œ ์‹คํ–‰

# 1) ์‚ฌ์šฉ ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„ ์‹คํ–‰
ros2 launch <your_camera_driver> ...

# 2) ํฌ์ฆˆ ์ถ”์ •๊ธฐ ์‹คํ–‰
ros2 launch apriltag_pose_estimator apriltag_estimator.launch.py

3. ํ† ํ”ฝ ๋ชจ๋‹ˆํ„ฐ๋ง

# ํ™œ์„ฑ ํ† ํ”ฝ ํ™•์ธ
ros2 topic list

# ๊ฒ€์ถœ๋œ ํฌ์ฆˆ ํ™•์ธ
ros2 topic echo /pose_estimator_node/target_poses

# ์ด๋ฏธ์ง€ ํ™•์ธ
ros2 run rqt_image_view rqt_image_view

4. ์„œ๋น„์Šค ํ˜ธ์ถœ

ros2 service call /pose_estimator_node/target_point_pose \
  apriltag_pose_estimator_msgs/srv/TargetPointPose \
  "{request_time: {sec: 0, nanosec: 0}, group_name: ''}"

5. ์„œ๋น„์Šค ์‘๋‹ต ์ง€ํ„ฐ ์ธก์ • (์„ ํƒ)

scripts/jitter_probe.py๋Š” target_point_pose ์„œ๋น„์Šค๋ฅผ NํšŒ ๋ฐ˜๋ณต ํ˜ธ์ถœํ•˜์—ฌ ์‘๋‹ต ํฌ์ฆˆ์˜ ํ”๋“ค๋ฆผ(์ง€ํ„ฐ)์„ ์œ„์น˜ (mm) / ํšŒ์ „ (deg) ํ†ต๊ณ„๋กœ ๋ณด์—ฌ์ฃผ๋Š” ์ง„๋‹จ ์Šคํฌ๋ฆฝํŠธ์ž…๋‹ˆ๋‹ค. ๋…ธ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘์ผ ๋•Œ ๋ณ„๋„ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ํ•˜์„ธ์š”. ๋นŒ๋“œ ๋ถˆํ•„์š”(์ˆœ์ˆ˜ Python).

๊ธฐ๋ณธ ์‹คํ–‰

# 100ํšŒ ํ˜ธ์ถœ, 0.1์ดˆ ๊ฐ„๊ฒฉ, default ๊ทธ๋ฃน ์ถ”์ 
python3 ros2_ws/src/apriltag_pose_estimator/scripts/jitter_probe.py

์‹คํ–‰ ์‹œ์ž‘ ์‹œ ์ž๋™์œผ๋กœ timestamp ๊ธฐ๋ฐ˜ ๋กœ๊ทธ/CSV ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ๊ฒฝ๋กœ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: jitter_probe_20260424_175126.log / .csv). CSV์—๋Š” ๋งค ํ˜ธ์ถœ์˜ raw ๊ฐ’(idx, ok, x_mm, y_mm, z_mm, roll_deg, pitch_deg, yaw_deg, message)์ด ๊ธฐ๋ก๋˜์–ด ์™ธ๋ถ€ ๋ถ„์„/๊ทธ๋ž˜ํ”„ ๋„๊ตฌ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ต์…˜

์˜ต์…˜ ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
-n, --count 100 ์„œ๋น„์Šค ํ˜ธ์ถœ ํšŸ์ˆ˜
-i, --interval 0.1 ํ˜ธ์ถœ ๊ฐ„๊ฒฉ (์ดˆ)
--service /pose_estimator_node/target_point_pose ์„œ๋น„์Šค ์ด๋ฆ„
--group "" ์กฐํšŒํ•  ๊ทธ๋ฃน ์ด๋ฆ„ (๋นˆ ๋ฌธ์ž์—ด = ์ฒซ/default ๊ทธ๋ฃน)
--log <path> ์ž๋™ timestamp ๋กœ๊ทธ ํŒŒ์ผ ๊ฒฝ๋กœ (์›ํ•  ๊ฒฝ์šฐ ์ง์ ‘ ์ง€์ • ๊ฐ€๋Šฅ)
--csv <path> ๋กœ๊ทธ์™€ ๋™์ผ ์œ„์น˜ .csv CSV ํŒŒ์ผ ๊ฒฝ๋กœ (์›ํ•  ๊ฒฝ์šฐ ์ง์ ‘ ์ง€์ • ๊ฐ€๋Šฅ)
--no-log off ํŒŒ์ผ ์ €์žฅ์„ ๋„๊ณ  ์ฝ˜์†”๋งŒ ์‚ฌ์šฉ

์‚ฌ์šฉ ์˜ˆ์‹œ

# 200ํšŒ ํ˜ธ์ถœ, 50ms ๊ฐ„๊ฒฉ
python3 .../jitter_probe.py -n 200 -i 0.05

# ํŠน์ • ๊ทธ๋ฃน ์ถ”์  (multi-group yaml ํ™˜๊ฒฝ)
python3 .../jitter_probe.py --group secondary

# ๋กœ๊ทธ/CSV ์ €์žฅ ๊ฒฝ๋กœ ์ง์ ‘ ์ง€์ •
python3 .../jitter_probe.py --log /tmp/run1.log --csv /tmp/run1.csv

# ํŒŒ์ผ ์ €์žฅ ๋„๊ณ  ์ฝ˜์†” ์ถœ๋ ฅ๋งŒ
python3 .../jitter_probe.py --no-log

์ถœ๋ ฅ ์˜ˆ์‹œ

position (mm):
  x      mean=  -14.5532 mm  std=  0.2340  min=  -14.9100  max=  -14.1200  p2p=  0.7900
  y      mean=  -47.2991 mm  std=  ...
  z      mean= +270.3540 mm  std=  ...

orientation (deg):
  roll   mean=  ...
  pitch  mean=  ...
  yaw    mean=  ...
  • mean: ํ‰๊ท  (์ •์  ์œ„์น˜ / ๋ฐ˜๋ณต ๊ฐ€๋Šฅ์„ฑ ๊ฒ€์ฆ)
  • std: 1-ฯƒ ํ‘œ์ค€ํŽธ์ฐจ (๋‚ฎ์„์ˆ˜๋ก ์•ˆ์ •)
  • p2p: peak-to-peak (maxโˆ’min, ์‹ค์ œ ๋–จ๋ฆผ ํญ)

์„ค์ •

Docker ์„ค์ •

config.sh

IMAGE_NAME="hhanoo/project:apriltag-pose-ros2-humble"  # Docker Hub ์ด๋ฏธ์ง€ (๊ธฐ๋ณธ๊ฐ’)
CONTAINER_NAME="apriltag-pose-ros2-humble"             # Docker ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„
ROS_DOMAIN_ID=                                         # ROS2 ๋„๋ฉ”์ธ ID
XAUTHORITY_PATH="$HOME/.Xauthority"                    # X11 .Xauthority ๊ฒฝ๋กœ (GUI/RViz ํ‘œ์‹œ์šฉ)

run.sh ์‹คํ–‰ ์ „ docker pull hhanoo/project:apriltag-pose-ros2-humble๋กœ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค์„ธ์š”.

์ง์ ‘ ๋นŒ๋“œํ•˜๋ ค๋ฉด IMAGE_NAME์„ "apriltag-pose-ros2-humble" ๋“ฑ์œผ๋กœ ๋ณ€๊ฒฝ ํ›„ ./build.sh๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”.

pose_estimator.yaml (Multi-Group, ๊ถŒ์žฅ)

apriltag_pose_estimator/config/pose_estimator.yaml

์‹ ๊ทœ ์‚ฌ์šฉ์ž๋Š” multi-group ํ˜•์‹์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ๊ทธ๋ฃน ์šด์˜๋„ group_names์— ๊ทธ๋ฃน ํ•˜๋‚˜๋งŒ ๋‘๋ฉด ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

pose_estimator_node:
  ros__parameters:
    # ๊ณตํ†ต AprilTag ์„ค์ •
    tag_size: 0.02778
    tag_family: 'tagStandard41h12'

    # ์ž…๋ ฅ / ์ถœ๋ ฅ ํ† ํ”ฝ (yaml์— ์ ์œผ๋ฉด ๊ทธ ๊ฐ’, ์—†์œผ๋ฉด ~/<topic> ์ž๋™ ์‚ฌ์šฉ)
    camera_topic: 'camera/camera/color/image_raw'
    camera_info_topic: 'camera/camera/color/camera_info'
    camera_frame: 'camera_color_optical_frame'
    use_distortion_from_camera_info: false

    target_poses_topic:    'pose_estimator_node/target_poses'
    group_names_topic:     'pose_estimator_node/group_names'      # latched
    group_status_topic:    'pose_estimator_node/group_status'
    detection_image_topic: 'pose_estimator_node/detection_image'

    publish_detection_image: true

    # ---- Multi-group ์ •์˜ ----
    # ๊ฐ ๊ทธ๋ฃน์€ base marker์˜ pose 1๊ฐœ๋ฅผ ์ถœ๋ ฅ. group_names ์ˆœ์„œ๊ฐ€ PoseArray / group_status ์ˆœ์„œ.
    group_names:
      - default
      - secondary

    groups:
      default:
        marker_ids: [0, 1, 2]
        base_marker_id: 1
        # ๋งˆ์ปค๋งˆ๋‹ค 6 doubles [x, y, z, roll, pitch, yaw] (m, rad), T_base <- marker_i
        # base_marker entry๋Š” ์ •์˜์ƒ ๋ชจ๋‘ 0 (์ž๋™ ๊ฐ•์ œ)
        marker_offsets: [
          -0.065,  0.000,  0.000,   0.0000,  0.0000,  0.0000,   # marker 0
           0.000,  0.000,  0.000,   0.0000,  0.0000,  0.0000,   # marker 1 (base)
           0.065,  0.000,  0.000,   0.0000,  0.0000,  0.0000,   # marker 2
        ]

      secondary:
        marker_ids: [10, 11, 12]
        base_marker_id: 11
        marker_offsets: [
          -0.065,  0.000,  0.000,   0.0000,  0.0000,  0.0000,
           0.000,  0.000,  0.000,   0.0000,  0.0000,  0.0000,
           0.065,  0.000,  0.000,   0.0000,  0.0000,  0.0000,
        ]

v3.0.0 ABI break

  • yaml: group_names + groups.<name>.{...} ์Šคํ‚ค๋งˆ๊ฐ€ ํ•„์ˆ˜. ๋‹จ์ผ ๊ทธ๋ฃน๋งŒ ์‚ฌ์šฉํ•ด๋„ group_names: [<your_group>] + groups.<your_group>.{...} ํ˜•ํƒœ๋กœ ๋ช…์‹œํ•ด์•ผ ํ•จ. ์ด์ „ ๋‹จ์ผ ๊ทธ๋ฃน ํ˜•์‹(marker_ids / marker_offsets / target_points ์ตœ์ƒ์œ„)์€ ๋” ์ด์ƒ ์ง€์›ํ•˜์ง€ ์•Š์Œ.
  • srv: TargetPointPose.srv request์— string group_name ํ•„๋“œ ์ถ”๊ฐ€. ๋นˆ ๋ฌธ์ž์—ด์€ group_names์˜ ์ฒซ ๊ทธ๋ฃน์„ ๊ฐ€๋ฆฌํ‚ด.
  • ์ถœ๋ ฅ: target_points ๊ฐœ๋… ์ œ๊ฑฐ. ๊ฐ ๊ทธ๋ฃน์€ base marker pose 1๊ฐœ๋งŒ ์ถœ๋ ฅํ•˜๋ฏ€๋กœ PoseArray.poses[i]๊ฐ€ group_names[i]์™€ 1:1 ๋งคํ•‘.

์ฃผ์š” ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค๋ช…

  • tag_size: AprilTag ๊ฒ€์€์ƒ‰ ์‚ฌ๊ฐํ˜•์˜ ํ•œ ๋ณ€ ๊ธธ์ด(m). ์ •ํ™•๋„์— ์ง์ ‘์ ์œผ๋กœ ์˜ํ–ฅ
  • marker_offsets: ๋งˆ์ปค๋ณ„ base_marker ๊ธฐ์ค€ 6-DoF ๋ณ€ํ™˜ (T_base โ† marker_i). marker_ids ์ˆœ์„œ๋Œ€๋กœ ๋งˆ์ปค๋งˆ๋‹ค 6๊ฐœ ๊ฐ’ [x, y, z, roll, pitch, yaw](m, rad)์„ ํ‰๋ฉด ๋ฆฌ์ŠคํŠธ๋กœ ๋‚˜์—ด. base_marker_id์— ํ•ด๋‹นํ•˜๋Š” ํ•ญ๋ชฉ์€ ์ •์˜์ƒ identity (๋ชจ๋‘ 0)์—ฌ์•ผ ํ•˜๋ฉฐ, 0์ด ์•„๋‹ˆ๋ฉด WARN ํ›„ ๊ฐ•์ œ 0 ์ฒ˜๋ฆฌ๋จ. ๋งˆ์ปค ์ˆ˜๊ฐ€ N์ด๋ฉด ์ด 6N๊ฐœ. ํšŒ์ „ ํ•ฉ์„ฑ์€ R = Rz(yaw) * Ry(pitch) * Rx(roll) (intrinsic Z-Y-X)
  • use_distortion_from_camera_info: PnP ์‹œ ์‚ฌ์šฉํ•  ์™œ๊ณก ๊ณ„์ˆ˜ ์†Œ์Šค ์„ ํƒ
    • false (๊ธฐ๋ณธ): ์™œ๊ณก ๊ณ„์ˆ˜๋ฅผ 0 ์œผ๋กœ ๊ฐ„์ฃผ. ์ด๋ฏธ rectified ๋œ ์ด๋ฏธ์ง€๋ฅผ ํผ๋ธ”๋ฆฌ์‹œํ•˜๋Š” ์นด๋ฉ”๋ผ์— ์‚ฌ์šฉ
    • true: camera_info.d ์˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ. raw ์ด๋ฏธ์ง€๋ฅผ ํผ๋ธ”๋ฆฌ์‹œํ•˜๋Š” ์นด๋ฉ”๋ผ์— ์‚ฌ์šฉ
  • display_width / display_height: ์„œ๋น„์Šค ๊ฒฐ๊ณผ ์œˆ๋„์šฐ ํฌ๊ธฐ. 0์ด๋ฉด ์›๋ณธ ํ•ด์ƒ๋„ ๊ทธ๋Œ€๋กœ ํ‘œ์‹œ

Launch ์ธ์ˆ˜

์ธ์ˆ˜ ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
config_file pose_estimator.yaml YAML ์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ
show_service_result_window "" (YAML ๊ฐ’ ์‚ฌ์šฉ) ์„œ๋น„์Šค ๊ฒฐ๊ณผ ์œˆ๋„์šฐ ํ‘œ์‹œ ์—ฌ๋ถ€
camera_topic "" (YAML ๊ฐ’ ์‚ฌ์šฉ) ์นด๋ฉ”๋ผ ์ด๋ฏธ์ง€ ํ† ํ”ฝ ์˜ค๋ฒ„๋ผ์ด๋“œ
camera_info_topic "" (YAML ๊ฐ’ ์‚ฌ์šฉ) ์นด๋ฉ”๋ผ ์ •๋ณด ํ† ํ”ฝ ์˜ค๋ฒ„๋ผ์ด๋“œ
tag_family "" (YAML ๊ฐ’ ์‚ฌ์šฉ) ํƒœ๊ทธ ํŒจ๋ฐ€๋ฆฌ ์˜ค๋ฒ„๋ผ์ด๋“œ
tag_size "" (YAML ๊ฐ’ ์‚ฌ์šฉ) ํƒœ๊ทธ ํฌ๊ธฐ ์˜ค๋ฒ„๋ผ์ด๋“œ

API / ROS ์ธํ„ฐํŽ˜์ด์Šค

๋…ธ๋“œ

๋…ธ๋“œ ์–ธ์–ด ํŒจํ‚ค์ง€ ์„ค๋ช…
pose_estimator_node C++ apriltag_pose_estimator AprilTag ๊ฒ€์ถœ ๋ฐ ํฌ์ฆˆ ์ถ”์ •
pose_visualizer_node Python apriltag_pose_visualizer ๊ฒ€์ถœ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” ๋ฐ RPY ๊ณ„์‚ฐ

์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„ ๋…ธ๋“œ๋Š” ๋ณธ ํŒจํ‚ค์ง€ ์™ธ๋ถ€ ์˜์กด์„ฑ์œผ๋กœ, ์‚ฌ์šฉ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ๋ณ„๋„๋กœ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Published ํ† ํ”ฝ

ํ† ํ”ฝ ํƒ€์ž… QoS / ๋น„๊ณ  ์„ค๋ช…
/pose_estimator_node/tag_detections apriltag_pose_estimator_msgs/TagDetection KEEP_LAST(10) Raw ๊ฒ€์ถœ ๋ฐ์ดํ„ฐ (debug. multi-group์—์„  ์ฒซ ๊ทธ๋ฃน rvec/tvec)
/pose_estimator_node/target_poses geometry_msgs/PoseArray KEEP_LAST(10) ๊ฐ ๊ทธ๋ฃน์˜ base marker pose (group_names ์ˆœ์„œ, ์‹คํŒจ ๊ทธ๋ฃน์€ NaN)
/pose_estimator_node/group_names std_msgs/String transient_local + KEEP_LAST(1) (latched) ๊ทธ๋ฃน ์ด๋ฆ„ CSV. boot ๋™๊ธฐํ™”์šฉ
/pose_estimator_node/group_status std_msgs/UInt8MultiArray KEEP_LAST(10) group_names ์ˆœ์„œ๋Œ€๋กœ 0(invalid) / 1(valid)
/pose_estimator_node/detection_image sensor_msgs/Image (BGR8) KEEP_LAST(10), subscriber 0์ด๋ฉด publish skip ๋ชจ๋“  ๊ทธ๋ฃน ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ์ด๋ฏธ์ง€์— ๋ˆ„์  ์˜ค๋ฒ„๋ ˆ์ด

Subscribed ํ† ํ”ฝ

ํ† ํ”ฝ ํƒ€์ž… ์„œ๋ธŒ์Šคํฌ๋ผ์ด๋ฒ„ ์„ค๋ช…
/camera/color/image_raw sensor_msgs/Image pose_estimator_node ์ž…๋ ฅ ์นด๋ฉ”๋ผ ์ด๋ฏธ์ง€
/camera/color/camera_info sensor_msgs/CameraInfo pose_estimator_node ์นด๋ฉ”๋ผ ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์ •๋ณด

์„œ๋น„์Šค

์„œ๋น„์Šค ํƒ€์ž… ์ œ๊ณต์ž ์„ค๋ช…
/pose_estimator_node/target_point_pose TargetPointPose pose_estimator_node ์ตœ์‹  ๊ฒ€์ถœ ํฌ์ฆˆ ์ฟผ๋ฆฌ

์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€

TagDetection.msg:

bool       tag_detected    # ํƒœ๊ทธ ๊ฒ€์ถœ ํ”Œ๋ž˜๊ทธ
float64[9] camera_matrix   # 3x3 ๋‚ด๋ถ€ ํŒŒ๋ผ๋ฏธํ„ฐ ํ–‰๋ ฌ (row-major)
float64[]  dist_coeffs     # ์™œ๊ณก ๊ณ„์ˆ˜ (OpenCV ์ˆœ์„œ)
float64[3] rvec            # Rodrigues ํšŒ์ „ ๋ฒกํ„ฐ
float64[3] tvec            # ๋ณ‘์ง„ ๋ฒกํ„ฐ (m)
float64    tag_size        # ํƒœ๊ทธ ํฌ๊ธฐ (m)

TargetPointPose.srv:

# Request
builtin_interfaces/Time request_time    # ์š”์ฒญ ์‹œ๊ฐ
string group_name                       # ์กฐํšŒ ๊ทธ๋ฃน ์ด๋ฆ„ ("" = ์ฒซ/default ๊ทธ๋ฃน)
---
# Response
bool success                            # ์„ฑ๊ณต ์—ฌ๋ถ€
string message                          # ์ƒํƒœ ๋ฉ”์‹œ์ง€
builtin_interfaces/Time data_time       # ๋ฐ์ดํ„ฐ ํƒ€์ž„์Šคํƒฌํ”„
geometry_msgs/PoseArray poses           # ํ•ด๋‹น ๊ทธ๋ฃน์˜ base marker pose (์š”์†Œ 1๊ฐœ)

group_name์ด ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด group_names์˜ ์ฒซ ๊ทธ๋ฃน์„ ๊ฐ€๋ฆฌํ‚ด. ์•Œ ์ˆ˜ ์—†๋Š” ๊ทธ๋ฃน ์ด๋ฆ„์€ service error.

๋„คํŠธ์›Œํฌ ๊ตฌ์„ฑ (Docker)

ํ•ญ๋ชฉ ๊ฐ’ ์„ค๋ช…
Network mode host ํ˜ธ์ŠคํŠธ ๋„คํŠธ์›Œํฌ ๊ณต์œ 
ROS_DOMAIN_ID 99 ROS2 ๋„๋ฉ”์ธ ID
IPC host IPC ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ณต์œ 
X11 /tmp/.X11-unix GUI ํฌ์›Œ๋”ฉ

๋ฌธ์ œ ํ•ด๊ฒฐ

1. ์นด๋ฉ”๋ผ๊ฐ€ ์ธ์‹๋˜์ง€ ์•Š์„ ๋•Œ

์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋””๋ฐ”์ด์Šค๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ USB ์—ฐ๊ฒฐยท๊ถŒํ•œยท์ปค๋„ ๋ชจ๋“ˆ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

# USB ์—ฐ๊ฒฐ ํ™•์ธ
lsusb

# ์ปค๋„ ๋ชจ๋“ˆ ๋กœ๋“œ (UVC ์นด๋ฉ”๋ผ)
sudo modprobe uvcvideo

# ๊ถŒํ•œ ์„ค์ •
sudo usermod -aG video $USER
sudo usermod -aG plugdev $USER
# ๋กœ๊ทธ์•„์›ƒ ํ›„ ์žฌ๋กœ๊ทธ์ธ

์นด๋ฉ”๋ผ ๋ชจ๋ธ๋ณ„ ์ถ”๊ฐ€ ์ง„๋‹จ ์ ˆ์ฐจ๋Š” ์‚ฌ์šฉ ROS2 ๋“œ๋ผ์ด๋ฒ„ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

2. "No AprilTags detected"

[WARN] No tags detected in current frame
# ํ™•์ธ ์‚ฌํ•ญ:
# - ์กฐ๋ช…: ๋ฐ๊ณ  ๊ท ์ผํ•œ ์กฐ๋ช… (๊ทธ๋ฆผ์ž ์ตœ์†Œํ™”)
# - ์ดˆ์ : ์นด๋ฉ”๋ผ ์ดˆ์ ์ด ํƒœ๊ทธ์— ๋งž์ถฐ์ ธ ์žˆ๋Š”์ง€ ํ™•์ธ
# - ๊ฑฐ๋ฆฌ: ์นด๋ฉ”๋ผ-ํƒœ๊ทธ ๊ฐ„ 0.3m ~ 3m ๊ถŒ์žฅ
# - ๊ฐ๋„: ํƒœ๊ทธ๊ฐ€ ์นด๋ฉ”๋ผ๋ฅผ ํ–ฅํ•˜๋„๋ก (< 45๋„)

# config์—์„œ ํƒœ๊ทธ ํฌ๊ธฐ์™€ ํŒจ๋ฐ€๋ฆฌ๊ฐ€ ์‹ค์ œ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ
# tag_size: 0.02778  (์‹ค์ธก๊ฐ’์„ ๋ฏธํ„ฐ ๋‹จ์œ„๋กœ)
# tag_family: 'tagStandard41h12'  (์ธ์‡„ํ•œ ํƒœ๊ทธ์™€ ๋™์ผํ•ด์•ผ ํ•จ)

3. ํฌ์ฆˆ ๋ถˆ์•ˆ์ •/์ง€ํ„ฐ๋ง

# ํฌ์ฆˆ ์ถ”์ •๊ฐ’์ด ํฌ๊ฒŒ ํ”๋“ค๋ฆฌ๋Š” ๊ฒฝ์šฐ
# 1. tag_size ๊ฐ’์ด ์‹ค์ธก์น˜์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ (mm -> m ๋ณ€ํ™˜ ์ฃผ์˜)
# 2. marker_offsets ๊ฐ’์ด ๋งˆ์ปค ๊ฐ„ ์‹ค์ œ ๊ฑฐ๋ฆฌ/ํšŒ์ „๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ (๋งˆ์ปค๋ณ„ 6-DoF)
# 3. ํ•ด์ƒ๋„๋ฅผ ๋†’์ด๊ฑฐ๋‚˜ ํ”„๋ ˆ์ž„ ๋ ˆ์ดํŠธ๋ฅผ ๋‚ฎ์ถฐ์„œ ์ด๋ฏธ์ง€ ํ’ˆ์งˆ ๊ฐœ์„ 
#    (์‚ฌ์šฉ ์นด๋ฉ”๋ผ ROS2 ๋“œ๋ผ์ด๋ฒ„ launch์—์„œ ํ•ด์ƒ๋„/FPS ์˜ต์…˜์„ ์กฐ์ •)

# 4. scripts/jitter_probe.py ๋กœ ์ •๋Ÿ‰ ์ธก์ • (์‚ฌ์šฉ๋ฒ• ์„น์…˜ 5๋ฒˆ ์ฐธ๊ณ )
python3 ros2_ws/src/apriltag_pose_estimator/scripts/jitter_probe.py

4. "Could not find libapriltag-dev"

CMake Error: Could not find libapriltag
sudo apt update
sudo apt install -y libapriltag-dev

# ์—ฌ์ „ํžˆ ์‹คํŒจ ์‹œ
sudo add-apt-repository universe
sudo apt update
sudo apt install -y libapriltag-dev

5. cv_bridge NumPy ๋ฒ„์ „ ์ถฉ๋Œ

ImportError: numpy.core.multiarray failed to import
pip3 install 'numpy>=1.21.0,<2.0'

๋ผ์ด์„ ์Šค

์ด ํ”„๋กœ์ ํŠธ๋Š” MIT ๋ผ์ด์„ ์Šค๋กœ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ LICENSE ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์„ธ์š”.


Maintainer

hhanoo (woo980711@gmail.com)

About

Real-time 6-DOF pose estimation with AprilTag

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors