Skip to content

hhanoo/hand-eye_calibration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

35 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Hand-Eye Calibration

Multi-robot hand-eye calibration system with PyQt5 GUI

ROS2 Python C++ OpenCV Docker License


๋ชฉ์ฐจ


๋ฐ๋ชจ

GUI ํ™”๋ฉด

Hand-Eye Calibration GUI

Pose Pairs ์‹œ๊ฐํ™”

Pose Pairs Visualization

์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™”

Calibration Result Visualization


๊ฐœ์š”

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

๋กœ๋ด‡ ์—”๋“œ์ดํŽ™ํ„ฐ์™€ ์นด๋ฉ”๋ผ ์‚ฌ์ด์˜ ๋ณ€ํ™˜ ๊ด€๊ณ„(AX=XB)๋ฅผ ๊ตฌํ•˜๋Š” Hand-Eye Calibration ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ROS2 Humble ๊ธฐ๋ฐ˜์˜ PyQt5 GUI์—์„œ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘, ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์‹คํ–‰, ๊ฒฐ๊ณผ ์ €์žฅ๊นŒ์ง€ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

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

  • gui_node (Python): ROS2 ๋…ธ๋“œ + PyQt5 GUI, ์นด๋ฉ”๋ผ ์˜์ƒ ํ‘œ์‹œ, ํฌ์ฆˆ ์ˆ˜์ง‘, ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์‹คํ–‰
  • ์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„: ์‚ฌ์šฉ ์„ผ์„œ์— ๋”ฐ๋ผ VCS๋กœ ์„ ํƒ
    (RealSense: realsense2_camera, Orbbec: OrbbecSDK_ROS2)
  • calibration (Python): ArUco ๋งˆ์ปค ๊ฒ€์ถœ, Tsai-Lenz / DQ RANSAC ์†”๋ฒ„ ๋ชจ๋“ˆ
  • robot_interface (Python): UR Direct (read-only ์†Œ์ผ“) ๋˜๋Š” ROS2 TF๋ฅผ ํ†ตํ•œ ๋กœ๋ด‡ ํฌ์ฆˆ ํš๋“
  • dsr_pose_reader (C++): Doosan ๋กœ๋ด‡ ์ „์šฉ ํฌ์ฆˆ ๋ฆฌ๋”, DRFL ๋ชจ๋‹ˆํ„ฐ๋ง์œผ๋กœ ํŽœ๋˜ํŠธ ์ œ์–ด ์œ ์ง€

์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜

DQ RANSAC (๊ธฐ๋ณธ, ๊ถŒ์žฅ)

  • ์ถœ์ฒ˜: Daniilidis, "Hand-Eye Calibration Using Dual Quaternions", IEEE 1999
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ: ethz-asl/hand_eye_calibration
  • ๋ฐฉ์‹: ํšŒ์ „๊ณผ ์ด๋™์„ Dual Quaternion์œผ๋กœ ๋™์‹œ์— ํ’€์ด, RANSAC์œผ๋กœ ์ด์ƒ์น˜ ์ž๋™ ์ œ๊ฑฐ
  • ์žฅ์ : ๋…ธ์ด์ฆˆ/์ด์ƒ์น˜์— ๊ฐ•๊ฑด
  • ๊ถŒ์žฅ ํฌ์ฆˆ ์ˆ˜: 15๊ฐœ ์ด์ƒ

Tsai-Lenz

  • ์ถœ์ฒ˜: Tsai & Lenz, IEEE 1989
  • ๋ฐฉ์‹: ํšŒ์ „(R)์„ SVD๋กœ ๋จผ์ € ํ’€๊ณ , ์ด๋™(t)์„ ์ตœ์†Œ์ž์Šน๋ฒ•์œผ๋กœ ํ’€์ด
  • ์žฅ์ : ๋งค์šฐ ๋น ๋ฆ„, ๊ฐ„๋‹จ
  • ๋‹จ์ : ์ด์ƒ์น˜ ์ฒ˜๋ฆฌ ์—†์Œ -- ๋ฐ์ดํ„ฐ๊ฐ€ ๊นจ๋—ํ•ด์•ผ ํ•จ

4-DOF Calibrator (ํ–ฅํ›„)

  • ์ถœ์ฒ˜: QuantuMope/handeye-4dof
  • SCARA ๋“ฑ 4์ถ• ๋กœ๋ด‡์šฉ, ํ˜„์žฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ํฌํ•จ (GUI ํ†ตํ•ฉ ์˜ˆ์ •)

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

  • Eye-in-hand ๋กœ๋ด‡ ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ (์นด๋ฉ”๋ผ๊ฐ€ ์—”๋“œ์ดํŽ™ํ„ฐ์— ๋ถ€์ฐฉ๋œ ๊ฒฝ์šฐ)
  • ์‚ฐ์—… ์ž๋™ํ™” ์‹œ์Šคํ…œ์˜ ๋กœ๋ด‡-์นด๋ฉ”๋ผ ์ •๋ฐ€ ์ •ํ•ฉ
  • ๋‹ค์ค‘ ๋กœ๋ด‡ ํ™˜๊ฒฝ (UR, Doosan ๋“ฑ)
  • ์—ฐ๊ตฌ ๊ฐœ๋ฐœ ๋ฐ ๊ต์œก

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

  • ๋‹ค์ค‘ ๋กœ๋ด‡ ์ง€์›: UR Direct (read-only ์†Œ์ผ“), Doosan DRFL (๋ชจ๋‹ˆํ„ฐ๋ง), ROS2 TF๋ฅผ ํ†ตํ•ด ํŽœ๋˜ํŠธ ์ œ์–ด๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ํฌ์ฆˆ ํš๋“
  • 2๊ฐ€์ง€ ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜: DQ RANSAC (์ด์ƒ์น˜์— ๊ฐ•๊ฑด), Tsai-Lenz (๋น ๋ฅธ ๊ฒฐ๊ณผ ํ™•์ธ)
  • PyQt5 GUI: ์นด๋ฉ”๋ผ ์˜์ƒ ์‹ค์‹œ๊ฐ„ ํ‘œ์‹œ, ArUco ๋งˆ์ปค ์˜ค๋ฒ„๋ ˆ์ด, ํฌ์ฆˆ ์ˆ˜์ง‘/์‚ญ์ œ, ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์‹คํ–‰์„ ํ•œ ํ™”๋ฉด์—์„œ ์ฒ˜๋ฆฌ
  • 3D ์‹œ๊ฐํ™”: ์ˆ˜์ง‘๋œ ํฌ์ฆˆ ์Œ๊ณผ ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ๋ฅผ Matplotlib 3D ํ”Œ๋กฏ์œผ๋กœ ํ™•์ธ
  • ROS2 ๋„ค์ดํ‹ฐ๋ธŒ: ์นด๋ฉ”๋ผ ์˜์ƒ์€ ROS2 ํ† ํ”ฝ์œผ๋กœ ์ˆ˜์‹  (RealSense / Orbbec ๋“ฑ), TF2๋กœ ๋กœ๋ด‡ ํฌ์ฆˆ ํš๋“ ๊ฐ€๋Šฅ
  • Docker ์ง€์›: ๋นŒ๋“œ ๋ฐ ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ ํฌํ•จ, ์›ํด๋ฆญ ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ
  • ๋ฐ์ดํ„ฐ ์ €์žฅ/๋กœ๋“œ: CSV ํฌ๋งท์œผ๋กœ ํฌ์ฆˆ ๋ฐ์ดํ„ฐ ์ €์žฅ, ๋‚˜์ค‘์— ๋ถˆ๋Ÿฌ์™€ ์žฌ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฐ€๋Šฅ

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

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Vision Sensor         โ”‚  โ”‚ UR Robot         โ”‚  โ”‚ Doosan Robot           โ”‚
โ”‚ RealSense / Orbbec    โ”‚  โ”‚                  โ”‚  โ”‚                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
            โ”‚ USB 3.0               โ”‚ TCP:30003               โ”‚ TCP:12345
            โ”‚                       โ”‚ (read-only)             โ”‚ (DRFL monitoring)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”           โ”‚          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Camera ROS2 Driver    โ”‚           โ”‚          โ”‚ dsr_pose_reader (C++)     โ”‚
