DrawingProcess
๋“œํ”„ DrawingProcess
DrawingProcess
์ „์ฒด ๋ฐฉ๋ฌธ์ž
์˜ค๋Š˜
์–ด์ œ
ยซ   2025/06   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (968) N
    • Profile & Branding (25)
      • Career (18)
    • IT Trends (254)
      • Conference, Faire (Experien.. (31)
      • News (187)
      • Youtube (19)
      • TED (8)
      • Web Page (2)
      • IT: Etc... (6)
    • Contents (98) N
      • Book (67) N
      • Lecture (31)
    • Project Process (94)
      • Ideation (0)
      • Study Report (34)
      • Challenge & Award (22)
      • 1Day1Process (5)
      • Making (5)
      • KRC-FTC (Team TC(5031, 5048.. (10)
      • GCP (GlobalCitizenProject) (15)
    • Study: ComputerScience(CS) (72)
      • CS: Basic (9)
      • CS: Database(SQL) (5)
      • CS: Network (14)
      • CS: OperatingSystem (3)
      • CS: Linux (39)
      • CS: Etc... (2)
    • Study: Software(SW) (95)
      • SW: Language (29)
      • SW: Algorithms (1)
      • SW: DataStructure & DesignP.. (1)
      • SW: Opensource (15)
      • SW: Error Bug Fix (43)
      • SW: Etc... (6)
    • Study: Artificial Intellige.. (149)
      • AI: Research (1)
      • AI: 2D Vision(Det, Seg, Tra.. (35)
      • AI: 3D Vision (70)
      • AI: MultiModal (3)
      • AI: SLAM (0)
      • AI: Light Weight(LW) (3)
      • AI: Data Pipeline (7)
      • AI: Machine Learning(ML) (1)
    • Study: Robotics(Robot) (33)
      • Robot: ROS(Robot Operating .. (9)
      • Robot: Positioning (8)
      • Robot: Planning & Control (7)
    • Study: DeveloperTools(DevTo.. (83)
      • DevTool: Git (12)
      • DevTool: CMake (13)
      • DevTool: NoSQL(Elastic, Mon.. (25)
      • DevTool: Container (17)
      • DevTool: IDE (11)
      • DevTool: CloudComputing (4)
    • ์ธ์ƒ์„ ์‚ด๋ฉด์„œ (64)
      • ๋‚˜์˜ ์ทจ๋ฏธ๋“ค (7)
      • ๋‚˜์˜ ์ƒ๊ฐ๋“ค (42)
      • ์—ฌํ–‰์„ ๋– ๋‚˜์ž~ (10)
      • ๋ถ„๊ธฐ๋ณ„ ํšŒ๊ณ  (5)

๊ฐœ๋ฐœ์ž ๋ช…์–ธ

โ€œ ๋งค์ฃผ ๋ชฉ์š”์ผ๋งˆ๋‹ค ๋‹น์‹ ์ด ํ•ญ์ƒ ํ•˜๋˜๋Œ€๋กœ ์‹ ๋ฐœ๋ˆ์„ ๋ฌถ์œผ๋ฉด ์‹ ๋ฐœ์ด ํญ๋ฐœํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ผ.
์ปดํ“จํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ด๋Ÿฐ ์ผ์ด ํ•ญ์ƒ ์ผ์–ด๋‚˜๋Š”๋ฐ๋„ ์•„๋ฌด๋„ ๋ถˆํ‰ํ•  ์ƒ๊ฐ์„ ์•ˆ ํ•œ๋‹ค. โ€

- Jef Raskin

๋งฅ์˜ ์•„๋ฒ„์ง€ - ์• ํ”Œ์ปดํ“จํ„ฐ์˜ ๋งคํ‚จํ† ์‹œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ฃผ๋„

์ธ๊ธฐ ๊ธ€

์ตœ๊ทผ ๊ธ€

์ตœ๊ทผ ๋Œ“๊ธ€

ํ‹ฐ์Šคํ† ๋ฆฌ

hELLO ยท Designed By ์ •์ƒ์šฐ.
DrawingProcess

๋“œํ”„ DrawingProcess

[ROS] ROS TF ์ขŒํ‘œ๊ณ„ ๋ฐ ๋ณ€ํ™˜
Study: Robotics(Robot)/Robot: ROS(Robot Operating Sytem)

[ROS] ROS TF ์ขŒํ‘œ๊ณ„ ๋ฐ ๋ณ€ํ™˜

2023. 10. 26. 23:52
๋ฐ˜์‘ํ˜•
๐Ÿ’ก ๋ณธ ๋ฌธ์„œ๋Š” 'ROS TF ์ขŒํ‘œ๊ณ„ ๋ฐ ๋ณ€ํ™˜'์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋†“์€ ๊ธ€์ž…๋‹ˆ๋‹ค.
์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ROS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ฐ”์ผ ๋กœ๋ด‡์˜ ํ‘œ์ค€ ์ขŒํ‘œ๊ณ„(์˜ˆ: x,y,z ์ถ• )์˜ ๊ธฐ๋ณธ ์‚ฌํ•ญ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ธฐ๋ณธ์ ์ธ 2๋ฅœ ์ฐจ๋™ ๊ตฌ๋™ ๋ชจ๋ฐ”์ผ ๋กœ๋ด‡ ์˜ ์ขŒํ‘œ๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๋‹ค๋ฃฐ ๊ฒƒ์ด๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

1. Why Coordinate Frames Are Important?

๋ฐ”ํ€ด ๋‹ฌ๋ฆฐ ๋กœ๋ด‡ ์œ„์— LIDAR๊ฐ€ ์žฅ์ฐฉ๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. LIDAR์˜ ์ž„๋ฌด๋Š” ํ™˜๊ฒฝ ๋‚ด ๋ฌผ์ฒด๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ LIDAR๋Š” ๋ณดํ†ต ๋กœ๋ด‡์˜ ์ค‘์‹ฌ์ ์— ์œ„์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ๋กœ๋ด‡์ด ํ™˜๊ฒฝ์—์„œ ์ด๋™ํ•  ๋•Œ ์žฅ์• ๋ฌผ์„ ํ”ผํ•˜๋ ค๋ฉด LIDAR ์ขŒํ‘œ๊ณ„์—์„œ ๊ฐ์ง€๋œ ๊ฐ์ฒด์˜ ์ขŒํ‘œ๋ฅผ ๋กœ๋ด‡ ๋ฒ ์ด์Šค ํ”„๋ ˆ์ž„์˜ ํ•ด๋‹น ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด LIDAR๋Š” 100cm ๋–จ์–ด์ง„ ๋ฌผ์ฒด๋ฅผ ๊ฐ์ง€ํ•˜๋”๋ผ๋„ LIDAR๊ฐ€ ๋กœ๋ด‡์˜ ์ „๋ฉด๋ถ€(๋กœ๋ด‡ ๋ฒ ์ด์Šค ํ”„๋ ˆ์ž„์˜ ์ค‘์‹ฌ์ ์—์„œ 10cm ์•ž์ชฝ)์— ์žฅ์ฐฉ๋œ ๊ฒฝ์šฐ, ๋ฌผ์ฒด๋Š” ์‹ค์ œ๋กœ ๋กœ๋ด‡์œผ๋กœ๋ถ€ํ„ฐ 110cm ๋–จ์–ด์ ธ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

๋”ฐ๋ผ์„œ ์ •ํ™•ํ•œ ์ž์œจ์ฃผํ–‰์„ ์œ„ํ•ด์„œ๋Š” ์ขŒํ‘œ ํ”„๋ ˆ์ž„๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ์ขŒํ‘œ ํ”„๋ ˆ์ž„์—์„œ ๋‹ค๋ฅธ ์ขŒํ‘œ ํ”„๋ ˆ์ž„์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

2. ๋ชจ๋ฐ”์ผ ๋กœ๋ด‡์„ ์œ„ํ•œ ROS์˜ ํ‘œ์ค€ ์ขŒํ‘œ๊ณ„

์•„๋ž˜๋Š” ๊ธฐ๋ณธ 2๋ฅœ ์ฐจ๋™ ๊ตฌ๋™ ๋กœ๋ด‡์˜ ํ‘œ์ค€ ์ขŒํ‘œ๊ณ„์ž…๋‹ˆ๋‹ค. ๋นจ๊ฐ„์ƒ‰ ํ™”์‚ดํ‘œ๋Š” x์ถ•, ํŒŒ๋ž€์ƒ‰ ํ™”์‚ดํ‘œ๋Š” z์ถ•, ๋…น์ƒ‰ ์ ์€ y์ถ•์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

 

๊ณต์‹ ROS ๋ฌธ์„œ์—๋Š” ์ด๋Ÿฌํ•œ ์ขŒํ‘œ ํ”„๋ ˆ์ž„์— ๋Œ€ํ•œ ์„ค๋ช…์ด ์žˆ์ง€๋งŒ ์ฃผ์š” ์ขŒํ‘œ ํ”„๋ ˆ์ž„์„ ๊ฐ„๋žตํ•˜๊ฒŒ ์ •์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

  • map ํ”„๋ ˆ์ž„์€ world์—์„œ ์ž„์˜๋กœ ์„ ํƒํ•œ ์ง€์ ์—์„œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ์ด ์ขŒํ‘œ๊ณ„๋Š” world ์ขŒํ‘œ๊ณ„์— ๊ณ ์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • odom ํ”„๋ ˆ์ž„์€ ๋กœ๋ด‡์ด ์ดˆ๊ธฐํ™”๋˜๋Š” ์ง€์ ์—์„œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ์ด ์ขŒํ‘œ๊ณ„๋Š” world ์ขŒํ‘œ๊ณ„์— ๊ณ ์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • base_footprint ์˜ ์›์ ์€ ๋กœ๋ด‡ ์ค‘์‹ฌ ๋ฐ”๋กœ ์•„๋ž˜์— ์žˆ์Šต๋‹ˆ๋‹ค. ๋กœ๋ด‡์˜ 2D ํฌ์ฆˆ์ž…๋‹ˆ๋‹ค. ์ด ์ขŒํ‘œ๊ณ„๋Š” ๋กœ๋ด‡์ด ์›€์ง์ผ ๋•Œ ์›€์ง์ž…๋‹ˆ๋‹ค.
  • base_link ์˜ ์›์ ์€ ๋กœ๋ด‡์˜ ํ”ผ๋ฒ—์ ์ด๋‚˜ ์ค‘์‹ฌ์— ์ง์ ‘ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ขŒํ‘œ๊ณ„๋Š” ๋กœ๋ด‡์ด ์›€์ง์ผ ๋•Œ ์›€์ง์ž…๋‹ˆ๋‹ค.
  • laser_link๋Š” ๋ ˆ์ด์ € ์„ผ์„œ(์˜ˆ: LIDAR)์˜ ์ค‘์‹ฌ์—์„œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ์ด ์ขŒํ‘œ ํ”„๋ ˆ์ž„์€ base_link๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ณ ์ •๋œ(์ฆ‰, "์ •์ ") ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋กœ๋ด‡์— IMU ์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์„ผ์„œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, ์ด์— ๋Œ€ํ•œ ์ขŒํ‘œ๊ณ„๋„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. TF(Transform) Publisher: Static, Broadcaster

ํ•œ ์ขŒํ‘œ๊ณ„์— ๊ฒŒ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ์ขŒํ‘œ๊ณ„์˜ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด map ์ขŒํ‘œ๊ณ„์˜ ์ขŒํ‘œ (x=3.7, y=1.23, z = 0.0)์— ๊ฐ์ฒด๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋กœ๋ด‡์„ ์ด ๊ฐ์ฒด๋กœ ์ด๋™์‹œํ‚ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. base_link ์ขŒํ‘œ๊ณ„๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฐœ์ฒด์˜ ์œ„์น˜๋ฅผ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”? ๋‹คํ–‰ํžˆ ROS ์—๋Š” ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์ขŒํ‘œ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•˜๋Š” tf๋ผ๋Š” ํŒจํ‚ค์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ •์  ์ขŒํ‘œ๊ณ„: ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ์„œ๋กœ ์ƒ๋Œ€์ ์œผ๋กœ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ์ขŒํ‘œ ํ”„๋ ˆ์ž„์˜ ๊ฒฝ์šฐ(์˜ˆ: ๋ ˆ์ด์ €๊ฐ€ ๋กœ๋ด‡์— ๋ถ€์ฐฉ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— base_link์— ๋Œ€ํ•œ laser_link๊ฐ€ ์ •์ ์œผ๋กœ ์œ ์ง€๋จ) Static Transform Publisher๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 
  • ๋™์  ์ขŒํ‘œ๊ณ„: ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ์„œ๋กœ ์ƒ๋Œ€์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ์ขŒํ‘œ ํ”„๋ ˆ์ž„์˜ ๊ฒฝ์šฐ(์˜ˆ: base_link์— ๋งคํ•‘) tf broadcasters and listeners๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค . ๋งŽ์€ ROS ํŒจํ‚ค์ง€๊ฐ€ ์ด๋Ÿฌํ•œ ์ด๋™ ์ขŒํ‘œ๊ณ„ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ)

Static transform

ROS์—์„œ ์ •์  ๋ณ€ํ™˜ ๊ฒŒ์‹œ์ž๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ •์  ๋ณ€ํ™˜ ๊ฒŒ์‹œ์ž๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ž‘์—… ์ค‘์ธ ๋กœ๋ด‡์— ๋Œ€ํ•œ ์‹คํ–‰ ํŒŒ์ผ ๋‚ด๋ถ€์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms

ROS ์›น์‚ฌ์ดํŠธ์—์„œ: “๋ฏธํ„ฐ ๋‹จ์œ„์˜ x/y/z ์˜คํ”„์…‹๊ณผ ๋ผ๋””์•ˆ ๋‹จ์œ„์˜ ์š”/ํ”ผ์น˜/๋กค์„ ์‚ฌ์šฉํ•˜์—ฌ tf์— ์ •์  ์ขŒํ‘œ ๋ณ€ํ™˜์„ ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. (์š”๋Š” Z์— ๋Œ€ํ•œ ํšŒ์ „, ํ”ผ์น˜๋Š” Y์— ๋Œ€ํ•œ ํšŒ์ „, ๋กค์€ X์— ๋Œ€ํ•œ ํšŒ์ „) ๊ธฐ๊ฐ„(๋ฐ€๋ฆฌ์ดˆ)์€ ๋ณ€ํ™˜์„ ๋ณด๋‚ด๋Š” ๋นˆ๋„๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. 100ms(10hz)๊ฐ€ ์ข‹์€ ๊ฐ’์ž…๋‹ˆ๋‹ค.”

Map to Odom

์˜ˆ๋ฅผ ๋“ค์–ด, ์ง€๋„ ์™€ ์ฃผํ–‰ ๊ฑฐ๋ฆฌ ์ธก์ • ํ”„๋ ˆ์ž„์„ ๋™๋“ฑํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด ROS ์‹คํ–‰ ํŒŒ์ผ ๋‚ด์— ์ž‘์„ฑํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<node pkg="tf" type="static_transform_publisher" name="map_to_odom" args="0 0 0 0 0 0 map odom 30" />
 

map -> odom ๋ณ€ํ™˜์€ ์ง€๋„์˜ ์ขŒํ‘œ๊ณ„(์ฆ‰, ์ƒ์œ„) ๋‚ด๋ถ€์—์„œ ๋กœ๋ด‡์˜ ์‹œ์ž‘์ (์ฆ‰, ํ•˜์œ„์ธ odom ์ขŒํ‘œ๊ณ„)์˜ ์œ„์น˜์™€ ๋ฐฉํ–ฅ์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์—์„œ๋Š” Odom ํ”„๋ ˆ์ž„์ด ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ๋งต ํ”„๋ ˆ์ž„์„ ๊ธฐ์ค€์œผ๋กœ ์›€์ง์ด์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

Odom to Base Footprint

odom -> base_footprint ๋ณ€ํ™˜์€ ๋กœ๋ด‡์ด ์ „ ์„ธ๊ณ„๋ฅผ ์ด๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •์ ์ด ์•„๋‹™๋‹ˆ๋‹ค. base_footprint ์ขŒํ‘œ๊ณ„๋Š” ๋ฐ”ํ€ด๊ฐ€ ํšŒ์ „ํ•จ์— ๋”ฐ๋ผ ์ง€์†์ ์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ์ด ๋น„์ •์  ๋ณ€ํ™˜์€ ์ข…์ข… robots_pose_ekf ํŒจํ‚ค์ง€ ์™€ ๊ฐ™์€ ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค .

Base Footprint to Base Link

base_footprint -> base_link๋Š” ๋‘ ์ขŒํ‘œ ํ”„๋ ˆ์ž„์ด ์„œ๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ •์  ๋ณ€ํ™˜์ž…๋‹ˆ๋‹ค. ๋กœ๋ด‡์ด ์›€์ง์ด๊ณ  ๋กœ๋ด‡์˜ "๋ฐœ์ž๊ตญ"์˜ ์ขŒํ‘œ๊ณ„๊ฐ€ ์›€์ง์ž…๋‹ˆ๋‹ค.

<node pkg="tf" type="static_transform_publisher" name="base_link_broadcaster" args="0 0 0.09 0 0 0 base_footprint base_link 30" />
 

์œ„์˜ ๊ฒฝ์šฐ, base_link ์ขŒํ‘œ๊ณ„์˜ ์›์ (์ฆ‰, ๋กœ๋ด‡์˜ ์ค‘์‹ฌ)์ด ๋ฐœ์ž๊ตญ ์œ„ 0.09๋ฏธํ„ฐ์— ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

Base Link to Laser

base_link -> Laser ๋ณ€ํ™˜์€ base_link์˜ ์ขŒํ‘œ๊ณ„ ๋‚ด๋ถ€์—์„œ ๋ ˆ์ด์ €์˜ ์œ„์น˜์™€ ๋ฐฉํ–ฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€ํ™˜์€ ์ •์ ์ž…๋‹ˆ๋‹ค.

<node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.06 0 0.08 0 0 0 base_link laser 30" />
 

๋ ˆ์ด์ €๋Š” ๋กœ๋ด‡ ์ค‘์‹ฌ์—์„œ ์•ž์ชฝ์œผ๋กœ 0.06m, ๋กœ๋ด‡ ์ค‘์‹ฌ์—์„œ ์œ„์ชฝ์œผ๋กœ 0.08m์— ์œ„์น˜ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

Base Link to IMU

base_link -> imu ๋ณ€ํ™˜์€ base_link์˜ ์ขŒํ‘œ ํ”„๋ ˆ์ž„ ๋‚ด IMU(๊ด€์„ฑ ์ธก์ • ์žฅ์น˜…์ผ๋ฐ˜์ ์œผ๋กœ BNO055 ์„ผ์„œ)์˜ ์œ„์น˜์™€ ๋ฐฉํ–ฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€ํ™˜์€ ์ •์ ์ž…๋‹ˆ๋‹ค.

<node pkg="tf" type="static_transform_publisher" name="imu_broadcaster" args="0 0.06 0.02 0 0 0 base_link imu 30" />
 

์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ROS์˜ ์ขŒํ‘œ ํ”„๋ ˆ์ž„ ๋ฐ ์ •์  ๋ณ€ํ™˜ ๊ฒŒ์‹œ์ž์˜ ๊ธฐ๋ณธ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. 

Dynamic Publisher

TF Broadcaster

์šฐ์„ , ๋กœ๋ด‡์˜ ๊ท€ํ™˜์ง€๋ฅผ ์›์ ์œผ๋กœ ํ•˜๋Š” ์ขŒํ‘œ๊ณ„์˜ ์ด๋ฆ„์„ home์ด๋ผ๊ณ  ํ•ด๋ณด์ž. ๊ทธ๋ ‡๋‹ค๋ฉด, home ํ”„๋ ˆ์ž„ ์ƒ์—์„œ (-5, 10, 0) ๋งŒํผ ๋–จ์–ด์ง„ ์œ„์น˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„๋  ๊ฒƒ์ด๋‹ค.

#!/usr/bin/python

import rospy
import tf
from geometry_msgs.msg import PoseStamped


class Robot(object):
   def __init__(self):
       position = PoseStamped()

       position.header.frame_id = "home"

       position.pose.position.x = -5
       position.pose.position.y = 10

       position.pose.orientation.w = 1

       self.position = position
       self.pub = rospy.Publisher("robot_pose", PoseStamped, queue_size=1)

   def publishPose(self):
       self.position.header.stamp = rospy.Time.now()

       self.pub.publish(self.position)


if __name__ == '__main__':
   rospy.init_node("tf_pub")

   robot = Robot()

   r = rospy.Rate(1)
   while not rospy.is_shutdown():

       robot.publishPose()

       r.sleep()

์ด๋ฒˆ์—๋Š” home ํ”„๋ ˆ์ž„๊ณผ world ํ”„๋ ˆ์ž„ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์—๋Š” tf.TransformBroadcaster() ํด๋ž˜์Šค์™€, ํ•ด๋‹น ํด๋ž˜์Šค์— ์„ ์–ธ๋œ sendTransform ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•œ๋‹ค.

sendTransform ๋ฉ”์†Œ๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„, TF ๊ด€๊ณ„๋ฅผ ๋ฐœํ–‰ํ•œ๋‹ค.

  • translation: (x, y, z), ์ขŒํ‘œ๊ณ„ ๊ฐ„์˜ ๋ณ‘์ง„์šด๋™์„ ์ •์˜ํ•˜๋Š” ๊ฐ’
  • rotation: (x, y, z, w), ์ขŒํ‘œ๊ณ„ ๊ฐ„์˜ ํšŒ์ „์šด๋™์„ ์ •์˜ํ•˜๋Š” ๊ฐ’
  • time: time, transform์„ ๊ฐ€์ง€๋Š” ์‹œ์ 
  • child: string, ์ž์‹ ํ”„๋ ˆ์ž„์˜ ์ด๋ฆ„
  • parent: string, ๋ถ€๋ชจ ํ”„๋ ˆ์ž„์˜ ์ด๋ฆ„

์—ฌ๊ธฐ์„œ ๋ถ€๋ชจ์™€ ์ž์‹์ด๋ž€, ์–ด๋–ค ํ”„๋ ˆ์ž„์„ ๋” ์ƒ์œ„์˜ ํ”„๋ ˆ์ž„์œผ๋กœ ์ทจ๊ธ‰ํ• ์ง€๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ์œ„์˜ ๋‚ด์šฉ์„ ์ฝ”๋”ฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    tf_broadcaster = tf.TransformBroadcaster()

    r = rospy.Rate(1)
    while not rospy.is_shutdown():

        tf_broadcaster.sendTransform(
            translation=[10, 10, 0],
            rotation=[0., 0., 0., 1],
            time=rospy.Time.now(),
            child="home",
            parent="world"
        )

        robot.publishPose()

        r.sleep()

TF Listener

๋ณด๋‹ค์‹ถ์ด TF ๊ด€๊ณ„์˜ ๋ฐœํ–‰์€ ROS Publisher์™€ ๋งค์šฐ ์œ ์‚ฌํ•œ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ, ์ด์™€ ๋น„์Šทํ•˜๊ฒŒ TF๊ด€๊ณ„ ๋˜ํ•œ, ๊ตฌ๋…ํ•˜์—ฌ ์‹ค์ œ ํ”„๋ ˆ์ž„ ๊ฐ„์˜ ์ขŒํ‘œ ๋ณ€ํ™˜์„ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

๊ตฌ์ฒด์ ์œผ๋กœ๋Š” tf.TransformListener ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค.

#!/usr/bin/python

import rospy
import tf
from geometry_msgs.msg import PoseStamped


if __name__ == '__main__':
    rospy.init_node("tf_listener")

    tf_listener = tf.TransformListener()    # TF Listener ๊ฐ์ฒด ์„ ์–ธ

    r = rospy.Rate(1)
    while not rospy.is_shutdown():

        if tf_listener.canTransform(
                target_frame="world", source_frame="home", time=rospy.Time(0)):
            # TF ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•œ์ง€ ๊ฒ€์‚ฌ. ๋ถˆ๊ฐ€๋Šฅ ํ•  ๋•Œ, lookupTransform์„ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ ์˜ˆ์™ธ ๋ฐœ์ƒ
            # TF ๋ณ€ํ™˜์‹œ ์‹œ๊ฐ„์€ rospy.Time.now()๊ฐ€ ์•„๋‹ˆ๋ผ Time(0)์„ ์จ์•ผํ•œ๋‹ค!!

            tf_matrix = tf_listener.lookupTransform(
                target_frame="world", source_frame="home", time=rospy.Time(0))
            # ๋ณ€ํ™˜ ํ–‰๋ ฌ ๋ฆฌํ„ด. ๋ฆฌํ„ด ๊ฐ’์€ ([x, y, z], [x, y, z, w])

            rospy.loginfo(tf_matrix)

        else:
            rospy.logwarn("Cannot lookup transform between world and home")

        r.sleep()

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

๋˜ํ•œ, ROS Docs๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด, TransformListener๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฌ๋Ÿฌ ๋ฉ”์†Œ๋“œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์ค‘์—์„œ transformPose๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

#!/usr/bin/python

import rospy
import tf
from geometry_msgs.msg import PoseStamped

msg = None


def poseCallback(m):
    global msg
    m.header.stamp = rospy.Time(0)
    msg = m


if __name__ == '__main__':
    rospy.init_node("tf_listener")

    tf_listener = tf.TransformListener()
    pose_subscriber = rospy.Subscriber(
        "robot_pose", PoseStamped, callback=poseCallback)

    r = rospy.Rate(1)
    while not rospy.is_shutdown():

        if tf_listener.canTransform(
                target_frame="world", source_frame="home", time=rospy.Time(0)) and msg is not None:

            res = tf_listener.transformPose(ps=msg, target_frame="world")

            rospy.loginfo(res)

        else:
            rospy.logwarn("Cannot lookup transform between world and home")

        r.sleep()

ํ˜น์‹œ ์ด๋Ÿฐ ์˜๋ฌธ์ด ๋“ค์ง€๋Š” ์•Š์„๊นŒ. TF๋Š” ์ „ํ˜€ ์ƒˆ๋กœ์šด ๋‚ด์šฉ์ด ์•„๋‹ˆ๋ฉฐ, ๋ณ€ํ™˜ ํ–‰๋ ฌ์˜ ๊ณ„์‚ฐ์€ numpy ๋“ฑ ๋‹จ์ˆœ ํ–‰๋ ฌ ๊ณ„์‚ฐ์„ ํ†ตํ•˜์—ฌ ์–ผ๋งˆ๋“ ์ง€ ๋Œ€์‹ ํ•  ์ˆ˜ ์žˆ๊ณ , ์˜คํžˆ๋ ค ๊ทธ์ชฝ์ด ๋น ๋ฅด์ง€ ์•Š์„๊นŒ?

๋ฌผ๋ก  ์™„์ „ํžˆ ํ‹€๋ฆฐ ๋ง์€ ์•„๋‹ˆ์ง€๋งŒ, ROS์˜ tf ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋ณ€ํ™”ํ•˜๋Š” ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ์ถ”์ ํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๋ฉฐ, ๋‹ค๋ฅธ ROS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์—ฐ๋™๋˜์–ด ๊ท€์ฐฎ์€ ์ž‘์—…์„ ๋Œ€ํญ ๊ฐ์†Œ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ, ํ”„๋ ˆ์ž„ ๊ฐ„ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋Š” ๋‹จ์ˆœํžˆ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๋ฌดํ•œํ•˜๊ฒŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, TransformListener๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ ์ขŒํ‘œ๊ณ„ ๊ฐ„์˜ ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ํ•œ๋ฒˆ์— ๊ณ„์‚ฐ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์กด์žฌํ•œ๋‹ค.

tf_broadcaster.sendTransform(
	translation=[10, 10, 0],
	rotation=[0., 0., 0., 1],
	time=rospy.Time.now(),
	child="home",
	parent="world"
)

tf_broadcaster.sendTransform(
	translation=[10, 10, 0],
	rotation=[0., 0., 0., 1],
	time=rospy.Time.now(),
	child="world",
	parent="utm"
)

if tf_listener.canTransform(
	target_frame="utm", source_frame="home", time=rospy.Time(0)) and msg is not None:

	res = tf_listener.transformPose(ps=msg, target_frame="utm")

	rospy.loginfo(res)

๋˜ํ•œ, ์ด ์—ญ์‹œ๋„ ROS์˜ ์ผ๋ถ€์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ„๋‹จํ•˜๊ฒŒ ์‹œ๊ฐํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์  ๋˜ํ•œ, ์žฅ์ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

$ rosrun tf view_frames

์ฐธ๊ณ 

  • [Blog] Coordinate Frames and Transforms for ROS-based Mobile Robots: https://automaticaddison.com/coordinate-frames-and-transforms-for-ros-based-mobile-robots/
  • [Blog] ์ดˆ๋ณด์ž๋ฅผ ์œ„ํ•œ ROS : TF๋ž€ ๋ฌด์—‡์ธ๊ฐ€: https://velog.io/@7cmdehdrb/whatIsTF
๋ฐ˜์‘ํ˜•
์ €์ž‘์žํ‘œ์‹œ ๋น„์˜๋ฆฌ ๋ณ€๊ฒฝ๊ธˆ์ง€ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'Study: Robotics(Robot) > Robot: ROS(Robot Operating Sytem)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[ROS] apt ์„ค์น˜ํ•œ ํŒจํ‚ค์ง€์™€ buildํ•œ ํŒจํ‚ค์ง€(catkin, colcon) ์ค‘ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉ?  (0) 2023.11.10
[ROS] ROS URDF vs. Gazebo SDF: Link Pose, Joint Pose, Visual & Collision  (0) 2023.10.27
[ROS] ROS rosrun ์‹คํ–‰ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ(python, cpp)  (0) 2023.10.12
[ROS] ROS Docker Official Image, Docker Compose ํŒŒ์ผ  (0) 2023.05.03
[ROS] Why ROS2? (feat. ROS1 vs ROS2)  (0) 2022.11.30
    'Study: Robotics(Robot)/Robot: ROS(Robot Operating Sytem)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
    • [ROS] apt ์„ค์น˜ํ•œ ํŒจํ‚ค์ง€์™€ buildํ•œ ํŒจํ‚ค์ง€(catkin, colcon) ์ค‘ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉ?
    • [ROS] ROS URDF vs. Gazebo SDF: Link Pose, Joint Pose, Visual & Collision
    • [ROS] ROS rosrun ์‹คํ–‰ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ(python, cpp)
    • [ROS] ROS Docker Official Image, Docker Compose ํŒŒ์ผ
    DrawingProcess
    DrawingProcess
    ๊ณผ์ •์„ ๊ทธ๋ฆฌ์ž!

    ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”