11. Mô Phỏng Robot trong ROS - Phần 2

11. Mô Phỏng Robot trong ROS - Phần 2

Hãy cùng tiếp tục chương trước bằng việc dùng Xacro để cải tiến mô tả robot (URDF) và thêm nhiều thuộc tính hơn để mô phỏng và điều khiển robot trong Gazebo. Code ở phần này nhìn có vẻ dài dòng (vì XML luôn yêu cầu các thẻ mở và đóng) nhưng thực ra rất dễ hiểu.

Xacro là gì?

Trong phần trước, chúng ta đã tạo một URDF để mô tả tất cả các liên kết và khớp nối của một robot di động. Tuy nhiên, bạn có thể nhận thấy một số điểm dư thừa trong URDF này, ví dụ: 4 bánh xe có các thành phần gần như giống hệt nhau (ngoại trừ tên và vị trí). Đối với một robot phức tạp hơn, sẽ có nhiều thành phần lặp đi lặp lại hơn nữa và sẽ khiến URDF trở nên cồng kềnh và khó bảo trì. Đó là lý do tại sao Xacro ra đời. Xacro là viết tắt của XML Macro cho phép bạn sử dụng macro trong URDF để tăng tính mô đun và giảm những đoạn mã thừa. Lưu ý rằng Xacro không phải là một giải pháp thay thế cho URDF mà chỉ là một cách viết khác vì cuối cùng, Xacro sẽ được (tự động) chuyển đổi thành URDF trong khi được sử dụng.

Để hiểu cú pháp Xacro, hãy tạo một tệp mô tả mới trong thư mục urdf và đặt tên là mobile_robot.urdf.xacro. Toàn bộ tập tin nằm ở đây và sau đây là giải thích cho các phần chính. Hai dòng đầu tiên tương tự như mobile_robot.urdf, ngoại trừ trong thẻ robot, có dòng xmlns:xacro="http://www.ros.org/wiki/xacro" dùng để định nghĩa không gian tên (namespace) XML cho tệp để có thể đọc được các thẻ (tag) đúng cách.

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="mobile_robot">

Có ba đặc tính chúng ta có thể sử dụng với Xacro: property, math, and macro.

Xacro Property

Trong xacro, bạn có thể định nghĩa một hằng số làm một property (thuộc tính) và dùng nó khi nào cần. Ví dụ: trong đoạn mã bên dưới, ba thuộc tính có tên: chiều cao, chiều rộng và chiều sâu (height, width, depth) được tạo với các giá trị lần lượt là 0.4, 0.4 và 0.1 (mét). Sau đó, chúng được sử dụng trong cả thẻ visual và thẻ collision trong liên kết (link) chassis. Để sử dụng property chỉ cần đặt nó vào trong dấu đô la và dấu ngoặc nhọn, ví dụ: <box size="${height} ${width} ${depth}"/>. visualcollision là gì sẽ được giải thích ở bên dưới.

<xacro:property name="height" value="0.4" /> <!-- [m] -->
<xacro:property name="width" value="0.4" /> <!-- [m] -->
<xacro:property name="depth" value="0.1" /> <!-- [m] -->

<!--Chassis-->
<link name="chassis">
  <visual>
    <geometry>
      <box size="${height} ${width} ${depth}"/>
    </geometry>
  </visual>
  <collision>
    <geometry>
      <box size="${height} ${width} ${depth}"/>
    </geometry>
  </collision>
  <inertial>
    <mass value="1.0"/> <!-- [kg] -->
    <inertia ixx="0.014167" ixy="0.0" ixz="0.0" iyy="0.026667" iyz="0.0" izz="0.014167"/>
  </inertial>
</link>

Xacro Macro và Math

Bây giờ đến các bánh xe. Chúng ta đã tạo 4 mô tả riêng cho 4 bánh xe trong URDF từ chương trước, nhưng bây giờ chỉ cần dùng 1 macro để mô tả một bánh xe chung và sau đó sử dụng các tham số để định nghĩa 4 bánh xe sau trong 4 dòng. Bạn có thể coi việc viết macro giống như tạo một hàm với các đối số.

<xacro:property name="wheel_height" value="0.04" /> <!-- [m] -->
<xacro:property name="wheel_radius" value="0.06" /> <!-- [m] -->