โ”‚ - Color streaming     โ”‚           โ”‚          โ”‚ - No access control       โ”‚
โ”‚ - Camera info pub     โ”‚           โ”‚          โ”‚ - Pendant preserved       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜           โ”‚          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
            โ”‚                       โ”‚                         โ”‚
            โ”‚ /camera/color/        โ”‚                         โ”‚ /tf, /tcp_pose
            โ”‚   image_raw           โ”‚                         โ”‚
            โ”‚   camera_info         โ”‚                         โ”‚
            โ”‚                       โ”‚                         โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ hand_eye_calibration (gui_node)                                         โ”‚
โ”‚                                                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚  โ”‚ ArUco        โ”‚  โ”‚ Robot Interface                          โ”‚         โ”‚
โ”‚  โ”‚ Detector     โ”‚  โ”‚ - UR Direct (read-only socket)           โ”‚         โ”‚
โ”‚  โ”‚              โ”‚  โ”‚ - ROS2 TF (dsr_pose_reader, etc.)        โ”‚         โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ”‚         โ”‚                               โ”‚                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”                        โ”‚
โ”‚  โ”‚ Capture Pose (marker T + robot T ์ €์žฅ)       โ”‚                        โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                        โ”‚
โ”‚                         โ”‚                                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                        โ”‚
โ”‚  โ”‚ Calibration Solver                          โ”‚                        โ”‚
โ”‚  โ”‚ - DQ RANSAC (๊ธฐ๋ณธ)  - Tsai-Lenz              โ”‚                        โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                        โ”‚
โ”‚                         โ”‚                                               โ”‚
โ”‚  Result: X (4x4, camera <-> end-effector)                               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

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

Hand-eye_calibration/                           # ROS2 ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฃจํŠธ
โ”œโ”€โ”€ .github/workflows/
โ”‚   โ””โ”€โ”€ release.yml                             # ํƒœ๊ทธ push ์‹œ GitHub Release ์ž๋™ ์ƒ์„ฑ
โ”œโ”€โ”€ camera_realsense.repos                      # VCS: realsense-ros v4.55.1
โ”œโ”€โ”€ camera_orbbec.repos                         # VCS: OrbbecSDK_ROS2 v2-main
โ”œโ”€โ”€ docker/
โ”‚   โ”œโ”€โ”€ Dockerfile                              # ROS2 Humble + ์˜์กด์„ฑ
โ”‚   โ”œโ”€โ”€ config.sh.example                       # Docker ๊ณตํ†ต ์„ค์ • (์ด๋ฏธ์ง€๋ช…, ROS_DOMAIN_ID)
โ”‚   โ”œโ”€โ”€ build.sh                                # Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ
โ”‚   โ”œโ”€โ”€ run.sh                                  # Docker ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
โ”‚   โ”œโ”€โ”€ entrypoint.sh                           # ROS2 ํ™˜๊ฒฝ ์„ค์ • + RMW(CycloneDDS) ์„ค์ •
โ”‚   โ”œโ”€โ”€ cyclonedds.xml                          # CycloneDDS ํŠœ๋‹ (๋Œ€์šฉ๋Ÿ‰ ์„ผ์„œ ๋ฉ”์‹œ์ง€์šฉ)
โ”‚   โ””โ”€โ”€ commands.sh                             # ์ปจํ…Œ์ด๋„ˆ ๋‚ด ๋ช…๋ น์–ด ํ•จ์ˆ˜ ์ •์˜ (build, camera-*, gui-*, doosan)
โ”‚
โ””โ”€โ”€ src/
    โ”œโ”€โ”€ (camera driver)                         # VCS๋กœ ๊ฐ€์ ธ์˜ด: realsense-ros ๋˜๋Š” OrbbecSDK_ROS2
    โ”‚
    โ”œโ”€โ”€ dsr_pose_reader/                        # Doosan ๋กœ๋ด‡ ํฌ์ฆˆ ๋ฆฌ๋” (C++)
    โ”‚   โ”œโ”€โ”€ package.xml
    โ”‚   โ”œโ”€โ”€ CMakeLists.txt
    โ”‚   โ”œโ”€โ”€ doosan_api/                         # DRFL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (Doosan Robotics, BSD)
    โ”‚   โ”‚   โ”œโ”€โ”€ include/                        # DRFL.h, DRFC.h, DRFLEx.h, DRFS.h
    โ”‚   โ”‚   โ””โ”€โ”€ lib/                            # libDRFL.a, libPoco*.so
    โ”‚   โ”œโ”€โ”€ include/dsr_pose_reader/
    โ”‚   โ”‚   โ””โ”€โ”€ pose_reader_node.hpp
    โ”‚   โ”œโ”€โ”€ config/
    โ”‚   โ”‚   โ””โ”€โ”€ default.yaml                    # Doosan ์—ฐ๊ฒฐ ํŒŒ๋ผ๋ฏธํ„ฐ
    โ”‚   โ”œโ”€โ”€ launch/
    โ”‚   โ”‚   โ””โ”€โ”€ dsr_pose_reader.launch.py
    โ”‚   โ””โ”€โ”€ src/
    โ”‚       โ””โ”€โ”€ pose_reader_node.cpp
    โ”‚
    โ””โ”€โ”€ hand_eye_calibration/                   # ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ํŒจํ‚ค์ง€ (Python)
        โ”œโ”€โ”€ package.xml
        โ”œโ”€โ”€ setup.py
        โ”œโ”€โ”€ config/
        โ”‚   โ””โ”€โ”€ default.yaml                    # ROS2 ํŒŒ๋ผ๋ฏธํ„ฐ (ํ† ํ”ฝ, ๋งˆ์ปค, ๋กœ๋ด‡ ์„ค์ •)
        โ”‚
        โ””โ”€โ”€ hand_eye_calibration/               # Python ํŒจํ‚ค์ง€
            โ”œโ”€โ”€ gui_node.py                     # ๋ฉ”์ธ ROS2 ๋…ธ๋“œ + PyQt5 GUI
            โ”‚
            โ”œโ”€โ”€ calibration/                    # ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜
            โ”‚   โ”œโ”€โ”€ aruco_detector.py           # ArUco ๋งˆ์ปค ๊ฒ€์ถœ
            โ”‚   โ”œโ”€โ”€ tsai_lenz.py                # Tsai-Lenz ์†”๋ฒ„
            โ”‚   โ”œโ”€โ”€ dual_quaternion_ransac.py   # DQ RANSAC ๋ž˜ํผ
            โ”‚   โ”œโ”€โ”€ visualization.py            # 3D ์‹œ๊ฐํ™” (Matplotlib)
            โ”‚   โ””โ”€โ”€ data_io.py                  # ํฌ์ฆˆ ๋ฐ์ดํ„ฐ CSV ์ €์žฅ/๋กœ๋“œ
            โ”‚
            โ”œโ”€โ”€ robot_interface/                # ๋กœ๋ด‡ ํฌ์ฆˆ ํš๋“
            โ”‚   โ”œโ”€โ”€ pose_reader_interface.py    # PoseReader ABC
            โ”‚   โ”œโ”€โ”€ ur_direct_pose_reader.py    # UR read-only ์†Œ์ผ“ (ํฌํŠธ 30003)
            โ”‚   โ””โ”€โ”€ ros2_tf_pose_reader.py      # ROS2 TF ๋ฐฉ์‹
            โ”‚
            โ”œโ”€โ”€ hand_eye_calibration_lib/       # ethz-asl DQ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (์ถ”์ถœ)
            โ”‚   โ”œโ”€โ”€ dual_quaternion.py
            โ”‚   โ”œโ”€โ”€ quaternion.py
            โ”‚   โ””โ”€โ”€ dual_quaternion_hand_eye_calibration.py
            โ”‚
            โ””โ”€โ”€ handeye_4dof_lib/               # 4-DOF ์†”๋ฒ„ (์ถ”์ถœ)
                โ”œโ”€โ”€ calibrator.py
                โ””โ”€โ”€ pose_selector.py

