main.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import asyncio
  2. import logging
  3. from robot_control.src.robot.controller import RobotController
  4. from robot_control.src.utils.config import ConfigParser
  5. from robot_control.src.vision.datamatrix import DataMatrixReader
  6. from robot_control.src.api.i2c_handler import I2C, MockI2C
  7. from robot_control.src.vendor.mcp3428 import MCP3428
  8. from robot_control.src.robot.pump_controller import PumpController
  9. from robot_control.src.api.gpio import PiGPIO, MockGPIO
  10. from robot_control.src.utils.logging import setup_logging
  11. from robot_control.src.robot.mag_distributor import MagDistributor
  12. class LoaderSystem:
  13. def __init__(self):
  14. self.config = ConfigParser().config
  15. setup_logging(self.config)
  16. gpio_config = self.config.gpio
  17. if gpio_config.debug:
  18. self.gpio = MockGPIO()
  19. else:
  20. self.gpio = PiGPIO(out_pins=[gpio_config.pump_pin, gpio_config.valve_pin])
  21. self.logger = logging.getLogger(__name__)
  22. self.vision = DataMatrixReader(self.config.vision)
  23. self.logger.info("Initializing LoaderSystem")
  24. self.vision.initialize()
  25. # Use mock I2C device if debug is enabled
  26. i2c_device_class = MCP3428 if not self.config.i2c.debug else MockI2C
  27. self.i2c = I2C(i2c_device_class)
  28. self.i2c.initialize()
  29. self.logger.info(f"I2C initialized with {i2c_device_class.__name__}")
  30. self.pump_controller = PumpController(self.config, self.gpio)
  31. # Initialize MagDistributor
  32. self.mag_distributor = MagDistributor(self.config, self.gpio)
  33. self.feeder_queue: asyncio.Queue[int] = asyncio.Queue(self.config.feeder.max_capacity)
  34. self.defeeder_queue: asyncio.Queue[int] = asyncio.Queue(self.config.defeeder.max_capacity)
  35. # Pass all hardware interfaces to the controller
  36. self.controller = RobotController(
  37. self.config,
  38. self.gpio,
  39. self.i2c,
  40. self.vision,
  41. self.pump_controller,
  42. self.feeder_queue,
  43. self.defeeder_queue
  44. )
  45. async def run(self):
  46. await self.controller.connect()
  47. try:
  48. await asyncio.gather(
  49. self._loader_loop(),
  50. self._poll_i2c_channels(),
  51. self._queue_monitor_loop(),
  52. )
  53. finally:
  54. self.cleanup()
  55. self.logger.info("Cleaning up resources...")
  56. async def _poll_i2c_channels(self):
  57. while True:
  58. try:
  59. readings = await self.i2c.read_channels([1, 3, 4])
  60. for channel, value in readings.items():
  61. self.logger.debug(f"Channel {channel} reading: {value}")
  62. if channel == 3: # Pressure reading
  63. self.pump_controller.handle_tank_reading(value)
  64. if channel == 4:
  65. state = self.pump_controller.check_endeffector_state(value)
  66. self.controller.set_suction_state(state)
  67. except Exception as e:
  68. self.logger.error(f"Error polling I2C channels: {str(e)}")
  69. await asyncio.sleep(1) # Poll every second
  70. async def _loader_loop(self):
  71. """
  72. Main loop for the loader system.
  73. Orchestrates cell preparation, slot filling, and measurement processing.
  74. """
  75. while True:
  76. await asyncio.sleep(0.1) # avoid busy loop
  77. while True:
  78. # Prepare a cell in the feeder (returns True if a cell is ready)
  79. if not await self.controller.prepare_feeder_cell():
  80. break
  81. # Fill the next free slot (returns True if a cell was placed)
  82. if not await self.controller.fill_next_free_slot():
  83. break
  84. # Check for completed measurements and sort cell
  85. await self.controller.process_finished_measurement()
  86. async def _queue_monitor_loop(self):
  87. """
  88. Periodically checks feeder and defeeder queues and calls placeholder functions.
  89. """
  90. while True:
  91. # Feeder: If queue below max, trigger refill placeholder
  92. if not self.feeder_queue.full():
  93. self.logger.info(f"Refilling feeder...")
  94. await asyncio.get_event_loop().run_in_executor(
  95. None, self.mag_distributor.mag_to_feeder
  96. )
  97. await self.feeder_queue.put(1) # Add to queue
  98. # Defeeder: If queue not empty, process next cell
  99. if not self.defeeder_queue.empty():
  100. magazine_id = await self.defeeder_queue.get() # Remove from queue
  101. self.logger.info(f"Processing defeeder to magazine {magazine_id}...")
  102. await asyncio.get_event_loop().run_in_executor(
  103. None, self.mag_distributor.defeeder_to_mag, magazine_id
  104. )
  105. await asyncio.sleep(2) # Adjust interval as needed
  106. def cleanup(self):
  107. self.gpio.cleanup() # Ensure PumpController cleans up gpio
  108. if __name__ == "__main__":
  109. loader_system = LoaderSystem()
  110. asyncio.run(loader_system.run())