10. Mô Phỏng Robot trong ROS - Phần 1

10. Mô Phỏng Robot trong ROS - Phần 1

Trong chương này và chương tiếp theo, bạn sẽ học cách mô phỏng một rô-bốt và hiển thị trạng thái của nó bằng hai chương trình đi kèm với ROS là Gazebo và rviz. Gazebo là một chương trình mô phỏng 3D, nghĩa là nó cho phép bạn giả lập rô-bốt và môi trường xung quanh với các đặc tính vật lý như trọng lực, tốc độ, gia tốc, v.v., tương tự như trong thế giới thực. Khi bạn không có rô bốt thật hoặc bạn muốn kiểm tra rô bốt của mình trong môi trường ảo trước khi thử ngoài đời thì bạn nên sử dụng Gazebo. Rviz (viết tắt của ROS Visualization) là phần mềm trực quan hóa 3D giúp theo dõi trạng thái của rô-bốt chẳng hạn như dữ liệu cảm biến (hình ảnh, pointcloud - đám mây điểm, quỹ đạo, v.v.) hoặc chuyển đổi giữa các tọa độ khác nhau. Rviz có thể được sử dụng cho cả rô-bốt thật và mô phỏng.

Mô tả Robot

Để mô phỏng rô bốt trong ROS, bạn cần mô tả nó trong trong một file URDF (Unified Robot Description Format). URDF về cơ bản là một tệp XML cho phép bạn mô tả các thuộc tính vật lý quan trọng của rô-bốt chẳng hạn như link (liên kết), joint (khớp nối), hình dạng, màu sắc, collision (va chạm), v.v. Trong hình ví dụ bên dưới, phía bên trái là hình ảnh của một Universal Robot - UR5 trong rviz và phía bên phải hiển thị URDF của nó, trong đó tất cả các thành phần (liên kết và khớp nối) được định nghĩa bằng cách sử dụng tag (tương tự như tệp package.xml và tệp launch từ các chương trước). Phiên bản URDF hoàn chỉnh của rô-bốt UR5 tất nhiên dài hơn nhiều so với phiên bản tối giản bên dưới nhưng đây chỉ giúp bạn hình dung định dạng của một file URDF ra sao.

Tạo URDF cho robot di động