๋น ๋ฅธ ์‹œ์ž‘

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

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

# 2. (Orbbec ์‚ฌ์šฉ ์‹œ, ์ตœ์ดˆ 1ํšŒ) ํ˜ธ์ŠคํŠธ์—์„œ udev rules ์„ค์น˜
sudo bash src/OrbbecSDK_ROS2/orbbec_camera/scripts/install_udev_rules.sh
sudo udevadm control --reload-rules && sudo udevadm trigger
#     ์ดํ›„ ์นด๋ฉ”๋ผ USB๋ฅผ ๋ฝ‘์•˜๋‹ค ๋‹ค์‹œ ์—ฐ๊ฒฐ

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

# 4. ๋นŒ๋“œ (์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€) โ€” build ํ•จ์ˆ˜๊ฐ€ Release ๋นŒ๋“œ + source๋ฅผ ํ•จ๊ป˜ ์‹คํ–‰
build

# 5. ์นด๋ฉ”๋ผ์™€ GUI๋ฅผ ๊ฐ๊ฐ ์‹คํ–‰ (ํ„ฐ๋ฏธ๋„ 2๊ฐœ, ์ถ”๊ฐ€ ์…ธ์€ ./run.sh ์žฌ์‹คํ–‰์œผ๋กœ attach)
#    ํ„ฐ๋ฏธ๋„ 1: ์นด๋ฉ”๋ผ (RealSense ๋˜๋Š” Orbbec)
camera-realsense          # ๋˜๋Š” camera-orbbec
#    ํ„ฐ๋ฏธ๋„ 2: GUI (์‚ฌ์šฉ ์นด๋ฉ”๋ผ์— ๋งž์ถฐ ํ•จ์ˆ˜ ์„ ํƒ)
gui-realsense             # ๋˜๋Š” gui-orbbec

์„ผ์„œ๋ณ„ launch ์˜ต์…˜ยทํ† ํ”ฝ์€ ์‹คํ–‰ > ๊ฐœ๋ณ„ ๋ชจ๋“ˆ ์ฐธ๊ณ .

Option 2: Native

์‚ฌ์šฉ ์„ผ์„œ์˜ ๋“œ๋ผ์ด๋ฒ„๋ฅผ ๋จผ์ € ์„ค์น˜ โ€” ์œ„ ์„ค์น˜ > Method 2 > ์‹œ์Šคํ…œ ์˜์กด์„ฑ ์ฐธ๊ณ .

rosdep install --from-paths src --ignore-src -r -y
colcon build --symlink-install \
  --event-handlers console_direct+ \
  --cmake-args -DCMAKE_BUILD_TYPE=Release
source install/setup.bash
  • -DCMAKE_BUILD_TYPE=Release: ์ „์ฒด ํŒจํ‚ค์ง€๋ฅผ -O3 -DNDEBUG๋กœ ์ตœ์ ํ™” ๋นŒ๋“œ (์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„ ์‹ค์‹œ๊ฐ„์„ฑ ํ™•๋ณด์— ํ•„์ˆ˜)
  • --event-handlers console_direct+: ๋นŒ๋“œ ๋กœ๊ทธ๋ฅผ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ถœ๋ ฅ (์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” C++ ํŒจํ‚ค์ง€ ์ง„ํ–‰ ์ƒํ™ฉ ํ™•์ธ)

์ดํ›„ ์นด๋ฉ”๋ผ์™€ GUI๋ฅผ ๊ฐ๊ฐ ์‹คํ–‰ โ€” ์‹คํ–‰ > ๊ฐœ๋ณ„ ๋ชจ๋“ˆ ์ฐธ๊ณ .


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

