Gazebo Simülasyon Ortamında ROS Destekli Otonom Vinç Tasarımı

Herkese merhaba ben Mustafa! Bu yazımda sizlerle staj süreci boyunca yaptığım proje hakkında bilgi paylaşımında bulunacağım. Tüm dünyada üretim ve imalat çok büyük öneme sahip olmaktadır. Bu üretim ve imalatın büyük bölümünü lojistik faaliyetler oluşturmaktadır. Lojistik faaliyetler; Ham maddenin veya üretim bandından çıkan ürünün taşıma araçlarına yüklenmesi, ve müşterilere ulaştırılmasıdır. Ben bu kısımda Üretilen ürünün veya üretime girecek olan parçanın üretim bandına taşınmasına odaklanacağım.

Vinçler yüksek ağırlıktaki malzemeleri bir yerden alıp ihtiyaç olan yere götüren mekanizmalardır. Bir operatör yardımı ile kumandalı olarak kontrol edilmektedirler. Projemde bu vinçlerin otonom bir şekilde bir operatöre ihtiyaç duymadan hareket etmesini hedefledim ve bunu Gazebo ortamında simüle ettim.

Projemi ilk aşamada sanal ortamda tasarlayıp fiziksel ve yazılımsal tepkilerini test etmeyi amaçladım. Projemde robot modellemek için Urdf ve Xacro kullandım. ROS’un kullandığım sürümü olan Noetic’de bunlar kaldırılarak tek bir parça haline getirilen Xml formatına taşınmıştır. Ama Urdf ve Xacro lar sorunsuz çalışabilmektedir. Simülasyon ortamı için yukarıda bahsettiğim Gazebo simülasyon ortamını kullandım.

Urdf nedir?

Sanal ortamda modellenmek istenen robotların temel görünümlerinin tutulduğu dosya biçimidir.

Temel görünümler modellenebilir Gazebo ortamında görüntülenebilir ancak çarpışma noktaları belirtilmediği için simülasyon uzayında kaybolurlar.

Xacro nedir?

Urdf dosyasında belirtilen temel modellemelere ek olarak çarpışma noktası ve atalet matrisi gibi ağırlık merkezinin belirtildiği fonksiyonlara sahiptir. Ayrıca Gazebo simülasyon ortamında hareket kabiliyeti verebilen eklentileride destekler.

Xml nedir?

Aslında urdf ve Xacro dan hiçbir farkı yoktur. Sadece ROS sürümü gereği .Urdf ve .Xacro uzantıları kaldırılıp yerine Xml uzantısı getirilmiştir.

Gazebo nedir?

Urdf ve Xacro ile oluşturulan robot modellerinin gerçek dünyaya çok yakın özelliklerde olan sanal dünyaya taşınmasını sağlayan simülasyon programıdır.

Urdf ve Xacro ile modellenmiş bir robot örneği:

Kendi Modellediğim Robot Vinç’in Gazebo görüntüsü:

 

Vinç tasarımım tamamen otonom olduğu için köprü üzerinde bulunan motora sabit bir kamera görüntü işleme yapabilmekte, bu işlediği görüntüyü Open_Cv ile nesne tanıma yapabilecek ve taşınması istenilen yükü taşıyacak. Sürü haberleşme altyapısıyla birden çok robotla haberleşerek taşıma işlemini ihtiyaçlar doğrultusunda yapabilecektir. Üzerinde bulunan sensörler sayesinde kendi aralarında haberleşerek, herhangi bir çarpışma durumuna maruz kalmamak için kritik mesafeye girildiğinde otomatik olarak duracaklardır.

Örnek kod parçacıkları:

Otonom Şekilde Hareket Ederken Kameradan Görüntü Aktaran Örnek Vinç Tasarımı:

 

Python Cv_Bridge kameradan görüntü alma kodları örneği:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import rospy
import cv2
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import numpy as np
import sys

class KenarTespit():
    
    def __init__(self):
        
        self.node_name = "kenar_tespit"
        
        rospy.init_node(self.node_name)
        
        self.bridge = CvBridge()
        
        rospy.Subscriber("/vinc/camera/image_raw", Image, self.func, queue_size = 1)
        
        rospy.loginfo("Goruntu alindi!")

    def func(self, ros_goruntu):
    
        try:
            cv_goruntu = self.bridge.imgmsg_to_cv2(ros_goruntu, "bgr8")
        
        except CvBridgeError as e:
            print (e)
        
        array_goruntu = np.array(cv_goruntu, dtype=np.uint8)
        
        islenmis_goruntu = self.tespit(array_goruntu)
                       
        cv2.imshow('Kenar Tespiti', islenmis_goruntu)
        
        if cv2.waitKey(1) & 0xFF == ord('q'):
           rospy.signal_shutdown('kapatiliyor...')
       
    def tespit(self, array_goruntu):
   
        gri_goruntu = cv2.cvtColor(array_goruntu, cv2.COLOR_BGR2GRAY)
        
        blur_goruntu = cv2.blur(gri_goruntu, (7, 7))
        
        kenarlar = cv2.Canny(blur_goruntu, 15.0, 30.0)
        
        return kenarlar

