|
|
@@ -36,6 +36,8 @@ class LoaderSystem:
|
|
|
|
|
|
self.pump_controller = PumpController(self.config, self.gpio)
|
|
|
|
|
|
+ self.feeder_prepared = False
|
|
|
+
|
|
|
async def run(self):
|
|
|
await self.controller.connect()
|
|
|
try:
|
|
|
@@ -62,25 +64,78 @@ class LoaderSystem:
|
|
|
self.logger.error(f"Error polling I2C channels: {str(e)}")
|
|
|
await asyncio.sleep(1) # Poll every second
|
|
|
|
|
|
+ def check_cell_voltage(self, voltage, cell_id_str = ""):
|
|
|
+ if voltage < abs(self.config.feeder.min_voltage):
|
|
|
+ self.logger.info(f"Cell {cell_id_str} voltage too low, discarding cell")
|
|
|
+ return False
|
|
|
+ if voltage < 0:
|
|
|
+ self.logger.info(f"Cell {cell_id_str} has wrong polarity, discarding cell")
|
|
|
+ return False
|
|
|
+
|
|
|
+ self.logger.info(f"Cell {cell_id_str} voltage({voltage}) is good")
|
|
|
+ return True
|
|
|
+
|
|
|
async def _loader_loop(self):
|
|
|
+ """
|
|
|
+ Main loop for the loader system.
|
|
|
+
|
|
|
+ Checks for free slots and tries to fill them with cells.
|
|
|
+ If no more free slots are available, it checks for completed measurements
|
|
|
+ and sorts the cells accordingly.
|
|
|
+ """
|
|
|
while True:
|
|
|
await asyncio.sleep(0.1) # avoid busy loop
|
|
|
|
|
|
# Check for free slots loop
|
|
|
while True:
|
|
|
+ cell_id_str = ""
|
|
|
+ # Discard cells until acceptable cell is found
|
|
|
+ while not self.feeder_prepared:
|
|
|
+ # Check if cell is present in feeder
|
|
|
+ cell_id_str = self.vision.read_datamatrix()
|
|
|
+ if not cell_id_str:
|
|
|
+ self.logger.debug("No cell detected")
|
|
|
+ break # No cell detected
|
|
|
+
|
|
|
+ # Measure cell voltage with probe
|
|
|
+ io_conf = self.config.gpio
|
|
|
+ self.gpio.set_pin(io_conf.probe_pin, 1)
|
|
|
+ await asyncio.sleep(0.1) # Wait for probe to deploy
|
|
|
+ cell_v = await self.i2c.read_channel(1) # Measure cell voltage
|
|
|
+ self.gpio.set_pin(io_conf.probe_pin, 0)
|
|
|
+ self.logger.debug(f"Cell voltage: {cell_v}")
|
|
|
+
|
|
|
+ if self.check_cell_voltage(cell_v, cell_id_str):
|
|
|
+ self.feeder_prepared = True
|
|
|
+ break # Desired case!
|
|
|
+
|
|
|
+ # Discard cell directly from feeder
|
|
|
+ self.logger.info(f"Cell {cell_id_str} voltage({cell_v}) is bad, discarding cell")
|
|
|
+ self.gpio.do_step(io_conf.measure_dir_pin, io_conf.measure_step_pin, 1600, 200) # Exactly half a turn
|
|
|
+ await asyncio.sleep(1) # Wait for cell to be ejected
|
|
|
+ try:
|
|
|
+ await self.controller.pick_cell_from_feeder()
|
|
|
+ await self.controller.dropoff_cell()
|
|
|
+ except Exception as e:
|
|
|
+ self.logger.error(f"Failed to process cell {cell_id}: {str(e)}")
|
|
|
+ break
|
|
|
+
|
|
|
slot = self.controller.get_next_free_slot()
|
|
|
if not slot:
|
|
|
- break
|
|
|
- # Pick and place new cell
|
|
|
- cell_id_str = self.vision.read_datamatrix()
|
|
|
+ break # No free slots available
|
|
|
+
|
|
|
if not cell_id_str:
|
|
|
- self.logger.debug("No cell detected")
|
|
|
break
|
|
|
+
|
|
|
+ # Pick and place new cell
|
|
|
cell_id = int(cell_id_str)
|
|
|
self.logger.info(f"Processing cell {cell_id}")
|
|
|
cell = self.controller.add_cell(cell_id)
|
|
|
try:
|
|
|
+ self.gpio.do_step(io_conf.measure_dir_pin, io_conf.measure_step_pin, 1600, 200) # Exactly half a turn
|
|
|
+ await asyncio.sleep(1) # Wait for cell to be ejected
|
|
|
await self.controller.pick_cell_from_feeder()
|
|
|
+ self.feeder_prepared = False
|
|
|
await self.controller.insert_cell_to_slot(cell, slot)
|
|
|
except Exception as e:
|
|
|
self.logger.error(f"Failed to process cell {cell_id}: {str(e)}")
|