ํ•„์ˆ˜

ํ•ญ๋ชฉ ์š”๊ตฌ์‚ฌํ•ญ
OS Ubuntu 22.04
ROS2 Humble
Python 3.10
Camera Intel RealSense D415 / D435, Orbbec Femto Mega/Bolt, Gemini 2 ๋“ฑ (USB 3.0)

ํ•˜๋“œ์›จ์–ด (์ง€์› ๋กœ๋ด‡)

๋กœ๋ด‡ ์—ฐ๊ฒฐ ๋ฐฉ์‹ ๋น„๊ณ 
UR TCP ์†Œ์ผ“ (ํฌํŠธ 30003, read-only) ํŽœ๋˜ํŠธ ์ œ์–ด ์œ ์ง€
Doosan DRFL ๋ชจ๋‹ˆํ„ฐ๋ง (dsr_pose_reader) ํŽœ๋˜ํŠธ ์ œ์–ด ์œ ์ง€
๊ธฐํƒ€ ROS2 TF ๋ฐฉ์‹ TF ํผ๋ธ”๋ฆฌ์‹œ ๋…ธ๋“œ ํ•„์š”

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

ROS2 ํŒจํ‚ค์ง€:

  • rclpy, rclcpp, sensor_msgs, geometry_msgs, cv_bridge, tf2_ros
  • ์นด๋ฉ”๋ผ ๋“œ๋ผ์ด๋ฒ„: realsense2_camera (v4.55.1) ๋˜๋Š” OrbbecSDK_ROS2 (v2-main) โ€” VCS๋กœ ์„ ํƒ ์„ค์น˜

Python ํŒจํ‚ค์ง€:

  • numpy (<2.0), scipy, sympy
  • opencv-contrib-python-headless 4.10.0.84 (ArUco ๋ชจ๋“ˆ ํฌํ•จ)
  • PyQt5, matplotlib

C++ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (vendored):

  • DRFL (Doosan Robotics, BSD)
  • Poco (PocoFoundation, PocoNet)

์™ธ๋ถ€ ํŒจํ‚ค์ง€

ํŒจํ‚ค์ง€ ์ถœ์ฒ˜ ์šฉ๋„
hand_eye_calibration https://github.com/ethz-asl/hand_eye_calibration DQ RANSAC ์†”๋ฒ„
handeye-4dof https://github.com/QuantuMope/handeye-4dof 4-DOF ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜
realsense-ros https://github.com/realsenseai/realsense-ros (v4.55.1) RealSense ROS2 ๋“œ๋ผ์ด๋ฒ„
OrbbecSDK_ROS2 https://github.com/orbbec/OrbbecSDK_ROS2 (v2-main) Orbbec ROS2 ๋“œ๋ผ์ด๋ฒ„
DRFL https://robotlab.doosanrobotics.com/ko/Index Doosan ๋กœ๋ด‡ ๋ชจ๋‹ˆํ„ฐ๋ง

์„ค์น˜

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

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

# 2. (Orbbec ์‚ฌ์šฉ ์‹œ, ์ตœ์ดˆ 1ํšŒ) ํ˜ธ์ŠคํŠธ์—์„œ udev rules ์„ค์น˜
#    OrbbecSDK_ROS2๋Š” ์ปจํ…Œ์ด๋„ˆ์—์„œ ์†Œ์Šค ๋นŒ๋“œ๋˜๋ฏ€๋กœ udev rules๋Š” ํ˜ธ์ŠคํŠธ์—์„œ ์ˆ˜๋™ ์„ค์น˜ ํ•„์š”
sudo bash src/OrbbecSDK_ROS2/orbbec_camera/scripts/install_udev_rules.sh
sudo udevadm control --reload-rules && sudo udevadm trigger
#    ์ดํ›„ ์นด๋ฉ”๋ผ USB๋ฅผ ๋ฝ‘์•˜๋‹ค ๋‹ค์‹œ ์—ฐ๊ฒฐ

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

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

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

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

Method 2: Native

1. ์‹œ์Šคํ…œ ์˜์กด์„ฑ (์„ผ์„œ ๊ณตํ†ต)

# ROS2 ๊ณตํ†ต ํŒจํ‚ค์ง€ ์˜์กด์„ฑ
sudo apt install -y \
  ros-humble-cv-bridge \
  ros-humble-tf2-ros \
  ros-humble-tf2-geometry-msgs \
  ros-humble-image-transport

2. Python ํŒจํ‚ค์ง€

pip3 install \
  'numpy>=1.21.0,<2.0' \
  scipy sympy \
  opencv-contrib-python-headless==4.10.0.84 \
  PyQt5 PyQt5-sip matplotlib

3. ๋น„์ „ ์„ผ์„œ๋ณ„ ์ถ”๊ฐ€ ์„ค์น˜

Intel RealSense (D415 / D435 ๋“ฑ)
sudo apt update && sudo apt install -y ros-humble-realsense2-*

# ์‹คํ–‰ ํ™•์ธ
ros2 launch realsense2_camera rs_launch.py

USB 3.0 ์—ฐ๊ฒฐ ํ•„์ˆ˜. ์ธ์‹ ๋ถˆ๊ฐ€ ์‹œ ๋ฌธ์ œ ํ•ด๊ฒฐ > RealSense ์นด๋ฉ”๋ผ ์ธ์‹ ์•ˆ ๋จ ์ฐธ๊ณ .

Orbbec (Femto Mega/Bolt, Gemini 2 / 330 ์‹œ๋ฆฌ์ฆˆ ๋“ฑ)
sudo apt update && sudo apt install -y \
  ros-humble-orbbec-camera \
  ros-humble-orbbec-description

# ์žฅ์น˜ ์ธ์‹ ํ™•์ธ & ์‹คํ–‰
ros2 run orbbec_camera list_devices_node
ros2 launch orbbec_camera <model>.launch.py

udev rules์€ apt ํŒจํ‚ค์ง€์— ํฌํ•จ๋˜์–ด ์ž๋™ ์„ค์น˜๋จ. ์ธ์‹ ๋ถˆ๊ฐ€ ์‹œ sudo udevadm control --reload-rules && sudo udevadm trigger ์žฌ์‹คํ–‰ ๋˜๋Š” ์žฅ์น˜ ์žฌ์—ฐ๊ฒฐ.

์ฃผ์š” <model> launch ํŒŒ์ผ ๋งคํ•‘:

๋ชจ๋ธ launch ํŒŒ์ผ
Femto Mega / Mega I femto_mega.launch.py
Femto Bolt femto_bolt.launch.py
Gemini 2 gemini2.launch.py
Gemini 2 L gemini2L.launch.py
Gemini 330 / 335 / 336 ์‹œ๋ฆฌ์ฆˆ gemini_330_series.launch.py
Astra 2 astra2.launch.py

