diff --git a/docker-compose.yml b/docker-compose.yml index e58872c..bab7423 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,25 +1,24 @@ services: - teleshake: build: ./teleshake/ environment: - PORT=50050 - ports: - - "50050:50050" + # ports: + # - "50050:50050" network_mode: host sila-browser: image: registry.gitlab.com/unitelabs/sila2/sila-browser:latest network_mode: host - ports: - - "3000:3000" + # ports: + # - "3000:3000" robot-arm: build: ./robot-arm/ network_mode: host - environment: - - ROBOT_IP=192.168.1.4 # Change + # environment: + # - ROBOT_IP=192.168.1.4 # Change # command: [ "python", "-m", "genericroboticarm", "--address", "0.0.0.0" ] command: python -m genericroboticarm --port 50054 --address 0.0.0.0 -r XArm --simulation volumes: @@ -78,4 +77,4 @@ services: network_mode: host volumes: - pgdata: \ No newline at end of file + pgdata: diff --git a/laborchestrator/.gitignore b/laborchestrator/.gitignore new file mode 100644 index 0000000..38618e7 --- /dev/null +++ b/laborchestrator/.gitignore @@ -0,0 +1,3 @@ +jssp**.json +Schedule** +WFG** diff --git a/laborchestrator/platform_config.yaml b/laborchestrator/platform_config.yaml index c93b118..5a5e1b4 100755 --- a/laborchestrator/platform_config.yaml +++ b/laborchestrator/platform_config.yaml @@ -20,9 +20,15 @@ sila_servers: shaker_6_d_pos_: capacity: 1 + scanners: + scanner1: + capacity: 1 + resolution: 640 + # ------ Translation to used resources in the process description ------ # the key must match the categories above and the values must match the required resources in the workflow description pythonlab_translation: storage: LabwareStorageResource movers: MoverServiceResource shakers: ShakerServiceResource + scanners: ScannerResource diff --git a/laborchestrator/vu_lab/processes/__init__.py b/laborchestrator/vu_lab/processes/__init__.py index e69de29..833f19b 100644 --- a/laborchestrator/vu_lab/processes/__init__.py +++ b/laborchestrator/vu_lab/processes/__init__.py @@ -0,0 +1,2 @@ +from .basic_process import BasicProcess +from .mini_process import MiniProcess diff --git a/laborchestrator/vu_lab/processes/basic_process.py b/laborchestrator/vu_lab/processes/basic_process.py index cdc2aaa..5fbe94c 100644 --- a/laborchestrator/vu_lab/processes/basic_process.py +++ b/laborchestrator/vu_lab/processes/basic_process.py @@ -6,7 +6,7 @@ from pythonlab.resources.services.labware_storage import LabwareStorageResource from pythonlab.resources.services.moving import MoverServiceResource from pythonlab.resources.services.shaker import ShakerServiceResource - +from vu_lab.resources.scanner_resource import ScannerResource class BasicProcess(PLProcess, ABC): def __init__( @@ -33,6 +33,8 @@ def create_resources(self) -> None: self.shaker_pool = ShakerServiceResource(proc=self, name=None) + self.scanner1 = ScannerResource(proc=self, name="scanner1") + # the containers are automatically named/enumerated. You can change the naming without causing problems self.containers = [ LabwareResource( diff --git a/laborchestrator/vu_lab/processes/scanner_process.py b/laborchestrator/vu_lab/processes/scanner_process.py new file mode 100644 index 0000000..a8c9982 --- /dev/null +++ b/laborchestrator/vu_lab/processes/scanner_process.py @@ -0,0 +1,45 @@ +"""Duplicate this file and add/modify the missing parts to create new processes""" + +from pythonlab.process import PLProcess +from vu_lab.processes.basic_process import BasicProcess +from pythonlab.resource import LabwareResource +from vu_lab.resources.scanner_resource import ScannerResource + +DURATION = 10 +FREQUENCY = 10 +NUM_BEDS = 1 +PRIORITY = 3 + + +class ScannerProcess(BasicProcess): + """A simple test process that moves plates to a scanner, scans them, and returns them to the hotel.""" + + def __init__( + self, + priority: int = PRIORITY, + num_beds: int = NUM_BEDS, + duration: float = DURATION, + frequency: float = FREQUENCY, + ): + super().__init__( + priority=priority, num_plates=num_beds, process_name="Scanner process" + ) + self.duration = duration + self.frequency = frequency + + def init_service_resources(self): + super().init_service_resources() + self.container = self.containers[0] + self.container.set_start_position(self.hotel1, 1) + + def process(self): + + resolution = 640 + # Loop through all containers and scan them + for idx in range(self.num_mw_plates): + cont = self.containers[idx] + + # Move all containers to shaker + self.robot_arm.move(cont, self.scanner1) + self.scanner1.scan(cont, resolution) + self.robot_arm.move(cont, self.hotel1) diff --git a/laborchestrator/vu_lab/resources/scanner_resource.py b/laborchestrator/vu_lab/resources/scanner_resource.py new file mode 100644 index 0000000..c1f82de --- /dev/null +++ b/laborchestrator/vu_lab/resources/scanner_resource.py @@ -0,0 +1,42 @@ +"""Duplicate this file and add/modify the missing parts to create a new resource""" + +import logging +from pythonlab.resource import ServiceResource + +DURATION = 10 +FREQUENCY = 10 +NUM_BEDS = 1 +PRIORITY = 3 + + +class ScannerResource(ServiceResource): + """ + Flatbed scanner resource as a service. + + :param Resource: [description] + :type Resource: [type] + """ + + def __init__(self, proc, name: str = "Scanner"): + super().__init__(proc=proc, name=name) + + self._resolution = 640 + + def init(self): + logging.debug(f"init {self.name}") + + def scan( + self, + container: ServiceResource, + resolution: int, + **kwargs, + ): + kwargs.update( + { + "fct": "scan", + "resolution": resolution, + } + ) + + print(f"==[ Scan invoked.") + self.proc.add_process_step(self, [container], **kwargs) diff --git a/laborchestrator/vu_lab/wrappers/scanner_wrapper.py b/laborchestrator/vu_lab/wrappers/scanner_wrapper.py new file mode 100644 index 0000000..f96e965 --- /dev/null +++ b/laborchestrator/vu_lab/wrappers/scanner_wrapper.py @@ -0,0 +1,38 @@ +from laborchestrator.structures import ProcessStep, ContainerInfo +from laborchestrator.engine.worker_interface import Observable + +from vu_lab.wrappers import DeviceInterface + +from sila2.client import SilaClient as ScannerClient + + +class ScannerWrapper(DeviceInterface): + @staticmethod + def get_SiLA_handler( + step: ProcessStep, + cont: ContainerInfo, + sila_client: ScannerClient, + **kwargs, + ) -> Observable: + pass + + # Start scanning + # Stop scanning + # Start scan runtime + + def start_scan( + self, + client: ScannerClient, + resolution: int, + ) -> Observable: + """ + Start scanning with the specified mode, duration, and displacement. + :param client: SiLA client for the shaker device + :param resolution: The scanner resolution. + """ + + return client.ScanController.start_scan_step(resolution) + + def abort_scan(self, client: ScannerClient) -> Observable: + + return client.ScanController.abort_shake()