Pick-and-Place Nedir ve Neden ROS 2?
Pick-and-place, endüstriyel robotların en temel ve yaygın görevlerinden biridir. Bir nesneyi belirli bir konumdan alıp başka bir konuma yerleştirme işlemi, üretim hatlarından lojistik merkezlerine kadar pek çok alanda kullanılır. ROS 2 (Robot Operating System 2), bu tür görevleri programlamak için güçlü bir ekosistem sunar. MoveIt 2 entegrasyonu, gerçek zamanlı kontrol desteği ve DDS tabanlı iletişim altyapısı sayesinde ROS 2, endüstriyel seviyede robot kol programlama için ideal bir platformdur.
Gerekli Yazılım ve Donanım Bileşenleri
Yazılım Gereksinimleri
- ROS 2 Humble veya Iron: LTS sürümü tercih edilmelidir
- MoveIt 2: Hareket planlama ve kinematik çözümleme için
- Gazebo (Ignition): Simülasyon ortamı
- ros2_control: Donanım soyutlama katmanı
- Python 3 veya C++: Node geliştirme dilleri
Donanım Gereksinimleri
- 6 DOF (Degree of Freedom) robot kol (ör. UR5e, Franka Emika Panda, xArm6)
- Gripper (paralel jaw veya vakum tipi)
- Derinlik kamerası (isteğe bağlı, ör. Intel RealSense D435)
- Bilgisayar: En az 8 GB RAM, çok çekirdekli işlemci
Çalışma Ortamının Kurulumu
Öncelikle ROS 2 ve MoveIt 2 kurulumunu gerçekleştirelim. Ubuntu 22.04 üzerinde Humble sürümünü kullanacağız:
# ROS 2 Humble kurulumu sonrası MoveIt 2 yüklemesi
sudo apt install ros-humble-moveit ros-humble-moveit-setup-assistant
sudo apt install ros-humble-ros2-control ros-humble-ros2-controllers
sudo apt install ros-humble-gazebo-ros2-control
# Workspace oluşturma
mkdir -p ~/pick_place_ws/src
cd ~/pick_place_ws/src
# MoveIt 2 konfigürasyon paketini oluşturma
ros2 pkg create --build-type ament_python pick_place_demo \
--dependencies rclpy moveit_msgs geometry_msgs
MoveIt 2 ile Hareket Planlama Mimarisi
Pick-and-place işlemi temelde dört aşamadan oluşur:
- Yaklaşma (Approach): Robot kolu nesnenin üzerine yaklaşır
- Kavrama (Grasp): Gripper kapanarak nesneyi kavrar
- Taşıma (Transport): Nesne hedef konuma taşınır
- Bırakma (Release): Gripper açılarak nesne bırakılır
MoveIt 2, bu aşamaların her biri için trajectory planlama, çarpışma kontrolü ve kinematik çözümleme sağlar. Arka planda OMPL (Open Motion Planning Library) kullanarak RRT*, PRM gibi algoritmalarla çarpışmasız yollar hesaplar.
Python ile Pick-and-Place Node Geliştirme
Aşağıda MoveIt 2 Python API'sini kullanarak temel bir pick-and-place node'u yer almaktadır:
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Pose, PoseStamped
from moveit_msgs.msg import CollisionObject, Grasp
from shape_msgs.msg import SolidPrimitive
from moveit.planning import MoveItPy
from moveit.core.robot_state import RobotState
import numpy as np
class PickAndPlaceNode(Node):
def __init__(self):
super().__init__('pick_and_place_node')
# MoveItPy başlatma
self.moveit = MoveItPy(node_name="pick_place_moveit")
self.arm = self.moveit.get_planning_component("manipulator")
self.gripper = self.moveit.get_planning_component("gripper")
# Planning sahnesine erişim
self.planning_scene = self.moveit.get_planning_scene_monitor()
self.get_logger().info("Pick-and-Place node başlatıldı.")
def add_collision_objects(self):
"""Sahneye çarpışma nesneleri ekle (masa ve hedef nesne)."""
with self.planning_scene.read_write() as scene:
# Masa ekleme
table = CollisionObject()
table.id = "masa"
table.header.frame_id = "world"
table_primitive = SolidPrimitive()
table_primitive.type = SolidPrimitive.BOX
table_primitive.dimensions = [0.8, 1.2, 0.02]
table_pose = Pose()
table_pose.position.x = 0.5
table_pose.position.y = 0.0
table_pose.position.z = 0.4
table.primitives.append(table_primitive)
table.primitive_poses.append(table_pose)
scene.apply_collision_object(table)
# Kavranacak nesne ekleme
obj = CollisionObject()
obj.id = "kutu"
obj.header.frame_id = "world"
obj_primitive = SolidPrimitive()
obj_primitive.type = SolidPrimitive.BOX
obj_primitive.dimensions = [0.04, 0.04, 0.10]
obj_pose = Pose()
obj_pose.position.x = 0.5
obj_pose.position.y = 0.2
obj_pose.position.z = 0.46
obj.primitives.append(obj_primitive)
obj.primitive_poses.append(obj_pose)
scene.apply_collision_object(obj)
def move_to_pose(self, target_pose: Pose) -> bool:
"""Kolu belirtilen poza hareket ettir."""
pose_stamped = PoseStamped()
pose_stamped.header.frame_id = "world"
pose_stamped.pose = target_pose
self.arm.set_goal_state(pose_stamped_msg=pose_stamped)
plan_result = self.arm.plan()
if plan_result:
self.get_logger().info("Plan başarılı, hareket yürütülüyor...")
self.arm.execute()
return True
else:
self.get_logger().error("Hareket planlaması başarısız!")
return False
def open_gripper(self):
"""Gripper'ı aç."""
self.gripper.set_goal_state(configuration_name="open")
plan = self.gripper.plan()
if plan:
self.gripper.execute()
def close_gripper(self):
"""Gripper'ı kapat."""
self.gripper.set_goal_state(configuration_name="close")
plan = self.gripper.plan()
if plan:
self.gripper.execute()
def attach_object(self, object_id: str):
"""Nesneyi end-effector'a bağla."""
with self.planning_scene.read_write() as scene:
scene.attach_object(object_id, "gripper_link")
def detach_object(self, object_id: str):
"""Nesneyi end-effector'dan ayır."""
with self.planning_scene.read_write() as scene:
scene.detach_object(object_id)
def execute_pick_and_place(self):
"""Tam pick-and-place döngüsünü çalıştır."""
self.add_collision_objects()
# 1. Gripper'ı aç
self.get_logger().info("Adım 1: Gripper açılıyor...")
self.open_gripper()
# 2. Nesnenin üzerine yaklaş (pre-grasp pozisyon)
self.get_logger().info("Adım 2: Pre-grasp pozisyona hareket...")
pre_grasp = Pose()
pre_grasp.position.x = 0.5
pre_grasp.position.y = 0.2
pre_grasp.position.z = 0.60 # Nesnenin 10cm üstü
pre_grasp.orientation.x = 1.0 # Aşağı bakan yön
pre_grasp.orientation.w = 0.0
if not self.move_to_pose(pre_grasp):
return False
# 3. Kavrama pozisyonuna in
self.get_logger().info("Adım 3: Kavrama pozisyonuna iniş...")
grasp_pose = Pose()
grasp_pose.position.x = 0.5
grasp_pose.position.y = 0.2
grasp_pose.position.z = 0.50
grasp_pose.orientation.x = 1.0
grasp_pose.orientation.w = 0.0
if not self.move_to_pose(grasp_pose):
return False
# 4. Gripper'ı kapat ve nesneyi bağla
self.get_logger().info("Adım 4: Nesne kavranıyor...")
self.close_gripper()
self.attach_object("kutu")
# 5. Nesneyi yukarı kaldır
self.get_logger().info("Adım 5: Nesne kaldırılıyor...")
lift_pose = Pose()
lift_pose.position.x = 0.5
lift_pose.position.y = 0.2
lift_pose.position.z = 0.65
lift_pose.orientation.x = 1.0
lift_pose.orientation.w = 0.0
if not self.move_to_pose(lift_pose):
return False
# 6. Hedef konuma taşı
self.get_logger().info("Adım 6: Hedef konuma taşınıyor...")
place_pose = Pose()
place_pose.position.x = 0.5
place_pose.position.y = -0.2
place_pose.position.z = 0.50
place_pose.orientation.x = 1.0
place_pose.orientation.w = 0.0
if not self.move_to_pose(place_pose):
return False
# 7. Nesneyi bırak
self.get_logger().info("Adım 7: Nesne bırakılıyor...")
self.open_gripper()
self.detach_object("kutu")
# 8. Güvenli pozisyona geri dön
self.get_logger().info("Adım 8: Başlangıç pozisyonuna dönüş...")
self.arm.set_goal_state(configuration_name="home")
plan = self.arm.plan()
if plan:
self.arm.execute()
self.get_logger().info("Pick-and-place işlemi tamamlandı!")
return True
def main(args=None):
rclpy.init(args=args)
node = PickAndPlaceNode()
node.execute_pick_and_place()
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Gazebo Simülasyonunda Test Etme
Kodu gerçek robota göndermeden önce Gazebo simülasyonunda test etmek kritik önem taşır. Simülasyon ortamını başlatmak için:
# Terminal 1: Simülasyon ortamını başlat
ros2 launch pick_place_demo gazebo_sim.launch.py
# Terminal 2: MoveIt 2 ve RViz başlat
ros2 launch pick_place_demo moveit_demo.launch.py
# Terminal 3: Pick-and-place node'unu çalıştır
ros2 run pick_place_demo pick_and_place_node
Cartesian Path Planning ile Hassas Kontrol
Bazı pick-and-place senaryolarında düz çizgisel hareketler gerekir. Özellikle nesneye yaklaşırken ve bırakırken Cartesian yol planlama kullanmak daha güvenilir sonuçlar verir:
def compute_cartesian_path(self, waypoints, max_step=0.01):
"""Cartesian yol planla (düz çizgisel hareket)."""
robot_state = self.arm.get_start_state()
# Cartesian path hesaplama
trajectory, fraction = robot_state.compute_cartesian_path(
waypoints,
max_step, # Adım büyüklüğü (metre)
0.0, # Jump threshold
avoid_collisions=True
)
if fraction < 0.95:
self.get_logger().warn(
f"Cartesian yolun yalnızca %{fraction*100:.1f}'i planlanabildi."
)
return None
return trajectory
Gripper Kontrolü ve ros2_control Entegrasyonu
Gerçek donanımda gripper kontrolü ros2_control framework'ü üzerinden yapılır. YAML konfigürasyon dosyasında gripper controller'ını tanımlamak gerekir:
# gripper_controllers.yaml
controller_manager:
ros__parameters:
update_rate: 100
gripper_controller:
type: position_controllers/GripperActionController
gripper_controller:
ros__parameters:
joint: gripper_finger_joint
goal_tolerance: 0.01
max_effort: 50.0
stall_velocity_threshold: 0.001
stall_timeout: 1.0
Görüntü İşleme ile Dinamik Nesne Algılama
Statik koordinatlar yerine kamera ile nesne konumunu dinamik olarak belirlemek üretim ortamlarında zorunludur. Derinlik kamerası kullanarak nesne pozisyonunu TF2 frame'ine dönüştüren basit bir yaklaşım:
from tf2_ros import Buffer, TransformListener
from sensor_msgs.msg import PointCloud2
class ObjectDetector(Node):
def __init__(self):
super().__init__('object_detector')
self.tf_buffer = Buffer()
self.tf_listener = TransformListener(self.tf_buffer, self)
self.subscription = self.create_subscription(
PointCloud2,
'/camera/depth/points',
self.pointcloud_callback,
10
)
def pointcloud_callback(self, msg):
# Nokta bulutu işleme ve nesne segmentasyonu
# Algılanan nesne pozisyonunu base_link frame'ine dönüştür
try:
transform = self.tf_buffer.lookup_transform(
'base_link',
msg.header.frame_id,
rclpy.time.Time()
)
# Dönüştürülmüş koordinatları kullan
except Exception as e:
self.get_logger().warn(f"TF dönüşümü başarısız: {e}")
Hata Yönetimi ve Güvenlik Önlemleri
Endüstriyel ortamlarda güvenlik kritik öneme sahiptir. Dikkat edilmesi gereken noktalar:
- Hız sınırlama:
max_velocity_scaling_factorvemax_acceleration_scaling_factorparametrelerini 0.1-0.3 aralığında tutarak yavaş başlayın - Çarpışma kontrolü: Planning scene'e tüm statik engelleri ekleyin; self-collision kontrolünü asla devre dışı bırakmayın
- Kavrama doğrulama: Gripper sensör verilerini okuyarak nesnenin gerçekten kavranıp kavranmadığını kontrol edin
- Acil durdurma: E-stop entegrasyonunu mutlaka yapın ve yazılımsal olarak da
/emergency_stoptopic'ini dinleyin - Eklem limitleri: URDF/SRDF dosyalarındaki eklem limitlerinin doğru tanımlandığından emin olun
- Zaman aşımı: Her planlama ve yürütme adımı için makul timeout değerleri belirleyin
Performans Optimizasyonu İpuçları
Üretim ortamlarında çevrim süresini minimize etmek önemlidir. Aşağıdaki stratejiler performansı artırır:
- Pipeline planlama: Bir hareket yürütülürken sonraki hareketi arka planda planlayın
- Planlayıcı seçimi: OMPL'nin RRTConnect algoritması genellikle en hızlı sonucu verir; PRM* ise tekrarlayan görevlerde daha verimlidir
- Planlama süresi sınırlama:
planning_timeparametresini 1-5 saniye aralığında tutun - Waypoint azaltma: Gereksiz ara noktalardan kaçının; MoveIt trajectory post-processing otomatik olarak yolu düzeltir
- Paralel planlama: MoveIt 2'nin paralel planlama özelliğini etkinleştirerek birden fazla planlayıcıyı eşzamanlı çalıştırın ve en iyi sonucu seçin
Simülasyondan Gerçek Robota Geçiş
Simülasyonda başarılı olan kodun gerçek robota aktarımında şu adımları izleyin:
- Robot üreticisinin ROS 2 driver paketini kurun (ör.
ros-humble-ur-robot-driver) ros2_controlkonfigürasyonunu simülasyondan gerçek donanım interface'ine geçirin- Hız ve ivme ölçekleme faktörlerini düşük değerlerle başlatın (0.05-0.1)
- İlk testleri teach pendant üzerinden E-stop'a hazır şekilde yapın
- Gripper kuvvet parametrelerini nesneye uygun şekilde kalibre edin
- TF frame kalibrasyonunu doğrulayın; kamera-robot ilişkisini hand-eye kalibrasyon ile belirleyin
Sonuç
ROS 2 ve MoveIt 2 kombinasyonu, pick-and-place uygulamalarını geliştirmek için güçlü ve esnek bir platform sunar. Bu yazıda ele aldığımız temel bileşenler — hareket planlama, gripper kontrolü, çarpışma yönetimi ve simülasyon — endüstriyel seviyede bir pick-and-place sistemi kurmanın yapı taşlarıdır. Simülasyonda kapsamlı testler yaparak ve güvenlik önlemlerini ihmal etmeyerek, gerçek dünya uygulamalarına güvenle geçiş yapabilirsiniz. ROS 2 ekosisteminin sürekli büyüyen paket deposu ve topluluk desteği, karmaşık robotik görevleri giderek daha erişilebilir hale getirmektedir.