Docker ์‚ฌ์šฉ ์‹œ ์„ค์ • > Docker ์„ค์ •์˜ ORBBEC_MODEL์„ ์‚ฌ์šฉ ๋ชจ๋ธ๋กœ ์ง€์ •ํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ camera-orbbec ํ•จ์ˆ˜๋กœ ๋ฐ”๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅ.

ํŠน์ • ๋ฒ„์ „ ๊ณ ์ •์ด๋‚˜ ์ตœ์‹  ์†Œ์Šค ๋นŒ๋“œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ camera_realsense.repos / camera_orbbec.repos๋ฅผ ์ด์šฉํ•œ vcs import + colcon build ๋ฐฉ์‹๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.


๋นŒ๋“œ

์ „์ฒด ๋นŒ๋“œ

cd ~/ros2_ws
colcon build --symlink-install \
  --event-handlers console_direct+ \
  --cmake-args -DCMAKE_BUILD_TYPE=Release
source install/setup.bash

-DCMAKE_BUILD_TYPE=Release๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ „์ฒด ํŒจํ‚ค์ง€์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. Orbbec OrbbecSDK_ROS2๋Š” Release ๋นŒ๋“œ๊ฐ€ ํŠนํžˆ ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. --event-handlers console_direct+๋Š” ๋นŒ๋“œ ๋กœ๊ทธ๋ฅผ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

ํŠน์ • ๋ชจ๋“ˆ ๋นŒ๋“œ

colcon build --symlink-install --packages-select hand_eye_calibration
colcon build --symlink-install --packages-select dsr_pose_reader

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

rm -rf build install log
colcon build --symlink-install \
  --event-handlers console_direct+ \
  --cmake-args -DCMAKE_BUILD_TYPE=Release
source install/setup.bash

์‹คํ–‰

์นด๋ฉ”๋ผ์™€ GUI๋Š” ํ•ญ์ƒ ๋ณ„๋„ ํ„ฐ๋ฏธ๋„(๋˜๋Š” alias)๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋Š” ๋น„์ „ ์„ผ์„œ๋งˆ๋‹ค launch ๋ช…๋ น์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, ํ†ตํ•ฉ launch ํŒŒ์ผ์€ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ณ„ ๋ชจ๋“ˆ ์‹คํ–‰

์นด๋ฉ”๋ผ: Intel RealSense (D415 / D435 ๋“ฑ)

ros2 launch realsense2_camera rs_launch.py \
  rgb_camera.color_profile:=1280x720x30 \
  depth_module.depth_profile:=1280x720x30 \
  align_depth.enable:=true
  • ํ† ํ”ฝ: /camera/camera/color/image_raw, /camera/camera/color/camera_info
  • Docker: camera-realsense ํ•จ์ˆ˜๋กœ ๋™์ผ ๋ช…๋ น ์‹คํ–‰

์นด๋ฉ”๋ผ: Orbbec (Femto Mega/Bolt, Gemini 2 / 330 ์‹œ๋ฆฌ์ฆˆ ๋“ฑ)

ros2 run orbbec_camera list_devices_node                # ์žฅ์น˜ ์ธ์‹ ํ™•์ธ
ros2 launch orbbec_camera <model>.launch.py \
  color_width:=1280 color_height:=720 color_fps:=30
  • <model>: femto_mega, femto_bolt, gemini2, gemini2L, gemini_330_series, astra2 ๋“ฑ
  • Docker: camera-orbbec ํ•จ์ˆ˜ ์‚ฌ์šฉ (๋ชจ๋ธยทํ•ด์ƒ๋„๋Š” config.sh์˜ ORBBEC_MODEL, ORBBEC_COLOR_*๋กœ ์ง€์ •)
  • ํ† ํ”ฝ prefix๊ฐ€ RealSense(/camera/camera/color/...)์™€ ๋‹ค๋ฅด๊ฒŒ /camera/color/...๋กœ ํผ๋ธ”๋ฆฌ์‹œ๋จ. Docker ํ•จ์ˆ˜ gui-orbbec์ด ํ•ด๋‹น ํ† ํ”ฝ์„ ์ž๋™ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์—ฌ ๊ตฌ๋… (Native ์‹คํ–‰ ์‹œ ์•„๋ž˜ GUI ๋‹จ๋… ์‹คํ–‰ ์˜ˆ์‹œ ์ฐธ๊ณ )

GUI ๋‹จ๋… ์‹คํ–‰:

# RealSense (config/default.yaml์˜ ํ† ํ”ฝ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ)
ros2 run hand_eye_calibration gui_node

# Orbbec (ํ† ํ”ฝ prefix๊ฐ€ ๋‹ค๋ฅด๋ฏ€๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ์˜ค๋ฒ„๋ผ์ด๋“œ)
ros2 run hand_eye_calibration gui_node --ros-args \
  -p image_topic:=/camera/color/image_raw \
  -p camera_info_topic:=/camera/color/camera_info

UR ๋กœ๋ด‡ (UR Direct ๋ชจ๋“œ):

GUI์—์„œ UR Direct ๋ชจ๋“œ๋กœ ์ง์ ‘ ์—ฐ๊ฒฐํ•˜๋ฏ€๋กœ ๋ณ„๋„ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

Doosan ๋กœ๋ด‡ (dsr_pose_reader + ROS2 TF ๋ชจ๋“œ):

dsr_pose_reader๋ฅผ ๋จผ์ € ์‹คํ–‰ํ•˜๊ณ , GUI์—์„œ ROS2 TF ๋ชจ๋“œ๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

# ํ„ฐ๋ฏธ๋„ 1: Doosan ํฌ์ฆˆ ๋ฆฌ๋”
ros2 launch dsr_pose_reader dsr_pose_reader.launch.py

# ์ปค์Šคํ…€ yaml ์ง€์ •
ros2 launch dsr_pose_reader dsr_pose_reader.launch.py config_file:=/path/to/custom.yaml

# ํ„ฐ๋ฏธ๋„ 2/3: ์นด๋ฉ”๋ผ + GUI (์œ„ "์นด๋ฉ”๋ผ" ํ•ญ๋ชฉ ์ฐธ๊ณ )
camera-realsense   # ๋˜๋Š” camera-orbbec
gui-realsense      # ๋˜๋Š” gui-orbbec

Docker ์‹คํ–‰

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

cd docker
./run.sh

# ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€ โ€” build ํ•จ์ˆ˜๊ฐ€ Release ๋นŒ๋“œ + source๋ฅผ ํ•จ๊ป˜ ์‹คํ–‰
build