Trong phần này, bạn sẽ học cách tạo URDF cho một robot di động (mobile robot) đơn giản và hiển thị nó trong rviz (sau đó là Gazebo). Nhắc để bạn nhớ, ở phần cuối cùng của loạt bài này, bạn có thể sử dụng cử chỉ tay của mình để điều khiển robot này. Cool huh? Như mọi khi, mình cố gắng giữ các bước đơn giản nhất có thể và luôn khuyến khích bạn đọc và tự làm theo hướng dẫn thay vì copy/paste. Nếu bạn muốn tham khảo thì cả package này nằm tại đây.

  1. Tạo một ROS package mới và đặt tên là ros_mobile_robot. Sau đó, build catkin workspace.

     cd ~/catkin_ws/src/
     catkin_create_pkg ros_mobile_robot
     cd ..
     catkin build
    
  2. Trong package mới, tạo 2 thư mục có tên: urdflaunch.

  3. Trong thư mục launch, tạo một tệp tên mobile_robot.launch mà bạn sẽ dùng để gọi rviz để hiển thị URDF mà bạn sẽ viết. Nội dung của tệp này như sau:

     <?xml version="1.0"?>
     <launch>
       <arg name="config" default="urdf"/>
       <param name="robot_description" textfile="$(find ros_mobile_robot)/urdf/mobile_robot.urdf" />
       <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
       <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
       <node name="rviz" pkg="rviz" type="rviz" required="true" args="-d $(find ros_mobile_robot)/urdf/$(arg config).rviz"/>
     </launch>
    

    Giải thích: Dòng đầu tiên <?xml version="1.0"?> là một khai báo XML (XML declaration) dùng để chỉ định phiên bản XML. Bên trong tag launch, một đối số (argument) config được định nghĩa với giá trị mặc định là một chuỗi kí tự "urdf". Sau đó, một tham số (parameter) robot_description được tạo và textfile="$(find ros_mobile_robot)/urdf/mobile_robot.urdf" chỉ đơn giản là đường dẫn đến URDF (tạo ở bước 5). Tiếp theo, hai node joint_state_publisherrobot_state_publisher được gọi để theo dõi các trạng thái của robot chẳng hạn như vị trí & vận tốc của từng khớp và sự chuyển đổi (transform) giữa các liên kết. Cuối cùng, rviz được gọi bằng cách khởi chạy node rviz. Nếu có một tệp .rviz (fiel lưu các thiết lập của rviz) tồn tại trong $(find ros_mobile_robot)/urdf/$(arg config).rviz, nó sẽ được sử dụng. Nếu không, các thiết lập mặc định của rviz được khởi chạy. Vì đối số config theo mặc định là urdf, nên $(arg config).rviz bằng với urdf.rviz (ở bước 6 bạn sẽ biết cách có được file urdf.rviz này).

  4. Trong thư mục urdf, tạo một tệp có tên mobile_robot.urdf và thêm các dòng sau

     <?xml version="1.0"?>
     <robot name="my_robot">
    
      <!-- Tất cả các liên kết và khớp nối được khai báo ở đây -->
    
     </robot>
    

    Một URDF luôn bắt đầu và kết thúc bằng thẻ robot. Bây giờ chúng ta sẽ thêm tất cả các mô tả về liên kết và khớp nối vào giữa <robot name="my_robot"></robot>.

    Nhưng thực chất liên kết (link) và khớp (joint) là gì? Các liên kết là các phần cứng của robot (giống như xương trong cơ thể chúng ta) và chúng được kết nối với nhau bằng các khớp. Khớp nối là bộ phận của rô-bốt cho phép chuyển động giữa các liên kết.

    Trong hình trên, phía bên trái là một robot có năm liên kết và hai khớp còn phía bên phải là URDF của nó. Để mô tả cụ thể các liên kết và khớp nối, bạn cần điền vào chỗ ba chấm mà bạn sẽ biết trong các bước tiếp theo.

  5. Thẻ <link> được dùng để thêm liên kết. Thông thường người ta tạo một liên kết làm gốc (origin) cho toàn bộ robot. Đây chỉ đơn giản là một liên kết trống (vì nó chỉ có tên và không có thông tin gì khác). Mình gọi nó là base_link. Thêm những dòng này vào giữa <robot name="my_robot"></robot>.

           <link name="base_link">
           </link>
    

    Tiếp theo, tạo một liên kết tên chassis (khung xe), về cơ bản là một hộp có kích thước (dài x rộng x cao) là 0.4 x 0.4 x 0.1 mét.

           <link name="chassis">
             <visual>
               <geometry>
                 <box size="0.4 0.4 0.1"/>
               </geometry>
             </visual>
           </link>
    

    Thẻ <link> có ba thành phần: <visual> để mô tả các thuộc tính trực quan (hình dạng của liên kết), <collision> để mô tả thể tích va chạm (để kiểm tra xem các liên kết có va vào nhau không) và <inertial > để xác định mômen quán tính (một thuộc tính vật lý quan trọng cho mô phỏng, ví dụ: trong Gazebo). Sơ đồ bên dưới hiển thị tất cả các thành phần con của <link>. Trong đoạn mã trên, chỉ <visual> và phần tử con của nó <geometry> (và phần tử "cháu" <box>) được sử dụng để tạo một hộp có kích thước 0.4 x 0.4 x 0.1 mét (dài x rộng x chiều cao). <collision><inertial> sẽ được thêm vào sau.

    Tiếp theo, chúng ta cần thêm một khớp giữa base_link (liên kết mẹ) và chassis (liên kết con). Đây là một khớp tĩnh (fixed) vì không có chuyển động.

           <joint name="chassis_joint" type="fixed">
             <parent link="base_link"/>
             <child link="chassis"/>
           </joint>
    
  6. Để hiển thị những gì bạn vừa tạo, hãy chạy mobile_robot.launch từ bước 3 bằng cách chạy lệnh sau trong một terminal:

     roslaunch ros_mobile_robot mobile_robot.launch
    

    Lệnh này mở rviz lên nhưng ban đầu sẽ không có gì hện ra. Để xem mô hình rô-bốt của bạn, hãy làm theo các bước sau (xem ảnh bên dưới): Đầu tiên, thay đổi Fixed Frame thành base_link thay vì map. Sau đó, nhấp vào nút Add và chọn RobotModel trong danh sách. Nhấp vào OK và bạn sẽ thấy một chiếc hộp ở giữa cửa sổ bên phải. Dùng chuột, bạn có thể xoay (nhấp chuột trái), di chuyển X/Y (nhấp chuột giữa) và thu phóng (nhấp chuột phải hoặc con lăn chuột).

    Lưu tất cả các cấu hình bạn vừa chỉnh sửa trong rviz vào một tệp bằng cách đi tới File > Save Config As hoặc sử dụng Ctrl+Shift+S. Sau đó, lưu file với tên urdf.rviz trong thư mục ~/catkin_ws/src/ros_mobile_robot/urdf. Đường dẫn đến urdf.rviz này trùng với đường dẫn trong tệp launch ở bước 3, vì thế lần sau khi bạn khởi chạy nó, bạn sẽ không cần phải thêm RobotModel và thay đổi lại Fixed Frame nữa.

  7. Khung xe đã xong! Giờ hãy thêm bánh xe. Dưới đây là một ví dụ cho thấy cách mô tả bánh trước bên phải (front_wheel_right) và khớp nối của nó với khung xe (chassis).

           <material name="blue">
             <color rgba="0 0 0.8 1"/>
           </material>
    
           <!--right front wheel-->
           <link name="front_wheel_right">
             <visual>
               <geometry>
                 <cylinder length="0.04" radius="0.06"/>
               </geometry>
               <material name="blue"/>
             </visual>
           </link>
    
           <joint name="front_wheel_right_joint" type="continuous">
             <parent link="chassis"/>
             <child link="front_wheel_right"/>
             <origin xyz="0.2 -0.225 0" rpy="1.5707 0 0"/>
             <axis xyz="0 0 -1"/>
           </joint>
    

    Giải thích: Đầu tiên, một tag material với màu xanh lam (blue) được tạo (để sơn bánh xe). Liên kết bánh xe khá giống với khung xe chỉ khác là hình trụ thay vì hình hộp. Hình trụ có chiều dài 0.04 m và bán kính 0.06 m. Bánh xe có màu xanh lam (để dễ phân biệt với khung xe). Mối nối giữa khung xe (liên kết mẹ) và bánh trước bên phải (liên kết con) là khớp động (continuous), tức là khớp xoay liên tục quanh trục và không có giới hạn trên và dưới). Thông tin về các loại liên kết khác trong URDF có tại đây.

    Thẻ <origin> được dùng để mô tả vị trí và hướng của liên kết con đối với liên kết mẹ. Trong hình trên, bạn có thể thấy rằng vị trí của bánh xe so với gốc là 0.2 m ở X, -0.225 m ở Y và 0 m ở Z. Nó cũng cần xoay 90° (hoặc 1.5707 radian) ngược chiều kim đồng hồ dọc theo trục X của khung xe nếu không thì trục Z (màu xanh lam) của bánh xe sẽ bị hướng lên trên (xem hình ảnh bên dưới). Nếu bạn muốn trực quan hóa các trục, bạn nên nhấp vào nút Add và chọn TF (viết tắt của từ transformation) nằm ngay bên dưới RobotModel trong hộp thoại. Ở đây, X là Đỏ, Y là Lục và Z là Lam (hay XYZ <-> RGB).

    Cuối cùng, thẻ <axis> xác định trục quay của bánh là trục Z. Vì vậy, nó được đặt thành xyz="0 0 -1" vì chỉ có chuyển động trên trục Z. Có thể bạn thắc mắc tại sao là -1 thay vì 1. Đó là vì quy ước chung về hướng quay là cùng chiều kim đồng hồ là âm và ngược chiều kim đồng hồ là dương. Trong trường hợp này, khi muốn robot di chuyển về phía trước, các bánh xe bên phải sẽ di chuyển theo chiều kim đồng hồ dọc theo trục Z của nó, nghĩa là âm, do đó -1. Mặt khác, các bánh xe bên trái di chuyển ngược chiều kim đồng hồ khi robot di chuyển về phía trước để chúng có Z dương hay +1 (xem hình ảnh bên dưới).

    urdf-wheels

  8. Bạn hãy cố gắng làm theo ý tưởng trên và tự thêm 3 bánh xe còn lại. Một bài tập khác dành là thêm một hộp nhỏ ở phí trước của rô-bốt để bạn biết đầu của nó ở đâu. Bạn có thể tham khảo mã nguồn tại đây. Sau đó, khởi chạy lại mobile_robot.launch và kết quả cuối cùng sẽ như sau:

    mobile-robot-rviz-with-head

Và thế là xong! Bây giờ bạn đã biết cách mô tả một rô-bốt đơn giản bằng URDF và view nó trong rviz. Trong chương tiếp theo, mình sẽ chỉ cho bạn cách thêm nhiều thuộc tính vào file URDF để có thể mô phỏng và di chuyển robot trong Gazebo.

Did you find this article valuable?

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