รูปปกบทความ

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: เลื่อนเข้า-ออกเป็นเส้นตรง (เช่น กระบอกสูบโช้คอัพ)
รูปประกอบโครงสร้าง URDF: Link, Joint, Visual, Collision, Inertial

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