<!-- Wheel macro-->
<xacro:macro name="wheel" params="name reflect_x reflect_y reflect_r reflect_axis">

  <!-- Wheel link -->
  <link name="${name}_wheel">
    <visual>
      <geometry>
        <cylinder length="${wheel_height}" radius="${wheel_radius}"/>
      </geometry>
      <material name="blue"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="${wheel_height}" radius="${wheel_radius}"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="0.3"/>  <!-- [kg] -->
      <inertia ixx="0.00031" ixy="0.0" ixz="0.0" iyy="0.00031" iyz="0.0" izz="0.00054"/>
    </inertial>
  </link>

  <!-- Wheel joint -->
  <joint name="${name}_wheel_joint" type="continuous">
    <parent link="chassis"/>
    <child link="${name}_wheel"/>
    <origin xyz="${reflect_x*height/2} ${reflect_y*(width/2+0.025)} 0" rpy="${reflect_r*1.5707} 0 0"/>
    <axis xyz="0 0 ${reflect_axis}"/>
  </joint>
</xacro:macro>

Trong đoạn code trên, macro bánh xe (wheel) được định nghĩa với với 5 đối số: name, reflect_x, reflect_y, reflect_r,reflect_axis. name được sử dụng cho tên của liên kết và khớp. reflect_x, reflect_y, reflect_r,reflect_axis được dùng cho vị trí của các khớp. Trong phần định nghĩa khớp nối (joint), bạn có thể thấy các phép toán cơ bản (cộng, trừ, nhân, chia) cũng có thể được sử dụng trong xacro, ví dụ: <origin xyz="${reflect_x*height/2} ${reflect_y*(width/2+0.025)} 0" rpy="${reflect_r*1.5707} 0 0"/>.

Khi đã có macro bánh xe này, việc khởi tạo các bánh xe rất đơn giản. Bên dưới là định nghĩa (trong 1 dòng duy nhất) của bánh xe đằng trước bên phải. Bạn có thể kiểm tra xem mô tả này có khớp với URDF cũ hay không bằng cách thay thế các đối số tương ứng trong xacro ở trên bằng các giá trị ở bên dưới. Và hãy tự thử thêm ba bánh còn lại nhé!

<xacro:wheel name="front_right" reflect_x="1" reflect_y="-1" reflect_r="1" reflect_axis="-1"/>

Những Thuộc Tính Va Chạm và Vật Lý

Những gì chúng ta làm cho đến nay là để mô tả các đặc điểm trực quan của robot, nghĩa là việc nó trông như thế nào. Tuy nhiên, để cho phép phát hiện va chạm và mô phỏng robot trong Gazebo một cách thực tế hơn, chúng ta cần thêm các thuộc tính khác.

Collision (Va Chạm)

Bạn có thể đã thấy các thẻ collision trong các liên kết chassiswheel. Các thuộc tính của collision là (trích dẫn trực tiếp từ ROS wiki):

  • collision là phần tử con trực tiếp của link, ở cùng cấp độ với thẻ visual.

  • Hình dạng (shape) của collision được định nghĩa bằng thẻ geometry giống như cách thực hiện trong thẻ visual.

Ở đây, các collision có dạng hình học (geometry) giống hệt như các link. Điều này đúng trong nhiều trường hợp nhưng nếu robot của bạn có các hình dạng phức tạp hơn hoặc nếu bạn muốn thể tích của collision to hơn để đảm bảo an toàn thì chúng phải được điều chỉnh cho phù hợp.

Các Thuộc Tính Vật Lý

Trong các nền tảng mô phỏng 3D như Gazebo sẽ luôn có các công cụ (gọi là physical engine) để mô phỏng các đặc tính vật lý trong thế giới thực như trọng lực, ma sát, độ cứng, v.v. Do đó, chúng ta cũng cần thêm một số thuộc tính vật lý quan trọng vào URDF của mình. Một trong số đó là quán tính. Mọi phần tử liên kết được mô phỏng đều cần một thẻ quán tính mà bạn có thể thấy trong các link khung (chassis) và bánh xe (wheel) ở trên. Nó là một thành phần con của thẻ link và cung cấp hai thông tin: mass, khối lượng (tính bằng kilôgam) và inertia, mômen quán tính. Dành cho những bạn chưa biết "Momen quán tính, ký hiệu là I, là một đại lượng vật lý đặc trưng cho mức quán tính của các vật thể trong chuyển động quay, tương tự như khối lượng trong chuyển động thẳng" (nguồn).

inertia được xác định bởi một ma trận 3x3 nhưng ma trận đối xứng nên nó có thể được biểu diễn bằng 6 phần tử (in đậm).

moment-of-inertia.jpg

