ตอนที่ 17: การสร้างหุ่นยนต์ 3 มิติด้วย URDF (Unified Robot Description Format)

1. 🎯 ตอนที่ 17: เนรมิตกายหยาบให้หุ่นยนต์ด้วย URDF (Unified Robot Description Format)
สวัสดีครับน้องๆ วิศวกรหุ่นยนต์ทุกคน! ในตอนที่แล้วเราได้พูดถึงระบบประสาทสัมผัสอย่าง TF (Transform) กันไปแล้ว ตอนนี้น้องๆ คงสงสัยว่า… “พี่ครับ หุ่นยนต์ของผมมีสมอง (Nodes) มีเส้นประสาท (Topics/TF) แล้ว แต่กายหยาบของมันล่ะครับ? ผมจะเอาโมเดลหุ่นยนต์ 3 มิติเข้าไปวิ่งเล่นใน RViz หรือ Gazebo ได้ยังไง?”
คำถามนี้ดีมากครับ! การที่เราจะบอกให้ ROS 2 รู้จักรูปร่างหน้าตาและฟิสิกส์ของหุ่นยนต์ เราไม่สามารถแค่โยนไฟล์ CAD โง่ๆ เข้าไปแล้วหวังว่ามันจะเดินได้นะครับ เราต้องมี “พิมพ์เขียว” ที่อธิบายโครงสร้างทั้งหมดอย่างเป็นระบบ วันนี้พี่จะพาไปรู้จักกับภาษาศักดิ์สิทธิ์ที่ใช้สร้างกายหยาบให้หุ่นยนต์ ซึ่งมีชื่อว่า URDF ครับ เตรียมเปิด Editor แล้วมาสวมบทบาทเป็นพระเจ้าสร้างหุ่นยนต์กันเลย!
2. 📖 เปิดฉาก (The Hook)
น้องๆ เคยเล่นเกมสร้างหุ่นยนต์ไหมครับ? เวลาเราจะต่อหุ่นยนต์หนึ่งตัว เราต้องเอา “ชิ้นส่วน” (เช่น ล้อ, โครงรถ, แขนกล) มาต่อเข้าด้วยกันผ่าน “ข้อต่อ” (เช่น บานพับ, แกนหมุน)
ในโลกของการพัฒนาหุ่นยนต์จริงก็เหมือนกันครับ ถ้าน้องออกแบบหุ่นยนต์ในโปรแกรม SolidWorks แล้วอยากเอามาซิมูเลชันใน Gazebo น้องต้องบอกระบบให้ได้ว่าชิ้นส่วนไหนมีน้ำหนักเท่าไหร่? ชิ้นส่วนไหนหมุนได้? ล้อหน้าหมุนด้วยความเร็วสูงสุดเท่าไหร่? และขอบเขตการชน (Hitbox) อยู่ตรงไหน?
ถ้าไม่มีการกำหนดสิ่งเหล่านี้ หุ่นยนต์ในโลกจำลองของน้องก็จะกลายเป็นวิญญาณที่ร่วงทะลุพื้นโลกไปเลยครับ! และเครื่องมือที่วิศวกร ROS ใช้เพื่ออธิบายโครงสร้างทั้งหมดนี้ก็คือไฟล์ XML ที่เรียกว่า URDF (Unified Robot Description Format) นั่นเองครับ!
3. 🧠 แก่นวิชา (Core Concepts)
URDF (Unified Robot Description Format) คือไฟล์รูปแบบ XML ที่ทำหน้าที่เป็นพิมพ์เขียวของหุ่นยนต์ โดยจะอธิบายหุ่นยนต์ในรูปแบบของ “โครงสร้างต้นไม้ (Tree structure)” ซึ่งประกอบด้วย 2 แท็ก (Tags) หลักๆ ที่เป็นหัวใจสำคัญ ได้แก่:
<link>(ชิ้นส่วน/กระดูก): ใช้สำหรับอธิบาย “ชิ้นส่วนที่เป็นวัตถุแข็งเกร็ง (Rigid bodies)” เช่น โครงรถ (Chassis), ล้อ (Wheels), หรือท่อนแขน โดยภายในแท็ก<link>จะประกอบด้วย 3 แท็กย่อยที่สำคัญมากในการซิมูเลชัน:<visual>(ผิวหนัง/รูปลักษณ์): อธิบายว่าชิ้นส่วนนี้ “หน้าตาเป็นอย่างไร” ใน RViz หรือ Gazebo เราสามารถกำหนดรูปร่างพื้นฐาน (Box, Cylinder, Sphere) กำหนดสี (Material) หรือแม้แต่โหลดไฟล์โมเดล 3D สวยๆ อย่าง.dae(COLLADA) หรือ.stlเข้ามาครอบไว้ได้เลย<collision>(กล่องรับแรงกระแทก/Hitbox): อธิบาย “ขอบเขตการชน” เพื่อให้ Physics Engine นำไปคำนวณเมื่อหุ่นยนต์เดินชนกำแพง<inertial>(มวลและแรงเฉื่อย): อธิบาย “คุณสมบัติทางฟิสิกส์” เช่น น้ำหนักของชิ้นส่วน (Mass), จุดศูนย์ถ่วง (Center of Mass), และเมทริกซ์ความเฉื่อย (Inertia Tensor) ซึ่งสำคัญมากสำหรับการซิมูเลชันใน Gazebo
<joint>(ข้อต่อ): ใช้สำหรับอธิบายว่า<link>สองชิ้นเชื่อมต่อกันอย่างไร และขยับได้แบบไหน โดยจะต้องระบุparent(ชิ้นส่วนหลัก) และchild(ชิ้นส่วนรอง) เสมอ ชนิดของข้อต่อที่เจอบ่อยๆ ได้แก่:fixed: ยึดติดตายตัว ขยับไม่ได้ (เช่น ติดเซ็นเซอร์ LIDAR บนหลังคาหุ่นยนต์)continuous: หมุนได้อย่างอิสระไม่มีที่สิ้นสุด (เช่น แกนหมุนของล้อรถ)revolute: หมุนได้ แต่มีขีดจำกัดมุมองศา (เช่น ข้อศอกของแขนกล)prismatic: เลื่อนเข้า-ออกเป็นเส้นตรง (เช่น กระบอกสูบโช้คอัพ)

