* 修改lh的json启动

* 修改lh的json启动

* 修改backend,做成sim的通用backend

* 修改yaml的地址,3D模型适配网页生产环境

* 添加laiyu硬件连接

* 修改移液枪的状态判断方法,

修改移液枪的状态判断方法,
添加三轴的表定点与零点之间的转换
添加三轴真实移动的backend

* 修改laiyu移液站

简化移动方法,
取消软件限制位置,
修改当值使用Z轴时也需要重新复位Z轴的问题

* 更新lh以及laiyu workshop

1,现在可以直接通过修改backend,适配其他的移液站,主类依旧使用LiquidHandler,不用重新编写

2,修改枪头判断标准,使用枪头自身判断而不是类的判断,

3,将归零参数用毫米计算,方便手动调整,

4,修改归零方式,上电使用机械归零,确定机械零点,手动归零设置工作区域零点方便计算,二者互不干涉

* 修改枪头动作

* 修改虚拟仿真方法

---------

Co-authored-by: zhangshixiang <@zhangshixiang>
Co-authored-by: Junhan Chang <changjh@dp.tech>
This commit is contained in:
q434343
2025-11-15 02:50:17 +08:00
committed by GitHub
parent 0bf6994f95
commit a599eb70e5
98 changed files with 16477 additions and 126 deletions

View File

@@ -7,6 +7,8 @@ from collections import Counter
from typing import List, Sequence, Optional, Literal, Union, Iterator, Dict, Any, Callable, Set, cast
from pylabrobot.liquid_handling import LiquidHandler, LiquidHandlerBackend, LiquidHandlerChatterboxBackend, Strictness
from unilabos.devices.liquid_handling.rviz_backend import UniLiquidHandlerRvizBackend
from unilabos.devices.liquid_handling.laiyu.backend.laiyu_v_backend import UniLiquidHandlerLaiyuBackend
from pylabrobot.liquid_handling.liquid_handler import TipPresenceProbingMethod
from pylabrobot.liquid_handling.standard import GripDirection
from pylabrobot.resources import (
@@ -29,12 +31,15 @@ from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode
class LiquidHandlerMiddleware(LiquidHandler):
def __init__(self, backend: LiquidHandlerBackend, deck: Deck, simulator: bool = False, channel_num: int = 8):
def __init__(self, backend: LiquidHandlerBackend, deck: Deck, simulator: bool = False, channel_num: int = 8, total_height: float = 310, **kwargs):
self._simulator = simulator
self.channel_num = channel_num
joint_config = kwargs.get("joint_config", None)
if simulator:
self._simulate_backend = LiquidHandlerChatterboxBackend(channel_num)
self._simulate_backend = UniLiquidHandlerRvizBackend(channel_num,total_height, joint_config=joint_config, lh_device_id = deck.name)
self._simulate_handler = LiquidHandlerAbstract(self._simulate_backend, deck, False)
if hasattr(backend, "total_height"):
backend.total_height = total_height
super().__init__(backend, deck)
async def setup(self, **backend_kwargs):
@@ -217,7 +222,6 @@ class LiquidHandlerMiddleware(LiquidHandler):
offsets,
liquid_height,
blow_out_air_volume,
spread,
**backend_kwargs,
)
@@ -540,16 +544,51 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
support_touch_tip = True
_ros_node: BaseROS2DeviceNode
def __init__(self, backend: LiquidHandlerBackend, deck: Deck, simulator: bool=False, channel_num:int = 8):
def __init__(self, backend: LiquidHandlerBackend, deck: Deck, simulator: bool=False, channel_num:int = 8,total_height: float = 310,**backend_kwargs):
"""Initialize a LiquidHandler.
Args:
backend: Backend to use.
deck: Deck to use.
"""
backend_type = None
if isinstance(backend, dict) and "type" in backend:
backend_dict = backend.copy()
type_str = backend_dict.pop("type")
try:
# Try to get class from string using globals (current module), or fallback to pylabrobot or unilabos namespaces
backend_cls = None
if type_str in globals():
backend_cls = globals()[type_str]
else:
# Try resolving dotted notation, e.g. "xxx.yyy.ClassName"
components = type_str.split(".")
mod = None
if len(components) > 1:
module_name = ".".join(components[:-1])
try:
import importlib
mod = importlib.import_module(module_name)
except ImportError:
mod = None
if mod is not None:
backend_cls = getattr(mod, components[-1], None)
if backend_cls is None:
# Try pylabrobot style import (if available)
try:
import pylabrobot
backend_cls = getattr(pylabrobot, type_str, None)
except Exception:
backend_cls = None
if backend_cls is not None and isinstance(backend_cls, type):
backend_type = backend_cls(**backend_dict) # pass the rest of dict as kwargs
except Exception as exc:
raise RuntimeError(f"Failed to convert backend type '{type_str}' to class: {exc}")
else:
backend_type = backend
self._simulator = simulator
self.group_info = dict()
super().__init__(backend, deck, simulator, channel_num)
super().__init__(backend_type, deck, simulator, channel_num,total_height,**backend_kwargs)
def post_init(self, ros_node: BaseROS2DeviceNode):
self._ros_node = ros_node