Đối với các hình dạng đơn giản (hình hộp, hình trụ, hình cầu) như trong robot di động của chúng ta, ma trận quán tính có thể được tính bằng cách sử dụng các công thức từ danh sách này. Bảng bên dưới có chỉ ra công thức tính ma trận quán tính cho khung (hình hộp) và bánh xe (hình trụ). Bạn có thể thay các giá trị vào và tính xem có khớp với mã mô tả ở trên hay không. Đối với các mô hình phức tạp hơn, thông tin này có thể được trích xuất trực tiếp từ phần mềm 3D như MeshLab.

inertia-matrix.jpg

Có thể thêm nhiều đặc tính vật lý khác như ma sát, độ cứng và giảm chấn (chi tiết hơn tại đây). Tuy nhiên, vì chúng ta muốn mô phỏng trong Gazebo nên có thể thêm các thuộc tính này bằng thẻ gazebo. Để cho đơn giản, ở đây mình chỉ dùng thẻ material (vật liệu) màu xanh lam cho bánh xe nhưng bạn có thể thêm nhiều thành phần khác (chi tiết tại đây) để mô phỏng chân thực hơn.

  <gazebo reference="${name}_wheel">
    <material>Gazebo/Blue</material>
  </gazebo>

Khởi động và Điều Khiển Robot

Để điều khiển mobile robot của chúng ta trong Gazebo, bạn cần thêm hai thứ nữa vào tệp Xacro. Đầu tiên, mọi khớp truyền động, tức là tất cả các khớp bánh xe trong trường hợp của chúng ta, cần thẻ <transmission> bên trong macro wheel như bên dưới.

  <!-- Adding transmission to wheels -->
  <transmission name="${name}_wheel_trans">
    <type>transmission_interface/SimpleTransmission</type>
    <actuator name="${name}_wheel_motor">
      <mechanicalReduction>1</mechanicalReduction>
    </actuator>
    <joint name="${name}_wheel_joint">
      <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
    </joint>
  </transmission>

Thứ hai, plugin gazebo_ros_control được thêm vào để phân tích cú pháp các thẻ tranmission và tải các giao diện phần cứng và trình quản lý bộ điều khiển thích hợp trong gazebo.

Launch File

Xacro đã hoàn tất và để khởi chạy nó, hãy tạo một tệp launch khác có tên drive_robot.launch. Tệp đầy đủ nằm ở đây và mình đã thêm comment vào mỗi dòng để giải thích ý nghĩa của chúng nhưng nếu bạn vẫn chưa rõ về bất kỳ điều gì, hãy nhắn mình bằng comment dưới bài viết này.

Một điều quan trọng cần lưu ý là drive_robot.launch này cần 2 tệp (có thể được tải về tại đây và đặt trong thư mục config):

  • diffdrive.yaml bao gồm các cấu hình của diff_drive_controller (một trong nhiều bộ điều khiển mà ROS cung cấp và nó được sử dụng đặc biệt để tính toán vận tốc góc trái và phải cho rô-bốt 2 hoặc 4 bánh (bạn có thể tìm thêm chi tiết tại đây)).

  • gazebo_ros_control_params.yaml chứa các cài đặt cho control trong Gazebo.

Điều Khiển Robot Trong Gazebo

Mở 2 terminal, trong cái đầu tiên chạy tệp drive_robot.launch:

roslaunch ros_mobile_robot drive_robot.launch

Đợi vài giây cho Gazebo được tải xong.

Trong terminal thứ hai, chạy package rqt_robot_steering cung cấp GUI (giao diện) để điều khiển robot. Về cơ bản, nó cho phép bạn thay đổi vận tốc tuyến tính và tốc độ góc được publish tới topic /robot_diff_drive_controller/cmd_vel để điều khiển rô-bốt. Nếu tên topic không phải là /robot_diff_drive_controller/cmd_vel, hãy gõ lại cho đúng.

rosrun rqt_robot_steering rqt_robot_steering

rqt_robot_steering

Thay đổi vận tốc tuyến tính và góc trong GUI để điều khiển robot:

steer-robot-gazebo

Nếu bạn đang sử dụng máy ảo thì có thể thấy rằng mô phỏng bị lag. Đó là bởi vì Gazebo rất nặng, nếu bạn chạy nó trên máy tính chạy Ubuntu gốc và có card đồ họa tốt thì nó sẽ chạy mượt hơn.

Có thú vị khi thấy robot di chuyển không? Mình cá là có. Bạn đã đi một chặng đường dài và đã làm rất tốt! Chương tiếp theo sẽ là chương cuối của loạt bài này, trong đó bạn sẽ kết hợp mọi thứ bạn đã học được cho đến nay để điều khiển robot bằng cử chỉ tay của mình. See you there!

Did you find this article valuable?

Support Trinh Nguyen by becoming a sponsor. Any amount is appreciated!