ตอนที่ 18: ลดความซ้ำซ้อนของ URDF ด้วย Xacro

1. 🎯 ตอนที่ 18: เขียนโค้ดหุ่นยนต์แบบ “โปรแกรมเมอร์” ไม่ใช่ “กรรมกร” ด้วย Xacro
สวัสดีครับน้องๆ วิศวกรหุ่นยนต์ทุกคน! ในตอนที่แล้ว เราได้สวมวิญญาณสถาปนิก สร้างกายหยาบให้หุ่นยนต์ด้วยไฟล์ URDF กันไปแล้ว แต่ถ้าน้องๆ ลองเขียน URDF สำหรับหุ่นยนต์ที่มีความซับซ้อน เช่น หุ่นยนต์ขับเคลื่อน 4 ล้อ (4WD) น้องๆ คงจะเริ่มสัมผัสได้ถึง “ความเหนื่อย” ใช่ไหมครับ?
ถ้าเราใช้ URDF ธรรมดา เราต้องเขียนแท็ก <link> และ <joint> ของล้อหน้าซ้าย ล้อหน้าขวา ล้อหลังซ้าย และล้อหลังขวา ซ้ำๆ กันถึง 4 รอบ! แล้วถ้าวันนึงหัวหน้าสั่งให้เปลี่ยน “รัศมีล้อ” ล่ะ? น้องต้องไปนั่งไล่แก้ตัวเลขรัศมีและจุดหมุน (Origin) ทั้ง 4 ล้อด้วยมือ… พลาดไปล้อเดียว หุ่นยนต์เดินเป๋แน่นอน!
วันนี้พี่จะพาไปรู้จักกับ Xacro (XML Macros) ฮีโร่ที่จะมาเปลี่ยนการเขียนไฟล์อธิบายหุ่นยนต์ที่น่าเบื่อ ให้กลายเป็นการเขียนโปรแกรมที่มีตัวแปร มีฟังก์ชัน และคำนวณคณิตศาสตร์ได้ในตัว เตรียมตัวบอกลาการ Copy-Paste กันได้เลยครับ!
2. 📖 เปิดฉาก (The Hook)
ในโลกของการพัฒนาซอฟต์แวร์ เรามีกฎทองข้อหนึ่งที่เรียกว่า DRY (Don’t Repeat Yourself) หรือ “อย่าเขียนโค้ดซ้ำ” แต่ปัญหาคือไฟล์ URDF มันเป็นแค่ไฟล์ XML โง่ๆ (Static XML) ที่ไม่มีระบบตัวแปร ไม่มีลูป (Loop) ไม่มีอะไรเลย ไฟล์มันถึงได้ยาวเหยียดเป็นหลายร้อยบรรทัด และอ่านยากสุดๆ
วิศวกรระดับโลกของ ROS เขาก็ปวดหัวกับเรื่องนี้เหมือนกันครับ เขาเลยสร้างอาวุธที่ชื่อว่า Xacro ขึ้นมา มันคือการนำไฟล์ URDF มาอัปเกรดให้สามารถใส่ “ตรรกะการโปรแกรม (Programmability)” เข้าไปได้ เปรียบเสมือนการสร้าง Template เอาไว้ แล้วเวลาจะใช้งานก็แค่โยนพารามิเตอร์เข้าไป (เช่น บอกแค่ว่าเป็นล้อ “ซ้าย” หรือ “ขวา”) ระบบก็จะทำการ Generate โค้ด XML เต็มรูปแบบออกมาให้เราแบบอัตโนมัติ โค้ดของเราจะสั้นลง สะอาดขึ้น และนำไปใช้ซ้ำ (Reuse) ได้อย่างสง่างามครับ!
3. 🧠 แก่นวิชา (Core Concepts)
Xacro (XML Macros) ทำงานเหมือน Pre-processor ครับ เราจะเขียนโค้ดในไฟล์นามสกุล .xacro (หรือ .urdf.xacro) จากนั้นใช้คำสั่งรันให้มันแปลงร่างกลายเป็น .urdf ปกติที่ ROS 2 เข้าใจ โดย Xacro มีพลังวิเศษ 4 อย่างที่วิศวกรทุกคนต้องใช้ให้เป็น:
- 1. Properties (ตัวแปร/ค่าคงที่):
เราสามารถประกาศค่าคงที่ไว้ที่ต้นไฟล์ได้ (เช่น ขนาด ความกว้าง ความยาว) เวลาจะเรียกใช้ก็แค่พิมพ์
${ชื่อตัวแปร}ข้อดีคือถ้ามีการเปลี่ยนสเปกฮาร์ดแวร์ เราก็แก้แค่จุดเดียวจบ! - 2. Math Expressions (คณิตศาสตร์ในโค้ด):
ภายในวงเล็บปีกกา
${}เราสามารถใส่เครื่องหมายบวก ลบ คูณ หาร (+,-,*,/) ไปจนถึงใส่วงเล็บและเครื่องหมายลบด้านหน้า (Unary minus) ได้เลย เช่น${(mass/12) * (x*x + y*y)}ระบบจะคำนวณค่าเป็นตัวเลขทศนิยมให้อัตโนมัติ (แต่มีข้อควรระวังคือ มันยังไม่รองรับการยกกำลังและหาเศษทศนิยม หรือ Modulus นะครับ) - 3. Macros (ฟังก์ชัน):
นี่คือไม้ตายของ Xacro! เราสามารถกำหนดบล็อกของโค้ด (เช่น โครงสร้างล้อ 1 ล้อที่ประกอบด้วย Link และ Joint) ให้เป็น “มาโคร (Macro)” แล้วตั้งรับพารามิเตอร์ได้ เวลาใช้งานเราก็แค่เรียกชื่อมาโครนั้นซ้ำๆ พร้อมโยนค่าพารามิเตอร์ (เช่น
prefix="left",prefix="right") เข้าไปแทน - 4. Include (การแยกไฟล์):
เราไม่จำเป็นต้องเขียนทุกอย่างไว้ในไฟล์เดียว เราสามารถแยกไฟล์ (เช่น
wheel.xacro,sensor.xacro) แล้วใช้คำสั่ง<xacro:include filename="..."/>เพื่อดึงไฟล์มารวมกันตอนคอมไพล์ได้ ทำให้ทำงานร่วมกันเป็นทีมได้ง่ายขึ้นมากครับ