# ์นด๋ฉ”๋ผ์™€ GUI๋ฅผ ๋ณ„๋„ ์…ธ์—์„œ ์‹คํ–‰ (์ถ”๊ฐ€ ์…ธ์€ ./run.sh ์žฌ์‹คํ–‰์œผ๋กœ attach)
camera-realsense   # ๋˜๋Š” camera-orbbec
gui-realsense      # ๋˜๋Š” gui-orbbec

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

Command ์„ค๋ช… ์ฐธ๊ณ 
camera-realsense RealSense ์นด๋ฉ”๋ผ ์‹คํ–‰ โ€”
camera-orbbec Orbbec ์นด๋ฉ”๋ผ ์‹คํ–‰ config.sh์˜ ORBBEC_MODEL (๋ชจ๋ธ), ORBBEC_COLOR_WIDTH/HEIGHT/FPS (ํ•ด์ƒ๋„) ์‚ฌ์šฉ
gui-realsense GUI ์‹คํ–‰ (RealSense ํ† ํ”ฝ) gui_node.py
gui-orbbec GUI ์‹คํ–‰ (Orbbec ํ† ํ”ฝ) image_topic / camera_info_topic ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ /camera/color/...๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ
doosan Doosan ํฌ์ฆˆ ๋ฆฌ๋” ์‹คํ–‰ dsr_pose_reader.launch.py
build ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋นŒ๋“œ Release ๋นŒ๋“œ + install/setup.bash ์ ์šฉ
cmd-help ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ช…๋ น์–ด ๋ชฉ๋ก ์ถœ๋ ฅ ์ปจํ…Œ์ด๋„ˆ ์ ‘์† ์‹œ ์ž๋™ ์ถœ๋ ฅ

์‚ฌ์šฉ๋ฒ•

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

๋กœ๋ด‡ ์—ฐ๊ฒฐ  โ”€โ”€โ”€โ”€โ–ถ ๋งˆ์ปค ํ™•์ธ โ”€โ”€โ”€โ”€โ–ถ ํฌ์ฆˆ ์ˆ˜์ง‘ (15~30) โ”€โ”€โ”€โ”€โ–ถ ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ โ”€โ”€โ”€โ”€โ–ถ ๊ฒฐ๊ณผ ํ™•์ธ โ”€โ”€โ”€โ”€โ–ถ ์ €์žฅ

1. ๋กœ๋ด‡ ์—ฐ๊ฒฐ

GUI ์ƒ๋‹จ์—์„œ:

  • ๋กœ๋ด‡ ๋ชจ๋“œ ์„ ํƒ: UR Direct ๋˜๋Š” ROS2 TF
  • UR Direct: IP/Port ์ž…๋ ฅ โ†’ Connect (read-only ์†Œ์ผ“, ํŽœ๋˜ํŠธ ์ œ์–ด ์œ ์ง€)
  • ROS2 TF: Base Frame / EE Frame ์ž…๋ ฅ โ†’ Connect (dsr_pose_reader ๋“ฑ TF ํผ๋ธ”๋ฆฌ์‹œ ๋…ธ๋“œ ํ•„์š”)

2. ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘

  1. ์นด๋ฉ”๋ผ ์˜์ƒ์— ArUco ๋งˆ์ปค๊ฐ€ ๋ณด์ด๋Š”์ง€ ํ™•์ธ (์ดˆ๋ก์ƒ‰ ์ถ•์ด ๊ทธ๋ ค์ง)
  2. ๋กœ๋ด‡์„ ํŽœ๋˜ํŠธ๋กœ ๋‹ค์–‘ํ•œ ์ž์„ธ๋กœ ์ด๋™
  3. Capture Pose ํด๋ฆญ โ†’ ๋กœ๋ด‡ ํฌ์ฆˆ + ๋งˆ์ปค ํฌ์ฆˆ๊ฐ€ ์ €์žฅ๋จ
  4. 15~30๊ฐœ ํฌ์ฆˆ๋ฅผ ๋‹ค์–‘ํ•œ ๊ฐ๋„๋กœ ์ˆ˜์ง‘
  5. ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๋Š” ์„ ํƒ ํ›„ Delete Selected

3. ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ์‹คํ–‰

  1. ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ: DQ RANSAC (๊ธฐ๋ณธ, ๊ถŒ์žฅ) ๋˜๋Š” Tsai-Lenz
  2. Calibrate ํด๋ฆญ
  3. ๊ฒฐ๊ณผ: 4x4 ๋ณ€ํ™˜ ํ–‰๋ ฌ + RMSE ํ‘œ์‹œ

4. ๊ฒฐ๊ณผ ํ™•์ธ

  • Calibration Result: ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ๋ฅผ 3D ์ขŒํ‘œ๊ณ„๋กœ ์‹œ๊ฐํ™”
  • Data Poses: ์ˆ˜์ง‘๋œ ํฌ์ฆˆ ์Œ์„ 3D ํ”Œ๋กฏ์œผ๋กœ ํ™•์ธ

5. ๊ฒฐ๊ณผ ์ €์žฅ

  • Save Result: ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ๋ฅผ data/calibration_result_*.txt์— ์ €์žฅ
  • Save Data: ํฌ์ฆˆ ๋ฐ์ดํ„ฐ๋ฅผ data/pose_pairs.csv์— ์ €์žฅ
  • Load Data: ์ด์ „์— ์ €์žฅํ•œ CSV ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€ ์žฌ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ ๊ฐ€๋Šฅ

์„ค์ •

Docker ์„ค์ •

config.sh

IMAGE_NAME="hhanoo/project:hand-eye-calibration-humble"  # Docker Hub ์ด๋ฏธ์ง€ (๊ธฐ๋ณธ๊ฐ’)
CONTAINER_NAME="hand-eye-calibration-humble"              # Docker ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„
ROS_DOMAIN_ID=98                                          # ROS2 domain
XAUTHORITY_PATH="$HOME/.Xauthority"                       # ํ˜ธ์ŠคํŠธ์˜ .Xauthority (Qt GUI / RViz ํ‘œ์‹œ์šฉ)
ORBBEC_MODEL="femto_bolt"                                 # camera-orbbec ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰ํ•  Orbbec ๋ชจ๋ธ
                                                          # (femto_mega, femto_bolt, gemini2, gemini2L, gemini_330_series ๋“ฑ)
ORBBEC_COLOR_WIDTH=1280                                   # Orbbec color ์ŠคํŠธ๋ฆผ ๋„ˆ๋น„
ORBBEC_COLOR_HEIGHT=720                                   # Orbbec color ์ŠคํŠธ๋ฆผ ๋†’์ด
ORBBEC_COLOR_FPS=30                                       # Orbbec color ์ŠคํŠธ๋ฆผ FPS

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

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