def main(args):       
    
    try:
        KenarTespit()
        rospy.spin()
    
    except KeyboardInterrupt:
        print ('Kapatiliyor!')
        cv2.DestroyAllWindows()

if __name__ == '__main__':
    main(sys.argv)

Genel Tasarım Demo Sürüm Kodları:

<link name="direk1">
   <visual>
     <geometry>
       <box size="${en} ${boy} ${yükseklik}"/>
     </geometry>
     <material name="blue"/>
     <origin xyz="0.0 0.0 0.0"/>
   </visual>
   <collision>
     <geometry>
       <box size="${en} ${boy} ${yükseklik}"/>
     </geometry>
   </collision>
   <xacro:default_inertial mass="10"/>
 </link>

 <joint name="direk1_joint" type="fixed">
   <parent link="base_link"/>
   <child link="direk1"/>
   <origin xyz="3 3 0"/>
 </joint>
 

 <joint name="direk2_joint" type="fixed">
   <parent link="base_link"/>
   <child link="direk2"/>
   <origin xyz="-3 3 0"/>
 </joint>
 <link name="direk3">
   <visual>
     <geometry>
       <box size="${en} ${boy} ${yükseklik}"/>
     </geometry>
     <material name="blue"/>
     <origin xyz="0.0 0.0 0.0"/>
   </visual>
   <collision>
     <geometry>
       <box size="${en} ${boy} ${yükseklik}"/>
     </geometry>
   </collision>
   <xacro:default_inertial mass="10"/>
 </link>

 <joint name="direk3_joint" type="fixed">
   <parent link="base_link"/>
   <child link="direk3"/>
   <origin xyz="3 -3 0"/>
 </joint>
 

 <joint name="uzatma1_joint" type="fixed">
   <parent link="base_link"/>
   <child link="uzatma1"/>
   <origin xyz="-3 0 1.3"/>
 </joint>
 <link name="uzatma2">
   <visual>
     <geometry>
       <box size="${en} ${yükseklik*2} ${boy}"/>
     </geometry>
     <material name="blue"/>
     <origin xyz="0 0 0"/>
   </visual>
   <collision>
     <geometry>
       <box size="${en} ${(yükseklik*2)-0.4} ${boy}"/>
     </geometry>
   </collision>
   <xacro:default_inertial mass="10"/>
 </link>

 <joint name="uzatma2_joint" type="fixed">
   <parent link="base_link"/>
   <child link="uzatma2"/>
   <origin xyz="3 0 1.3"/>
 </joint>

 <link name="ust1">
   <visual>
     <geometry>
       <box size="${yükseklik*2} ${en} ${boy}"/>
     </geometry>
     <material name="blue"/>
     <origin xyz="0 0 0"/>
   </visual>
   <collision>
     <geometry>
       <box size="${yükseklik} ${en} ${boy}"/>
     </geometry>
   </collision>
   <xacro:default_inertial mass="10"/>
 </link>

 <joint name="ust1_joint" type="prismatic">
   <parent link="base_link"/>
   <child link="ust1"/>
   <origin xyz="0 3 1.7"/>
   <axis xyz="0 1 0" />
   <limit lower="-6.05" upper="6.05" effort="1000" velocity="1"/>
 </joint>
 <transmission name="ust1_trans">
   <type>transmission_interface/SimpleTransmission</type>
   <actuator name="$ust1_motor">
     <mechanicalReduction>1</mechanicalReduction>
   </actuator>
   <joint name="ust1_joint">
     <hardwareInterface>PositionJointInterface</hardwareInterface>
   </joint>
 </transmission>

 <link name="mtr">
   <visual>
     <geometry>
       <box size="${en} ${en} ${en}"/>
     </geometry>
     <material name="blue"/>
     <origin xyz="0 0 0"/>
   </visual>
   <collision>
     <geometry>
       <box size="${en} ${en} ${en}"/>
     </geometry>
   </collision>
   <xacro:default_inertial mass="1"/>
 </link>

 <joint name="mtr_joint" type="prismatic">
   <parent link="ust1"/>
   <child link="mtr"/>
   <origin xyz="0 0 -0.4"/>
   <axis xyz="1 0 0" />
   <limit lower="-6.05" upper="6.05" effort="1000" velocity="1"/>
 </joint>
 <transmission name="mtr_trans">
   <type>transmission_interface/SimpleTransmission</type>
   <actuator name="$mtr_motor">
     <mechanicalReduction>1</mechanicalReduction>
   </actuator>
   <joint name="mtr_joint">
     <hardwareInterface>PositionJointInterface</hardwareInterface>
   </joint>
 </transmission>

 <link name="camera">
   <visual>
     <origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
     <geometry>
       <mesh filename="package://urdf_sim_tutorial/meshes/hokuyo.dae"/>
     </geometry>
   </visual>
   </link>
   <gazebo reference="camera">


    <sensor type="camera" name="camera">
     <update_rate>30.0</update_rate>
       <camera name="head">
           <horizontal_fov>1.3962634</horizontal_fov>
           <image>
               <width>800</width>
               <height>800</height>
               <format>R8G8B8</format>
           </image>
           <clip>
               <near>0.02</near>
               <far>100</far>
           </clip>
           <noise>
               <type>gaussian</type>
               <mean>0.0</mean>
               <stddev>0.007</stddev>
           </noise>
       </camera>
       <plugin name="camera_controller" filename="libgazebo_ros_camera.so">
           <alwaysOn>true</alwaysOn>
           <updateRate>30.0</updateRate>
           <cameraName>urdf_sim_tutorial/camera</cameraName>
           <imageTopicName>image_raw</imageTopicName>
           <cameraInfoTopicName>camera_info</cameraInfoTopicName>
           <frameName>camera</frameName>
           <hackBaseline>0.07</hackBaseline>
           <distortionK1>0.0</distortionK1>
           <distortionK2>0.0</distortionK2>
           <distortionK3>0.0</distortionK3>
           <distortionT1>0.0</distortionT1>
           <distortionT2>0.0</distortionT2>
           <center>0 0 0</center>
       </plugin>
    </sensor>
       
   </gazebo>
   <joint name="camera_link_joint" type="fixed">
       <axis xyz="0.0 0.0 0.0" />
       <origin rpy="1.5707 1.5707 0.0" xyz="0.0 -0.15 -0.22"/>
       <parent link="mtr"/>
       <child link="camera"/>          
   </joint>
 <link name="halat">
       <visual>
           <geometry>
               <cylinder radius="0.03" length="0.5"/>
           </geometry>
               <origin rpy="0 0 0" xyz="0 0 0" />
           <material name="Blue">
               <color rgba="0 0 1 1" />
           </material>    
       </visual>  
       <collision>
           <geometry>
               <cylinder radius="0.03" length="0.5"/>
           </geometry>
        <origin rpy="0 0 0" xyz="0 -3 2.6" />
       </collision> 
      <xacro:default_inertial mass="0.5"/>
   </link>
   <joint name="halat_joint" type="prismatic">
   <parent link="mtr"/>
   <child link="halat"/>
   <origin xyz="0 0 -0.43"/>
   <axis xyz="0 0 1" />
   <limit lower="-6.05" upper="6.05" effort="1000" velocity="1"/>
   </joint>
   <transmission name="halat_trans">
   <type>transmission_interface/SimpleTransmission</type>
   <actuator name="$halat_motor">
     <mechanicalReduction>1</mechanicalReduction>
   </actuator>
   <joint name="halat_joint">
     <hardwareInterface>PositionJointInterface</hardwareInterface>
   </joint>
   </transmission>

 

   <link name="hokuyo">
   <visual>
       <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
     <geometry>
       <mesh filename="package://urdf_sim_tutorial/meshes/hokuyo.dae"/>
     </geometry>
   </visual>
   <xacro:default_inertial mass="0.1"/>
   </link>
   
   <joint name="hokuyo_joint" type="fixed">
   <parent link="ust1"/>
   <child link="hokuyo"/>
   <origin rpy="0.0 0.0 -1.5707" xyz="0.0 -0.187 0.235"/>
   </joint>
   <gazebo reference="hokuyo">
    <sensor type="gpu_ray" name="head_hokuyo_sensor">
     <pose>0.0 0.0 0.0 0.0 0.0 0.0</pose>
     <visualize>true</visualize>
     <update_rate>40</update_rate>
     <ray>
       <scan>
         <horizontal>
           <samples>640</samples>
           <resolution>1</resolution>
           <min_angle>-1.396263</min_angle>
           <max_angle>1.396263</max_angle>
         </horizontal>
       </scan>
       <range>
         <min>1.5</min>
         <max>300.0</max>
         <resolution>1</resolution>
       </range>
       <noise>
         <mean>0.0</mean>
         <stddev>0.1</stddev>
       </noise>
     </ray>
     <plugin name="gazebo_ros_head_hokuyo_controller" filename="libgazebo_ros_gpu_laser.so">
       <topicName>/laser/scan</topicName>
       <frameName>hokuyo</frameName>
     </plugin>
    </sensor>
   </gazebo>

Mustafa ÇEVLİK

Selçuk Üniversitesi Elektrik Elektronik Mühendisliği

İLETİŞİM:

Linkedin:  https://www.linkedin.com/in/mustafa-çevlik-ab3223199

Gmail: Mcevlik16@gmail.com