|
|
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
|
|
from enum import Enum
|
|
|
from typing import List, Tuple
|
|
|
from .config import ConfigParser, SlotConfig
|
|
|
+from .movement import RobotMovement
|
|
|
import logging
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
@@ -33,6 +34,10 @@ class RobotController:
|
|
|
self.rejected_grade = self.dropoff_grades['rejected']
|
|
|
self.system_settings = self.config.get_system_settings()
|
|
|
|
|
|
+ # Initialize robot movement
|
|
|
+ self.movement = RobotMovement()
|
|
|
+ self.movement.set_speed(self.system_settings.speed)
|
|
|
+
|
|
|
# Initialize with configured values
|
|
|
self.total_slots = sum(len(device.slots) for device in self.devices)
|
|
|
self.work_queue: List[SlotConfig] = []
|
|
|
@@ -40,10 +45,31 @@ class RobotController:
|
|
|
self.gripper_occupied = False
|
|
|
|
|
|
async def pick_cell_from_feeder(self):
|
|
|
- # Implementation for picking cell from feeder
|
|
|
- logger.info("Picking cell from feeder")
|
|
|
- self.gripper_occupied = True
|
|
|
- pass
|
|
|
+ if self.gripper_occupied:
|
|
|
+ logger.error("Gripper already occupied")
|
|
|
+ return False
|
|
|
+
|
|
|
+ try:
|
|
|
+ feeder_pos = self.feeder.pickup_position
|
|
|
+ x, y, z = feeder_pos
|
|
|
+ # Move to safe height first
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ # Move to pickup position
|
|
|
+ await self.movement.move_to_position(x, y, z)
|
|
|
+ # Grip cell
|
|
|
+ if await self.movement.activate_gripper():
|
|
|
+ self.gripper_occupied = True
|
|
|
+ else:
|
|
|
+ raise RuntimeError("Failed to grip cell")
|
|
|
+ # Move back to safe height
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ logger.info("Cell picked from feeder")
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Failed to pick cell from feeder: {str(e)}")
|
|
|
+ await self.movement.deactivate_gripper() # Try to deactivate to avoid stuck gripper
|
|
|
+ self.gripper_occupied = False
|
|
|
+ return False
|
|
|
|
|
|
async def read_cell_id(self):
|
|
|
# Use vision system to read data matrix and return cell ID
|
|
|
@@ -71,43 +97,98 @@ class RobotController:
|
|
|
|
|
|
async def insert_cell_to_slot(self, cell: Cell, slot: SlotConfig):
|
|
|
if slot.occupied:
|
|
|
- logger.error(f"Slot {slot.id} is already occupied")
|
|
|
- return
|
|
|
+ logger.error(f"Slot at position {slot.position} is already occupied")
|
|
|
+ return False
|
|
|
if not self.gripper_occupied:
|
|
|
logger.error("Gripper not occupied")
|
|
|
- return
|
|
|
- slot.occupied = True
|
|
|
- slot.cell_id = cell.id
|
|
|
- self.gripper_occupied = False
|
|
|
- logger.info(f"Cell {cell.id} inserted to slot at position {slot.position}")
|
|
|
- # Move to slot and insert cell
|
|
|
- pass
|
|
|
+ return False
|
|
|
+
|
|
|
+ # Move to slot position
|
|
|
+ try:
|
|
|
+ x, y, z = slot.position
|
|
|
+ # Move to safe height first
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ # Move down to insertion position
|
|
|
+ await self.movement.move_to_position(x, y, z)
|
|
|
+ # Release cell
|
|
|
+ if await self.movement.deactivate_gripper():
|
|
|
+ slot.occupied = True
|
|
|
+ slot.cell_id = cell.id
|
|
|
+ self.gripper_occupied = False
|
|
|
+ else:
|
|
|
+ raise RuntimeError("Failed to release cell")
|
|
|
+ # Move back to safe height
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ logger.info(f"Cell {cell.id} inserted to slot at position {slot.position}")
|
|
|
+ return True
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Failed to insert cell: {str(e)}")
|
|
|
+ return False
|
|
|
|
|
|
async def collect_cell_from_slot(self, slot: SlotConfig):
|
|
|
if self.gripper_occupied:
|
|
|
logger.error("Gripper already occupied")
|
|
|
return None
|
|
|
- # Collect cell from measurement slot
|
|
|
- self.gripper_occupied = True
|
|
|
- slot.occupied = False
|
|
|
- cell_id = slot.cell_id
|
|
|
- slot.cell_id = None
|
|
|
- logger.info(f"Cell {slot.cell_id} collected from slot at position {slot.position}")
|
|
|
- return cell_id
|
|
|
+
|
|
|
+ try:
|
|
|
+ x, y, z = slot.position
|
|
|
+ # Move to safe height first
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ # Move down to collection position
|
|
|
+ await self.movement.move_to_position(x, y, z)
|
|
|
+ # Grip cell
|
|
|
+ if await self.movement.activate_gripper():
|
|
|
+ self.gripper_occupied = True
|
|
|
+ cell_id = slot.cell_id
|
|
|
+ slot.occupied = False
|
|
|
+ slot.cell_id = None
|
|
|
+ else:
|
|
|
+ raise RuntimeError("Failed to grip cell")
|
|
|
+ # Move back to safe height
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ logger.info(f"Cell {cell_id} collected from slot at position {slot.position}")
|
|
|
+ return cell_id
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Failed to collect cell: {str(e)}")
|
|
|
+ await self.movement.deactivate_gripper() # Try to deactivate to avoid stuck gripper
|
|
|
+ self.gripper_occupied = False
|
|
|
+ return None
|
|
|
|
|
|
async def sort_cell(self, cell: Cell):
|
|
|
+ if not self.gripper_occupied:
|
|
|
+ logger.error("Gripper not occupied")
|
|
|
+ return False
|
|
|
if cell.status == CellStatus.FAILED:
|
|
|
- await self.dropoff_cell(cell.measurement_slot, self.rejected_grade)
|
|
|
+ await self.dropoff_cell(self.rejected_grade)
|
|
|
logger.info(f"Cell {cell.id} sorted to rejected grade")
|
|
|
- return
|
|
|
+ return True
|
|
|
for name, grade in self.dropoff_grades.items():
|
|
|
if cell.capacity >= grade.capacity_threshold:
|
|
|
- await self.dropoff_cell(cell, grade)
|
|
|
+ await self.dropoff_cell(grade)
|
|
|
self.gripper_occupied = False
|
|
|
logger.info(f"Cell {cell.id} sorted to grade {name}")
|
|
|
- return
|
|
|
+ return True
|
|
|
logger.error(f"No suitable grade found for cell {cell.id} with capacity {cell.capacity}")
|
|
|
+ return False
|
|
|
|
|
|
async def dropoff_cell(self, dropoff_grade: DropoffGrade):
|
|
|
- # Drop collected cell at position
|
|
|
- pass
|
|
|
+ if not self.gripper_occupied:
|
|
|
+ logger.error("Cannot drop off: gripper not occupied")
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ x, y, z = dropoff_grade.position
|
|
|
+ # Move to safe height first
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ # Move to dropoff position
|
|
|
+ await self.movement.move_to_position(x, y, z)
|
|
|
+ # Release cell
|
|
|
+ if await self.movement.deactivate_gripper():
|
|
|
+ self.gripper_occupied = False
|
|
|
+ else:
|
|
|
+ raise RuntimeError("Failed to release cell")
|
|
|
+ # Move back to safe height
|
|
|
+ await self.movement.move_to_position(x, y, self.system_settings.safe_height)
|
|
|
+ logger.info(f"Cell dropped off at grade {dropoff_grade.name}")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"Failed to drop off cell: {str(e)}")
|