mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-03-30 20:23:11 +00:00
Compare commits
13 Commits
50282664e0
...
694a779c66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
694a779c66 | ||
|
|
5d214ebcd8 | ||
|
|
0e11dacead | ||
|
|
7b68545db3 | ||
|
|
25960c2ed5 | ||
|
|
72c67ba25c | ||
|
|
cd9e7ef12c | ||
|
|
b85722f44d | ||
|
|
5a2cc2d709 | ||
|
|
644feced55 | ||
|
|
61ee446542 | ||
|
|
18f6685e18 | ||
|
|
e2052d4a2c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
configs/
|
||||
## Python
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "PLR_STATION_PRCXI",
|
||||
"name": "PLR_LH_TEST",
|
||||
"id": "PRCXI",
|
||||
"name": "PRCXI",
|
||||
"parent": null,
|
||||
"type": "device",
|
||||
"class": "liquid_handler.prcxi",
|
||||
@@ -16,10 +16,10 @@
|
||||
"_resource_child_name": "deck",
|
||||
"_resource_type": "unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Deck"
|
||||
},
|
||||
"host": "127.0.0.1",
|
||||
"host": "192.168.3.9",
|
||||
"port": 9999,
|
||||
"timeout": 10.0,
|
||||
"setup": false
|
||||
"setup": true
|
||||
},
|
||||
"data": {},
|
||||
"children": [
|
||||
@@ -35,9 +35,10 @@
|
||||
"plateT2",
|
||||
"plateT3",
|
||||
"rackT4",
|
||||
"plateT5"
|
||||
"plateT5",
|
||||
"plateT6"
|
||||
],
|
||||
"parent": "PLR_STATION_PRCXI",
|
||||
"parent": "PRCXI",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
@@ -184,6 +185,31 @@
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "plateT6",
|
||||
"name": "plateT6",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": []
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
|
||||
import json
|
||||
import traceback
|
||||
import uuid
|
||||
from unilabos.app.model import JobAddReq, JobData
|
||||
from unilabos.ros.nodes.presets.host_node import HostNode
|
||||
from unilabos.utils.type_check import serialize_result_info
|
||||
|
||||
|
||||
def get_resources() -> tuple:
|
||||
@@ -33,5 +35,10 @@ def job_add(req: JobAddReq) -> JobData:
|
||||
if "command" in action_args:
|
||||
action_args = action_args["command"]
|
||||
# print(f"job_add:{req.device_id} {action_name} {action_kwargs}")
|
||||
try:
|
||||
HostNode.get_instance().send_goal(req.device_id, action_type=action_type, action_name=action_name, action_kwargs=action_args, goal_uuid=req.job_id, server_info=req.server_info)
|
||||
except Exception as e:
|
||||
for bridge in HostNode.get_instance().bridges:
|
||||
if hasattr(bridge, "publish_job_status"):
|
||||
bridge.publish_job_status({}, req.job_id, "failed", serialize_result_info(traceback.format_exc(), False, {}))
|
||||
return JobData(jobId=req.job_id)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import traceback
|
||||
from typing import List, Sequence, Optional, Literal, Union, Iterator
|
||||
|
||||
import asyncio
|
||||
@@ -117,7 +118,7 @@ class LiquidHandlerAbstract(LiquidHandler):
|
||||
pass # This mode is not verified.
|
||||
else:
|
||||
if len(asp_vols) != len(targets):
|
||||
raise ValueError("Length of `vols` must match `targets`.")
|
||||
raise ValueError(f"Length of `asp_vols` {len(asp_vols)} must match `targets` {len(targets)}.")
|
||||
tip = next(self.current_tip)
|
||||
await self.pick_up_tips(tip)
|
||||
|
||||
@@ -160,6 +161,7 @@ class LiquidHandlerAbstract(LiquidHandler):
|
||||
await self.discard_tips()
|
||||
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
raise RuntimeError(f"Liquid addition failed: {e}") from e
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import collections
|
||||
import contextlib
|
||||
import json
|
||||
@@ -23,7 +24,7 @@ from pylabrobot.liquid_handling.standard import (
|
||||
ResourceMove,
|
||||
ResourceDrop,
|
||||
)
|
||||
from pylabrobot.resources import Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate
|
||||
from pylabrobot.resources import Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash
|
||||
|
||||
from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract
|
||||
|
||||
@@ -87,6 +88,12 @@ class PRCXI9300Container(Plate):
|
||||
|
||||
|
||||
class PRCXI9300Handler(LiquidHandlerAbstract):
|
||||
@property
|
||||
def reset_ok(self) -> bool:
|
||||
"""检查设备是否已重置成功。"""
|
||||
return self._unilabos_backend.is_reset_ok
|
||||
|
||||
|
||||
def __init__(self, deck: Deck, host: str, port: int, timeout: float, setup=True):
|
||||
tablets_info = []
|
||||
count = 0
|
||||
@@ -101,18 +108,18 @@ class PRCXI9300Handler(LiquidHandlerAbstract):
|
||||
|
||||
async def create_protocol(
|
||||
self,
|
||||
protocol_name: str,
|
||||
protocol_description: str,
|
||||
protocol_version: str,
|
||||
protocol_author: str,
|
||||
protocol_date: str,
|
||||
protocol_type: str,
|
||||
protocol_name: str = "",
|
||||
protocol_description: str = "",
|
||||
protocol_version: str = "",
|
||||
protocol_author: str = "",
|
||||
protocol_date: str = "",
|
||||
protocol_type: str = "",
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
self._unilabos_backend.create_protocol(protocol_name)
|
||||
|
||||
async def run_protocol(self):
|
||||
self._unilabos_backend.run_protocol()
|
||||
return self._unilabos_backend.run_protocol()
|
||||
|
||||
async def remove_liquid(
|
||||
self,
|
||||
@@ -253,11 +260,42 @@ class PRCXI9300Handler(LiquidHandlerAbstract):
|
||||
mix_rate: Optional[float] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
return await super().mix(targets, mix_time, mix_vol, height_to_bottom, offsets, mix_rate, none_keys)
|
||||
return await self._unilabos_backend.mix(targets, mix_time, mix_vol, height_to_bottom, offsets, mix_rate, none_keys)
|
||||
|
||||
def iter_tips(self, tip_racks: Sequence[TipRack]) -> Iterator[Resource]:
|
||||
return super().iter_tips(tip_racks)
|
||||
|
||||
async def pick_up_tips(self, tip_spots: List[TipSpot], use_channels: Optional[List[int]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None, **backend_kwargs):
|
||||
return await super().pick_up_tips(tip_spots, use_channels, offsets, **backend_kwargs)
|
||||
|
||||
async def aspirate(self, resources: Sequence[Container], vols: List[float],
|
||||
use_channels: Optional[List[int]] = None, flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Literal["wide", "tight", "custom"] = "wide", **backend_kwargs):
|
||||
return await super().aspirate(resources, vols, use_channels, flow_rates, offsets, liquid_height,
|
||||
blow_out_air_volume, spread, **backend_kwargs)
|
||||
|
||||
async def drop_tips(self, tip_spots: Sequence[Union[TipSpot, Trash]], use_channels: Optional[List[int]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None, allow_nonzero_volume: bool = False,
|
||||
**backend_kwargs):
|
||||
return await super().drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)
|
||||
|
||||
async def dispense(self, resources: Sequence[Container], vols: List[float],
|
||||
use_channels: Optional[List[int]] = None, flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Literal["wide", "tight", "custom"] = "wide", **backend_kwargs):
|
||||
return await super().dispense(resources, vols, use_channels, flow_rates, offsets, liquid_height,
|
||||
blow_out_air_volume, spread, **backend_kwargs)
|
||||
|
||||
async def discard_tips(self, use_channels: Optional[List[int]] = None, allow_nonzero_volume: bool = True,
|
||||
offsets: Optional[List[Coordinate]] = None, **backend_kwargs):
|
||||
return await super().discard_tips(use_channels, allow_nonzero_volume, offsets, **backend_kwargs)
|
||||
|
||||
def set_tiprack(self, tip_racks: Sequence[TipRack]):
|
||||
super().set_tiprack(tip_racks)
|
||||
|
||||
@@ -272,6 +310,13 @@ class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
"""
|
||||
|
||||
_num_channels = 8 # 默认通道数为 8
|
||||
_is_reset_ok = False
|
||||
|
||||
@property
|
||||
def is_reset_ok(self) -> bool:
|
||||
self._is_reset_ok = self.api_client.get_reset_status()
|
||||
return self._is_reset_ok
|
||||
|
||||
matrix_info: MatrixInfo
|
||||
protocol_name: str
|
||||
steps_todo_list = []
|
||||
@@ -296,19 +341,24 @@ class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
self.steps_todo_list = []
|
||||
|
||||
def run_protocol(self):
|
||||
assert self.is_reset_ok, "PRCXI9300Backend is not reset successfully. Please call setup() first."
|
||||
run_time = time.time()
|
||||
self.matrix_info = MatrixInfo(
|
||||
MatrixId=f"matrix_{run_time}",
|
||||
MatrixId=f"{int(run_time)}",
|
||||
MatrixName=f"protocol_{run_time}",
|
||||
MatrixCount=len(self.tablets_info),
|
||||
WorkTablets=self.tablets_info,
|
||||
)
|
||||
self.api_client.add_WorkTablet_Matrix(self.matrix_info)
|
||||
print(json.dumps(self.matrix_info, indent=2))
|
||||
res = self.api_client.add_WorkTablet_Matrix(self.matrix_info)
|
||||
assert res["Success"], f"Failed to create matrix: {res.get('Message', 'Unknown error')}"
|
||||
print(f"PRCXI9300Backend created matrix with ID: {self.matrix_info['MatrixId']}, result: {res}")
|
||||
solution_id = self.api_client.add_solution(
|
||||
f"protocol_{run_time}", self.matrix_info["MatrixId"], self.steps_todo_list
|
||||
)
|
||||
print(f"PRCXI9300Backend created solution with ID: {solution_id}")
|
||||
self.api_client.load_solution(solution_id)
|
||||
self.api_client.start()
|
||||
return self.api_client.start()
|
||||
|
||||
@classmethod
|
||||
def check_channels(cls, use_channels: List[int]) -> List[int]:
|
||||
@@ -323,6 +373,10 @@ class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
try:
|
||||
if self._execute_setup:
|
||||
self.api_client.call("IAutomation", "Reset")
|
||||
while not self.is_reset_ok:
|
||||
print("Waiting for PRCXI9300 to reset...")
|
||||
await asyncio.sleep(1)
|
||||
print("PRCXI9300 reset successfully.")
|
||||
except ConnectionRefusedError as e:
|
||||
raise RuntimeError(
|
||||
f"Failed to connect to PRCXI9300 API at {self.host}:{self.port}. "
|
||||
@@ -336,6 +390,18 @@ class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
"""Pick up tips from the specified resource."""
|
||||
# 12列,要PickUp A-H 1
|
||||
# PlateNo = 1-6 # 2行3列
|
||||
print("!!!!!!!!!" * 10)
|
||||
print(ops, "====="*10)
|
||||
# plate: PRCXI9300Container = ops[0].resource.parent.parent
|
||||
# deck: PRCXI9300Deck = plate.parent
|
||||
# plate_index = deck.children.index(plate)
|
||||
# tipspot = ops[0].resource
|
||||
# tipspot_index = tipspot.parent.children.index(tipspot)
|
||||
# print(f"PRCXI9300Backend pick_up_tips: plate_index={plate_index}, tipspot_index={tipspot_index}")
|
||||
# print(f"PRCXI9300Backend pick_up_tips: plate_index={plate_index}, plate.name={plate.name}")
|
||||
# print(plate._unilabos_state["Material"])
|
||||
# for op in ops:
|
||||
# print(f"PRCXI9300Backend pick_up_tips: {op.resource.name}")
|
||||
PlateNo = 1 # 第一块板
|
||||
hole_col = 2 # 第二列的8个孔
|
||||
step = self.api_client.Load(
|
||||
@@ -378,11 +444,41 @@ class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
raise ValueError("No matching Load step found for drop_tips.")
|
||||
print("PRCXI9300Backend drop_tips logged.")
|
||||
|
||||
async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None):
|
||||
volumes = [op.volume for op in ops]
|
||||
print(f"PRCXI9300Backend aspirate volumes: {volumes[0]} -> {int(volumes[0])} μL")
|
||||
PlateNo = 1
|
||||
async def mix(
|
||||
self,
|
||||
targets: Sequence[Container],
|
||||
mix_time: int = None,
|
||||
mix_vol: Optional[int] = None,
|
||||
height_to_bottom: Optional[float] = None,
|
||||
offsets: Optional[Coordinate] = None,
|
||||
mix_rate: Optional[float] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
volumes = [1]
|
||||
PlateNo = 2
|
||||
hole_col = 2
|
||||
blending_times = 1
|
||||
assert blending_times > 0
|
||||
step = self.api_client.Blending(
|
||||
"Left",
|
||||
dosage=int(volumes[0]),
|
||||
plate_no=PlateNo,
|
||||
is_whole_plate=False,
|
||||
hole_row=1,
|
||||
hole_col=hole_col,
|
||||
blending_times=blending_times,
|
||||
balance_height=0,
|
||||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||||
hole_numbers="1,2,3,4,5,6,7,8",
|
||||
)
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None):
|
||||
volumes = [1]
|
||||
# volumes = [op.volume for op in ops]
|
||||
# print(f"PRCXI9300Backend aspirate volumes: {volumes[0]} -> {int(volumes[0])} μL")
|
||||
PlateNo = 2
|
||||
hole_col = 4
|
||||
step = self.api_client.Imbibing(
|
||||
"Left",
|
||||
dosage=int(volumes[0]),
|
||||
@@ -398,9 +494,10 @@ class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[int] = None):
|
||||
volumes = [op.volume for op in ops]
|
||||
print(f"PRCXI9300Backend dispense volumes: {volumes[0]} -> {int(volumes[0])} μL")
|
||||
PlateNo = 1
|
||||
volumes = [1]
|
||||
# volumes = [op.volume for op in ops]
|
||||
# print(f"PRCXI9300Backend dispense volumes: {volumes[0]} -> {int(volumes[0])} μL")
|
||||
PlateNo = 2
|
||||
hole_col = 2
|
||||
step = self.api_client.Tapping(
|
||||
"Left",
|
||||
@@ -515,6 +612,11 @@ class PRCXI9300Api:
|
||||
"""GetErrorCode"""
|
||||
return self.call("IAutomation", "GetErrorCode")
|
||||
|
||||
def get_reset_status(self) -> Optional[str]:
|
||||
"""GetErrorCode"""
|
||||
res = self.call("IAutomation", "GetResetStatus")
|
||||
return not res
|
||||
|
||||
def clear_error_code(self) -> bool:
|
||||
"""RemoveErrorCodet"""
|
||||
return self.call("IAutomation", "RemoveErrorCodet")
|
||||
@@ -742,3 +844,110 @@ class PRCXI9300Api:
|
||||
"HoleNumbers": hole_numbers,
|
||||
"LiquidDispensingMethod": liquid_method,
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
deck = PRCXI9300Deck(name="PRCXI Deck", size_x=100, size_y=100, size_z=100)
|
||||
plate1 = PRCXI9300Container(name="rackT1", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate1.load_state({
|
||||
"Material": {
|
||||
"uuid": "80652665f6a54402b2408d50b40398df",
|
||||
"Code": "ZX-001-1000",
|
||||
"Name": "1000μL Tip头",
|
||||
"SummaryName": "1000μL Tip头",
|
||||
"PipetteHeight": 100,
|
||||
"materialEnum": 1
|
||||
}
|
||||
})
|
||||
|
||||
plate2 = PRCXI9300Container(name="plateT2", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate2.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
|
||||
plate3 = PRCXI9300Container(name="plateT3", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate3.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
|
||||
plate4 = PRCXI9300Container(name="rackT4", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate4.load_state({
|
||||
"Material": {
|
||||
"uuid": "80652665f6a54402b2408d50b40398df",
|
||||
"Code": "ZX-001-1000",
|
||||
"Name": "1000μL Tip头",
|
||||
"SummaryName": "1000μL Tip头",
|
||||
"PipetteHeight": 100,
|
||||
"materialEnum": 1
|
||||
}
|
||||
})
|
||||
|
||||
plate5 = PRCXI9300Container(name="plateT5", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate5.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
plate6 = PRCXI9300Container(name="plateT6", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate6.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
|
||||
from pylabrobot.resources.opentrons.tip_racks import tipone_96_tiprack_200ul
|
||||
from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat
|
||||
tip_rack = tipone_96_tiprack_200ul("TipRack")
|
||||
well_containers = corning_96_wellplate_360ul_flat("Plate")
|
||||
# from pprint import pprint
|
||||
# pprint(well_containers.children)
|
||||
plate1.assign_child_resource(tip_rack, location=Coordinate(0, 0, 0))
|
||||
plate2.assign_child_resource(well_containers, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate2, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate3, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate4, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate5, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate6, location=Coordinate(0, 0, 0))
|
||||
input("debug....")
|
||||
handler = PRCXI9300Handler(deck=deck, host="192.168.3.9", port=9999, timeout=10.0, setup=False)
|
||||
handler.set_tiprack([tip_rack]) # Set the tip rack for the handler
|
||||
asyncio.run(handler.setup()) # Initialize the handler and setup the connection
|
||||
asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection
|
||||
input("Creating protocol...")
|
||||
# asyncio.run(handler.pick_up_tips(tip_rack.children[:8],[0,1,2,3,4,5,6,7]))
|
||||
# asyncio.run(handler.aspirate(tip_rack.children[:8],[0,1,2,3,4,5,6,7]))
|
||||
# asyncio.run(handler.dispense(tip_rack.children[:8],[0,1,2,3,4,5,6,7]))
|
||||
# asyncio.run(handler.drop_tips(tip_rack.children[:8],[0,1,2,3,4,5,6,7]))
|
||||
asyncio.run(handler.pick_up_tips([], [], []))
|
||||
asyncio.run(handler.aspirate([], [], []))
|
||||
asyncio.run(handler.dispense([], [], []))
|
||||
asyncio.run(handler.mix([], mix_time=3, mix_vol=10, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100))
|
||||
asyncio.run(handler.drop_tips([], [], []))
|
||||
|
||||
# asyncio.run(handler.add_liquid(
|
||||
# asp_vols=[100]*8,
|
||||
# dis_vols=[100]*8,
|
||||
# reagent_sources=well_containers.children[-8:],
|
||||
# targets=well_containers.children[:8],
|
||||
# use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||||
# flow_rates=[None] * 8,
|
||||
# offsets=[Coordinate(0, 0, 0)] * 8,
|
||||
# liquid_height=[None] * 8,
|
||||
# blow_out_air_volume=[None] * 8,
|
||||
# spread="wide",
|
||||
# ))
|
||||
input("pick_up_tips add step")
|
||||
asyncio.run(handler.run_protocol()) # Run the protocol
|
||||
input("Running protocol...")
|
||||
print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info
|
||||
|
||||
|
||||
|
||||
input("Press Enter to continue...") # Wait for user input before proceeding
|
||||
print("PRCXI9300Handler initialized with deck and host settings.")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -132,7 +132,7 @@ _msg_converter: Dict[Type, Any] = {
|
||||
Bool: lambda x: Bool(data=bool(x)),
|
||||
str: str,
|
||||
String: lambda x: String(data=str(x)),
|
||||
Point: lambda x: Point(x=x.x, y=x.y, z=x.z) if not isinstance(x, dict) else Point(x=x.get("x", 0.0), y=x.get("y", 0.0), z=x.get("z", 0.0)),
|
||||
Point: lambda x: Point(x=x.x, y=x.y, z=x.z) if not isinstance(x, dict) else Point(x=float(x.get("x", 0.0)), y=float(x.get("y", 0.0)), z=float(x.get("z", 0.0))),
|
||||
Resource: lambda x: Resource(
|
||||
id=x.get("id", ""),
|
||||
name=x.get("name", ""),
|
||||
|
||||
@@ -603,8 +603,7 @@ class HostNode(BaseROS2DeviceNode):
|
||||
if action_name == "test_latency" and server_info is not None:
|
||||
self.server_latest_timestamp = server_info.get("send_timestamp", 0.0)
|
||||
if action_id not in self._action_clients:
|
||||
self.lab_logger().error(f"[Host Node] ActionClient {action_id} not found.")
|
||||
return
|
||||
raise ValueError(f"ActionClient {action_id} not found.")
|
||||
|
||||
action_client: ActionClient = self._action_clients[action_id]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user