4. 💻 ร่ายมนต์โค้ดและคำสั่ง (Show me the Code)
เรามาดูหน้าตาของพิมพ์เขียว URDF พื้นฐานสำหรับการสร้างหุ่นยนต์ที่มี “โครงรถ” และ “ล้อซ้าย” กันครับ:
<?xml version="1.0"?>
<!-- 1. ประกาศชื่อหุ่นยนต์ -->
<robot name="my_awesome_robot">
<!-- 2. สร้างชิ้นส่วนตัวถังรถ (Base Link) -->
<link name="base_link">
<!-- รูปลักษณ์ (Visual): ให้เป็นกล่องสี่เหลี่ยมสีน้ำเงิน -->
<visual>
<geometry>
<box size="0.5 0.3 0.2"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<!-- ขอบเขตการชน (Collision): ใช้ขนาดเดียวกับ Visual -->
<collision>
<geometry>
<box size="0.5 0.3 0.2"/>
</geometry>
</collision>
<!-- ฟิสิกส์ (Inertial): หนัก 5 กิโลกรัม พร้อมค่าความเฉื่อย -->
<inertial>
<mass value="5.0"/>
<inertia ixx="0.05" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<!-- 3. สร้างชิ้นส่วนล้อซ้าย (Left Wheel) -->
<link name="left_wheel">
<visual>
<!-- หมุนล้อตะแคง 90 องศา (pi/2 = 1.57 rad) ในแกน X ให้ตั้งขึ้น -->
<origin xyz="0 0 0" rpy="1.5708 0 0"/>
<geometry>
<cylinder radius="0.1" length="0.05"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="1.5708 0 0"/>
<geometry>
<cylinder radius="0.1" length="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.002" ixy="0" ixz="0" iyy="0.002" iyz="0" izz="0.005"/>
</inertial>
</link>
<!-- 4. สร้างข้อต่อเชื่อมล้อซ้ายเข้ากับตัวรถ -->
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<!-- กำหนดตำแหน่งล้อให้อยู่เยื้องไปด้านซ้ายและด้านหลัง -->
<origin xyz="-0.15 0.2 0" rpy="0 0 0"/>
<!-- กำหนดแกนหมุนของล้อให้หมุนรอบแกน Y -->
<axis xyz="0 1 0"/>
</joint>
</robot>คอมเมนต์สไตล์รุ่นพี่:
- สังเกตแท็ก
<origin>ดีๆ นะครับxyzคือระยะห่าง (Translation) ส่วนrpy(Roll, Pitch, Yaw) คือการหมุน (Rotation) ซึ่งใน ROS เราใช้หน่วยเป็น เมตร (Meters) และ เรเดียน (Radians) เสมอนะครับ! (ห้ามใส่ 90 องศามาตรงๆ นะ ต้องใส่ 1.5708 แทน) - ถ้าน้องอยากเช็กว่าเขียน XML ผิดตรงไหน สามารถใช้คำสั่ง Terminal:
check_urdf my_awesome_robot.urdfระบบจะช่วย Parse โครงสร้างออกมาให้ดูว่าใครเป็น Parent ใครเป็น Child ครับ!
5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
ในฐานะที่พี่ปั้นโมเดลหุ่นยนต์มาจนตาแฉะ นี่คือข้อควรระวังที่วิศวกรมือใหม่มักตกม้าตายครับ:
- ความลับของ
<collision>ที่หลายคนไม่รู้: เวลาน้องโหลดไฟล์ 3D Mesh สวยๆ รายละเอียดสูงปรี๊ดมาใส่ในแท็ก<visual>น้อง ไม่ควร โหลดไฟล์ Mesh ตัวเดียวกันนั้นมาใส่ในแท็ก<collision>เด็ดขาด! การคำนวณการชน (Collision detection) ด้วย Polygon นับแสนชิ้นจะทำให้ CPU ของ Gazebo ทำงานหนักจนคอมค้าง กฎเหล็กคือ จงใช้รูปทรงพื้นฐาน (Box, Cylinder, Sphere) มาครอบเป็น Hitbox ในแท็ก<collision>เสมอ เพื่อลดภาระการคำนวณครับ! - ฝันร้ายหุ่นยนต์ทะลุพื้น (
<inertial>หายไปไหน?): ถ้าน้องโยน URDF เข้า Gazebo แล้วหุ่นยนต์ร่วงทะลุพื้นโลก หรือชิ้นส่วนหลุดกระจาย นั่นเป็นเพราะน้องลืมใส่แท็ก<inertial>หรือใส่ค่า Mass และ Inertia Matrix ผิดครับ! Gazebo เป็นระบบฟิสิกส์ที่สมจริง ถ้ามวลเป็นศูนย์หรือไม่มีอยู่จริง มันจะถือว่าวัตถุนั้นเป็นวิญญาณทันที - กฎมือขวา (Right-Hand Rule): การวางตำแหน่งพิกัดใน URDF ให้ยึดกฎมือขวาเสมอครับ: แกน X (สีแดง) ชี้ไปด้านหน้า, แกน Y (สีเขียว) ชี้ไปด้านซ้าย, และ แกน Z (สีน้ำเงิน) ชี้ขึ้นด้านบน จำสี RGB = XYZ ให้ขึ้นใจ จะช่วยให้จัดพิกัดหุ่นยนต์ใน RViz ได้ง่ายขึ้นมากครับ!
6. 🏁 บทสรุป (To be continued…)
การเขียน URDF ก็เปรียบเสมือนการเขียนพิมพ์เขียวที่ทำให้หุ่นยนต์ของเรามีตัวตนขึ้นมาในโลกเสมือนจริง เมื่อเรานิยาม <link> และเชื่อมมันด้วย <joint> เรียบร้อยแล้ว โหนดอย่าง robot_state_publisher ก็จะสามารถนำไฟล์นี้ไปสร้าง TF Tree เพื่อให้หุ่นยนต์รับรู้การเคลื่อนไหวของตัวเองได้อย่างสมบูรณ์!
แต่เดี๋ยวก่อนครับน้องๆ… ถ้าน้องต้องทำหุ่นยนต์แมงมุมที่มี 6 ขา แต่ละขามี 3 ข้อต่อ ถ้าน้องต้องมานั่งก๊อปปี้แปะโค้ด XML ท่อนเดิมซ้ำๆ คงเมื่อยมือแย่เลยใช่ไหมครับ? ในตอนต่อไป พี่จะพาไปรู้จักกับอาวุธลับที่ชื่อว่า Xacro (XML Macros) ที่จะมาช่วยให้เราเขียน URDF แบบ “โปรแกรมมิ่ง” ใช้ตัวแปรและลูป (Loop) ได้! เตรียมตัวยกระดับการเขียนพิมพ์เขียวให้เป็นแบบฉบับมือโปรกันครับ!
ต้องการที่ปรึกษาด้านการออกแบบสถาปัตยกรรมหุ่นยนต์ (Robotics) และระบบ Automation ให้กับองค์กรของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p