DDS (CycloneDDS) ์„ค์ •

RealSense / Orbbec์˜ HD ํ”„๋ ˆ์ž„์€ ๊ธฐ๋ณธ Fast DDS์—์„œ "Sequence Size Exceeds remaining buffer" ์˜ค๋ฅ˜๋กœ drop๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด, Docker ํ™˜๊ฒฝ์€ CycloneDDS๋ฅผ ๊ธฐ๋ณธ RMW๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • entrypoint.sh: ์ปจํ…Œ์ด๋„ˆ ์ง„์ž… ์‹œ RMW_IMPLEMENTATION=rmw_cyclonedds_cpp, CYCLONEDDS_URI=file:///etc/cyclonedds.xml export
  • cyclonedds.xml: RTPS ๋ ˆ๋ฒจ์—์„œ ๋Œ€์šฉ๋Ÿ‰ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์•ˆ์ •ํ™”ํ•˜๋Š” ํŠœ๋‹ ๊ฐ’
    • MaxMessageSize=65500B -- IP ๋ ˆ๋ฒจ fragmentation ๋Œ€์‹  Cyclone์ด ์ง์ ‘ ๋ถ„ํ• 
    • SocketReceiveBufferSize min="10MB" -- HD ํ”„๋ ˆ์ž„ burst ๋ฒ„ํผ๋ง
  • run.sh: ์œ„ ๋ฒ„ํผ ๊ฐ’์ด ์‹ค์ œ๋กœ ์ ์šฉ๋˜๋„๋ก ํ˜ธ์ŠคํŠธ ์ปค๋„ sysctl ํŠœ๋‹ ์ˆ˜ํ–‰ (sudo ํ•„์š”)
    • net.core.rmem_max / wmem_max = 64MB
    • net.ipv4.ipfrag_time=3, ipfrag_high_thresh=128MB

Native ํ™˜๊ฒฝ์—์„œ๋„ ๋Œ€์šฉ๋Ÿ‰ ์„ผ์„œ ๋ฉ”์‹œ์ง€๋ฅผ ๋‹ค๋ฃฐ ๋•Œ๋Š” ๋™์ผํ•œ RMW / sysctl ํŠœ๋‹์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
sudo apt install ros-humble-rmw-cyclonedds-cpp ํ›„ ์œ„ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ export ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

hand_eye_calibration/config/default.yaml

hand_eye_calibration:
  ros__parameters:
    # ์นด๋ฉ”๋ผ ํ† ํ”ฝ
    image_topic: "/camera/camera/color/image_raw"
    camera_info_topic: "/camera/camera/color/camera_info"

    # ArUco ๋งˆ์ปค ์„ค์ •
    marker_dict: 10 # cv2.aruco.DICT_6X6_250
    board_grid_shape: [5, 7] # ๊ทธ๋ฆฌ๋“œ ๋ณด๋“œ (cols, rows)
    marker_length: 0.037 # ๋งˆ์ปค ํฌ๊ธฐ (m)
    marker_separation: 0.003 # ๋งˆ์ปค ๊ฐ„๊ฒฉ (m)

    # ๋กœ๋ด‡ ์„ค์ •
    robot_mode: "ur_direct" # "ur_direct" ๋˜๋Š” "ros2_tf"

    # ROS2 TF ์„ค์ •
    tf_base_frame: "base_link"
    tf_ee_frame: "tool0"

    # ๋ฐ์ดํ„ฐ ์ €์žฅ ๊ฒฝ๋กœ
    data_dir: "data/"

dsr_pose_reader/config/default.yaml

dsr_pose_reader:
  ros__parameters:
    robot_ip: "192.168.137.101" # Doosan ์ปจํŠธ๋กค๋Ÿฌ IP
    robot_port: 12345 # Doosan ์ปจํŠธ๋กค๋Ÿฌ ํฌํŠธ
    base_frame: "base_link" # TF base frame
    ee_frame: "tool0" # TF end-effector frame
    publish_rate: 30.0 # Hz
    publish_tf: true # TF ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ํ™œ์„ฑํ™”

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

ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
marker_length float 0.037 ArUco ๋งˆ์ปค ํ•œ ๋ณ€์˜ ์‹ค์ œ ํฌ๊ธฐ (m) -- ์ •ํ™•๋„์— ๋งค์šฐ ์ค‘์š”
marker_separation float 0.003 ๊ทธ๋ฆฌ๋“œ ๋ณด๋“œ์—์„œ ๋งˆ์ปค ๊ฐ„ ๊ฐ„๊ฒฉ (m)
board_grid_shape list [5, 7] ๊ทธ๋ฆฌ๋“œ ๋ณด๋“œ์˜ (์—ด, ํ–‰) ์ˆ˜
robot_mode string "ur_direct" ๋กœ๋ด‡ ํฌ์ฆˆ ํš๋“ ๋ฐฉ์‹ ("ur_direct" / "ros2_tf")

Launch ์ธ์ž

dsr_pose_reader.launch.py:

์ธ์ž ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
config_file config/default.yaml ํŒŒ๋ผ๋ฏธํ„ฐ YAML ํŒŒ์ผ ๊ฒฝ๋กœ
ros2 launch dsr_pose_reader dsr_pose_reader.launch.py config_file:=/path/to/custom.yaml

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

๋…ธ๋“œ

๋…ธ๋“œ ์–ธ์–ด ํŒจํ‚ค์ง€ ์„ค๋ช…
hand_eye_calibration Python hand_eye_calibration ์บ˜๋ฆฌ๋ธŒ๋ ˆ์ด์…˜ GUI + ROS2 ๋…ธ๋“œ
dsr_pose_reader C++ dsr_pose_reader Doosan ๋กœ๋ด‡ TCP ํฌ์ฆˆ ํผ๋ธ”๋ฆฌ์…”

Subscribed ํ† ํ”ฝ

Topic Type ๋…ธ๋“œ ์„ค๋ช…
/camera/camera/color/image_raw sensor_msgs/msg/Image hand_eye_calibration RGB ์นด๋ฉ”๋ผ ์ด๋ฏธ์ง€
/camera/camera/color/camera_info sensor_msgs/msg/CameraInfo hand_eye_calibration ์นด๋ฉ”๋ผ ๋‚ด๋ถ€ ํŒŒ๋ผ๋ฏธํ„ฐ

Published ํ† ํ”ฝ