4. 💻 ร่ายมนต์โค้ดและคำสั่ง (Show me the Code)
เรามาดูวิธีการเขียนไฟล์ .urdf.xacro เพื่อสร้างฐานหุ่นยนต์พร้อมล้อซ้าย-ขวา แบบมือโปรกันครับ!
1. โค้ด Xacro (my_robot.urdf.xacro):
<?xml version="1.0"?>
<!-- ต้องประกาศ xmlns:xacro เสมอ เพื่อบอกระบบว่าไฟล์นี้ใช้ Xacro -->
<robot name="my_robot" xmlns:xacro="http://www.ros.org/wiki/xacro">
<!-- 1. Properties: ประกาศค่าคงที่ต่างๆ ไว้ที่เดียว -->
<xacro:property name="base_length" value="0.6" />
<xacro:property name="base_width" value="0.4" />
<xacro:property name="base_height" value="0.2" />
<xacro:property name="wheel_radius" value="0.1" />
<xacro:property name="wheel_length" value="0.05" />
<!-- 2. Base Link: ใช้ตัวแปรและคำนวณคณิตศาสตร์เพื่อหาจุดศูนย์กลาง (Z-axis offset) -->
<link name="base_link">
<visual>
<!-- ใช้คณิตศาสตร์หาร 2 เพื่อเลื่อนจุด Origin ขึ้นมาให้กล่องวางบนพื้นพอดี -->
<origin xyz="0 0 ${base_height / 2.0}" rpy="0 0 0" />
<geometry>
<!-- ดึงตัวแปรมาใช้สร้างขนาดกล่อง -->
<box size="${base_length} ${base_width} ${base_height}" />
</geometry>
</visual>
</link>
<!-- 3. Macro: สร้าง "แม่พิมพ์" สำหรับล้อ (รับพารามิเตอร์ชื่อ prefix และค่า Y offset) -->
<xacro:macro name="wheel" params="prefix y_offset">
<!-- สร้างชิ้นส่วนล้อ (Link) -->
<link name="${prefix}_wheel">
<visual>
<!-- ใช้ค่า pi คงที่ของระบบ พลิกล้อให้ตั้งขึ้น 90 องศา -->
<origin xyz="0 0 0" rpy="${pi/2.0} 0 0" />
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_length}"/>
</geometry>
</visual>
</link>
<!-- สร้างจุดหมุนเชื่อมล้อเข้ากับ Base (Joint) -->
<joint name="${prefix}_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="${prefix}_wheel"/>
<!-- ใช้พารามิเตอร์ y_offset เพื่อกำหนดว่าล้อจะอยู่ฝั่งซ้ายหรือขวา -->
<origin xyz="0 ${y_offset} ${wheel_radius}" rpy="0 0 0" />
<axis xyz="0 1 0" />
</joint>
</xacro:macro>
<!-- 4. เรียกใช้ Macro (Instantiation): สั่งปั๊มล้อออกมา 2 ข้างแบบชิลๆ! -->
<xacro:wheel prefix="left" y_offset="${(base_width/2.0) + (wheel_length/2.0)}" />
<xacro:wheel prefix="right" y_offset="-${(base_width/2.0) + (wheel_length/2.0)}" />
</robot>2. การร่ายมนต์แปลงร่าง Xacro ให้เป็น URDF: ใน ROS 2 น้องๆ สามารถใช้คำสั่งนี้ใน Terminal เพื่อแปลงไฟล์ หรือเช็กความถูกต้องของโค้ดได้เลยครับ:
# สั่งแปลงร่าง xacro เป็น urdf แล้วบันทึกลงไฟล์ my_robot.urdf
ros2 run xacro xacro my_robot.urdf.xacro > my_robot.urdf
# ตรวจสอบโครงสร้างว่ามี Link และ Joint ครบถ้วนไหม
check_urdf my_robot.urdf5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
- วิชาใช้ค่าพาย (
pi): น้องไม่ต้องมานั่งกดเครื่องคิดเลขค่า $\pi$ หรือจำตัวเลขยาวๆ เพื่อแปลงองศาเป็นเรเดียนนะครับ ใน Xacro มีตัวแปรคงที่piให้ใช้ได้เลย! ถ้าน้องต้องการ 90 องศา ก็แค่พิมพ์${pi / 2.0}โค้ดจะอ่านง่ายและเป็นมาตรฐานขึ้นเยอะครับ - กฎเหล็กของการแยกไฟล์ (Include):
ถ้าน้องแยกไฟล์ Xacro เพื่อทำ Modular Design (เช่น แยกไฟล์ Macro ของแขนกลไว้ต่างหาก) ในไฟล์ลูกที่ถูกดึงไปรวม (Included files) ห้ามใส่แอตทริบิวต์
nameในแท็ก<robot>เด็ดขาด! แท็กชื่อ<robot name="my_robot">จะต้องถูกประกาศแค่ครั้งเดียวในไฟล์หลัก (Top-level file) เท่านั้น ไม่อย่างนั้นระบบจะสับสนครับ - สมการหาเมทริกซ์ความเฉื่อยสุดโหด:
การสร้างแท็ก
<inertial>ต้องใช้สมการเมทริกซ์ความเฉื่อย (Inertia Tensor) ที่วุ่นวาย พี่แนะนำให้สร้าง Macro สำหรับรูปทรงพื้นฐาน (Box, Cylinder, Sphere) เอาไว้ใช้เป็นเครื่องมือประจำตัวเลยครับ! เช่น<xacro:macro name="box_inertia" params="m x y z">พอถึงเวลาจะใช้ก็โยนแค่ตัวแปร มวล ความกว้าง ความยาว ความสูง เข้าไปให้ Macro คำนวณค่าixx,iyy,izzให้เราโดยอัตโนมัติ ประหยัดเวลาไปได้มหาศาล!
6. 🏁 บทสรุป (To be continued…)
เห็นไหมครับว่า Xacro คือพระเอกตัวจริงที่ทำให้ไฟล์ URDF ของเรากลายเป็นโมเดลที่มีตรรกะ มีระเบียบ และพร้อมรับมือกับการเปลี่ยนแปลงของฮาร์ดแวร์ได้อย่างไร้รอยต่อ นี่แหละครับคือทักษะที่แยก “มือสมัครเล่น” ออกจาก “วิศวกรระดับโปร” ในวงการ ROS!
ตอนนี้เรามีโมเดลหุ่นยนต์ 3 มิติสุดล้ำที่เขียนด้วย Xacro แล้ว แต่หุ่นยนต์มันยังยืนนิ่งๆ ไม่รับรู้โครงสร้าง (TF) ของตัวเองเลย! ในตอนต่อไป พี่จะพาไปเปิดตัว Node ระดับตำนานอย่าง robot_state_publisher ที่จะรับไฟล์ Xacro ของเราไปประมวลผล แล้วปล่อยค่า TF Tree ออกมาให้ระบบรับรู้แบบ Real-time เตรียมตัวกันให้พร้อม แล้วพบกันครับ!
ต้องการที่ปรึกษาด้านการออกแบบสถาปัตยกรรมหุ่นยนต์ (Robotics) และระบบ Automation ให้กับองค์กรของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p