Topic Type ๋…ธ๋“œ ์„ค๋ช…
tcp_pose geometry_msgs/msg/PoseStamped dsr_pose_reader Doosan TCP ํฌ์ฆˆ (base ๊ธฐ์ค€)
/tf tf2_msgs/msg/TFMessage dsr_pose_reader base_link โ†’ tool0 ๋ณ€ํ™˜ (์˜ต์…˜)

์„œ๋น„์Šค

ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๋Š” ROS2 ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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

ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๋Š” ์ปค์Šคํ…€ ๋ฉ”์‹œ์ง€๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ‘œ์ค€ ROS2 ๋ฉ”์‹œ์ง€ ํƒ€์ž…์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

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

๋Œ€์ƒ ํ”„๋กœํ† ์ฝœ ํฌํŠธ ๋ฐฉํ–ฅ ๋น„๊ณ 
UR ๋กœ๋ด‡ TCP 30003 read-only ๋กœ๋ด‡์— ๋ช…๋ น ์ „์†กํ•˜์ง€ ์•Š์Œ
Doosan ๋กœ๋ด‡ TCP 12345 monitoring DRFL ๋ชจ๋‹ˆํ„ฐ๋ง ์ „์šฉ
RealSense ์นด๋ฉ”๋ผ USB 3.0 - - ROS2 ํ† ํ”ฝ์œผ๋กœ ์ˆ˜์‹ 

๋ฌธ์ œ ํ•ด๊ฒฐ

1. Qt ํ”Œ๋Ÿฌ๊ทธ์ธ ์ถฉ๋Œ

์ฆ์ƒ:

qt.qpa.plugin: Could not load the Qt platform plugin "xcb"

ํ•ด๊ฒฐ:

  • Dockerfile์—์„œ opencv-contrib-python-headless ์‚ฌ์šฉ (OpenCV ๋ฒˆ๋“ค Qt ์ œ๊ฑฐ)
  • ๋˜๋Š” gui_node.py ์ƒ๋‹จ์— os.environ.pop("QT_QPA_PLATFORM_PLUGIN_PATH", None) ํ™•์ธ

2. RealSense ์นด๋ฉ”๋ผ ์ธ์‹ ์•ˆ ๋จ

์ฆ์ƒ:

lsusb | grep Intel  # ๊ฒฐ๊ณผ ์—†์Œ

ํ•ด๊ฒฐ:

sudo usermod -aG video $USER
sudo usermod -aG plugdev $USER

3. ArUco ๋งˆ์ปค ๊ฒ€์ถœ ์•ˆ ๋จ

  • ์กฐ๋ช…์ด ์ถฉ๋ถ„ํ•œ์ง€ ํ™•์ธ
  • ์นด๋ฉ”๋ผ์—์„œ ๋งˆ์ปค๊นŒ์ง€ ๊ฑฐ๋ฆฌ: 0.3m ~ 2m ๊ถŒ์žฅ
  • marker_length ๊ฐ’์ด ์‹ค์ œ ๋งˆ์ปค ํฌ๊ธฐ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ

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

์ฆ์ƒ:

AttributeError: module 'numpy' has no attribute 'bool'

ํ•ด๊ฒฐ:

pip3 install 'numpy>=1.21.0,<2.0'

5. Docker์—์„œ GUI ํ‘œ์‹œ ์•ˆ ๋จ

์ฆ์ƒ:

cannot open display: :0

ํ•ด๊ฒฐ:

# ํ˜ธ์ŠคํŠธ์—์„œ X11 ์ ‘๊ทผ ํ—ˆ์šฉ
xhost +local:docker

# DISPLAY ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ™•์ธ
echo $DISPLAY

6. Orbbec ์นด๋ฉ”๋ผ Failed to get NVRAM data, timeout

์ฆ์ƒ:

list_devices_node๋Š” ์นด๋ฉ”๋ผ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ฐพ์ง€๋งŒ, launch ์งํ›„ ์•ฝ 10์ดˆ ๋’ค ํƒ€์ž„์•„์›ƒ์œผ๋กœ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋จ.

ํ•ด๊ฒฐ ์ˆœ์„œ:

  1. ํ˜ธ์ŠคํŠธ์—์„œ OrbbecViewer ๋“ฑ ์นด๋ฉ”๋ผ๋ฅผ ์ ์œ  ์ค‘์ธ ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ
  2. ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์™„์ „ํžˆ ๋‚ด๋ฆผ: docker stop <name> && docker rm <name>
  3. ์นด๋ฉ”๋ผ USB + 12V ์ „์› ์–ด๋Œ‘ํ„ฐ ๋ชจ๋‘ ๋ฝ‘๊ณ  5์ดˆ ํ›„ ์žฌ์—ฐ๊ฒฐ
  4. ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹คํ–‰ ํ›„ launch ์žฌ์‹œ๋„

Femto Bolt๋Š” 12V ์™ธ๋ถ€ ์ „์› ์–ด๋Œ‘ํ„ฐ๊ฐ€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค (USB ๋ฒ„์Šค ํŒŒ์›Œ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑ).

7. ๋Œ€์šฉ๋Ÿ‰ ์„ผ์„œ ๋ฉ”์‹œ์ง€ drop / Sequence Size Exceeds remaining buffer

์ฆ์ƒ:

RealSense / Orbbec HD ํ”„๋ ˆ์ž„ ๊ตฌ๋… ์‹œ Fast DDS๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ dropํ•˜๊ฑฐ๋‚˜ ์œ„ ์˜ค๋ฅ˜ ๋กœ๊ทธ ์ถœ๋ ฅ.

ํ•ด๊ฒฐ:

Docker ํ™˜๊ฒฝ์€ ์„ค์ • > DDS (CycloneDDS) ์„ค์ •์— ๋”ฐ๋ผ ์ด๋ฏธ CycloneDDS + sysctl ํŠœ๋‹์ด ์ ์šฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Native ํ™˜๊ฒฝ์ด๊ฑฐ๋‚˜ run.sh๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฝ์šฐ ํ˜ธ์ŠคํŠธ์—์„œ ๋‹ค์Œ์„ ์ˆ˜๋™ ์ ์šฉํ•˜์„ธ์š”.

sudo sysctl -w net.core.rmem_max=67108864
sudo sysctl -w net.core.wmem_max=67108864
sudo sysctl -w net.ipv4.ipfrag_high_thresh=134217728

export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export CYCLONEDDS_URI=file:///etc/cyclonedds.xml   # ๋˜๋Š” ๋กœ์ปฌ ๊ฒฝ๋กœ

๋ผ์ด์„ ์Šค

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


Maintainer

hhanoo (woo980711@gmail.com)

About

ROS2 Humble hand-eye calibration system with PyQt5 GUI. (6DOF: UR, Doosan)

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors