mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-03-28 08:33:07 +00:00
Compare commits
2 Commits
a354965f8e
...
v0.9.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7db3123547 | ||
|
|
6da7a20a7a |
132
.github/workflows/multi-platform-build.yml
vendored
132
.github/workflows/multi-platform-build.yml
vendored
@@ -1,132 +0,0 @@
|
|||||||
name: Multi-Platform Conda Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main, dev ]
|
|
||||||
tags: [ 'v*' ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main, dev ]
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
platforms:
|
|
||||||
description: '选择构建平台 (逗号分隔): linux-64, osx-64, osx-arm64, win-64'
|
|
||||||
required: false
|
|
||||||
default: 'osx-arm64'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: ubuntu-latest
|
|
||||||
platform: linux-64
|
|
||||||
env_file: unilabos-linux-64.yaml
|
|
||||||
- os: macos-13 # Intel
|
|
||||||
platform: osx-64
|
|
||||||
env_file: unilabos-osx-64.yaml
|
|
||||||
- os: macos-latest # ARM64
|
|
||||||
platform: osx-arm64
|
|
||||||
env_file: unilabos-osx-arm64.yaml
|
|
||||||
- os: windows-latest
|
|
||||||
platform: win-64
|
|
||||||
env_file: unilabos-win64.yaml
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash -l {0}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Check if platform should be built
|
|
||||||
id: should_build
|
|
||||||
run: |
|
|
||||||
if [[ "${{ github.event_name }}" != "workflow_dispatch" ]]; then
|
|
||||||
echo "should_build=true" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ -z "${{ github.event.inputs.platforms }}" ]]; then
|
|
||||||
echo "should_build=true" >> $GITHUB_OUTPUT
|
|
||||||
elif [[ "${{ github.event.inputs.platforms }}" == *"${{ matrix.platform }}"* ]]; then
|
|
||||||
echo "should_build=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "should_build=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Setup Miniconda
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
uses: conda-incubator/setup-miniconda@v3
|
|
||||||
with:
|
|
||||||
miniconda-version: "latest"
|
|
||||||
channels: conda-forge,robostack-staging,defaults
|
|
||||||
channel-priority: strict
|
|
||||||
activate-environment: build-env
|
|
||||||
auto-activate-base: false
|
|
||||||
auto-update-conda: false
|
|
||||||
show-channel-urls: true
|
|
||||||
|
|
||||||
- name: Install boa and build tools
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
run: |
|
|
||||||
conda install -c conda-forge boa conda-build
|
|
||||||
|
|
||||||
- name: Show environment info
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
run: |
|
|
||||||
conda info
|
|
||||||
conda list | grep -E "(boa|conda-build)"
|
|
||||||
echo "Platform: ${{ matrix.platform }}"
|
|
||||||
echo "OS: ${{ matrix.os }}"
|
|
||||||
|
|
||||||
- name: Build conda package
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
run: |
|
|
||||||
if [[ "${{ matrix.platform }}" == "osx-arm64" ]]; then
|
|
||||||
boa build -m ./recipes/conda_build_config.yaml -m ./recipes/macos_sdk_config.yaml ./recipes/ros-humble-unilabos-msgs
|
|
||||||
else
|
|
||||||
boa build -m ./recipes/conda_build_config.yaml ./recipes/ros-humble-unilabos-msgs
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: List built packages
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
run: |
|
|
||||||
echo "Built packages in conda-bld:"
|
|
||||||
find $CONDA_PREFIX/conda-bld -name "*.tar.bz2" | head -10
|
|
||||||
ls -la $CONDA_PREFIX/conda-bld/${{ matrix.platform }}/ || echo "${{ matrix.platform }} directory not found"
|
|
||||||
ls -la $CONDA_PREFIX/conda-bld/noarch/ || echo "noarch directory not found"
|
|
||||||
echo "CONDA_PREFIX: $CONDA_PREFIX"
|
|
||||||
echo "Full path would be: $CONDA_PREFIX/conda-bld/**/*.tar.bz2"
|
|
||||||
|
|
||||||
- name: Prepare artifacts for upload
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
run: |
|
|
||||||
mkdir -p ${{ runner.temp }}/conda-packages
|
|
||||||
find $CONDA_PREFIX/conda-bld -name "*.tar.bz2" -exec cp {} ${{ runner.temp }}/conda-packages/ \;
|
|
||||||
echo "Copied files to temp directory:"
|
|
||||||
ls -la ${{ runner.temp }}/conda-packages/
|
|
||||||
|
|
||||||
- name: Upload conda package artifacts
|
|
||||||
if: steps.should_build.outputs.should_build == 'true'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: conda-package-${{ matrix.platform }}
|
|
||||||
path: ${{ runner.temp }}/conda-packages
|
|
||||||
if-no-files-found: warn
|
|
||||||
retention-days: 30
|
|
||||||
|
|
||||||
- name: Create release assets (on tags)
|
|
||||||
if: steps.should_build.outputs.should_build == 'true' && startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
mkdir -p release-assets
|
|
||||||
find $CONDA_PREFIX/conda-bld -name "*.tar.bz2" -exec cp {} release-assets/ \;
|
|
||||||
|
|
||||||
- name: Upload to release
|
|
||||||
if: steps.should_build.outputs.should_build == 'true' && startsWith(github.ref, 'refs/tags/')
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
with:
|
|
||||||
files: release-assets/*
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -234,7 +234,3 @@ CATKIN_IGNORE
|
|||||||
|
|
||||||
*.graphml
|
*.graphml
|
||||||
unilabos/device_mesh/view_robot.rviz
|
unilabos/device_mesh/view_robot.rviz
|
||||||
|
|
||||||
|
|
||||||
# Certs
|
|
||||||
**/.certs
|
|
||||||
@@ -2,10 +2,4 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
ros2 action send_goal /devices/host_node/create_resource_detailed unilabos_msgs/action/_resource_create_from_outer/ResourceCreateFromOuter "{ resources: [ { 'category': '', 'children': [], 'config': { 'type': 'Well', 'size_x': 6.86, 'size_y': 6.86, 'size_z': 10.67, 'rotation': { 'x': 0, 'y': 0, 'z': 0, 'type': 'Rotation' }, 'category': 'well', 'model': null, 'max_volume': 360, 'material_z_thickness': 0.5, 'compute_volume_from_height': null, 'compute_height_from_volume': null, 'bottom_type': 'flat', 'cross_section_type': 'circle' }, 'data': { 'liquids': [], 'pending_liquids': [], 'liquid_history': [] }, 'id': 'plate_well_11_7', 'name': 'plate_well_11_7', 'pose': { 'orientation': { 'w': 1.0, 'x': 0.0, 'y': 0.0, 'z': 0.0 }, 'position': { 'x': 0.0, 'y': 0.0, 'z': 0.0 } }, 'sample_id': '', 'parent': 'plate', 'type': 'device' } ], device_ids: [ 'PLR_STATION' ], bind_parent_ids: [ 'plate' ], bind_locations: [ { 'x': 0.0, 'y': 0.0, 'z': 0.0 } ], other_calling_params: [ '{}' ] }"
|
ros2 action send_goal /devices/host_node/create_resource_detailed unilabos_msgs/action/_resource_create_from_outer/ResourceCreateFromOuter "{ resources: [ { 'category': '', 'children': [], 'config': { 'type': 'Well', 'size_x': 6.86, 'size_y': 6.86, 'size_z': 10.67, 'rotation': { 'x': 0, 'y': 0, 'z': 0, 'type': 'Rotation' }, 'category': 'well', 'model': null, 'max_volume': 360, 'material_z_thickness': 0.5, 'compute_volume_from_height': null, 'compute_height_from_volume': null, 'bottom_type': 'flat', 'cross_section_type': 'circle' }, 'data': { 'liquids': [], 'pending_liquids': [], 'liquid_history': [] }, 'id': 'plate_well_11_7', 'name': 'plate_well_11_7', 'pose': { 'orientation': { 'w': 1.0, 'x': 0.0, 'y': 0.0, 'z': 0.0 }, 'position': { 'x': 0.0, 'y': 0.0, 'z': 0.0 } }, 'sample_id': '', 'parent': 'plate', 'type': 'device' } ], device_ids: [ 'PLR_STATION' ], bind_parent_ids: [ 'plate' ], bind_locations: [ { 'x': 0.0, 'y': 0.0, 'z': 0.0 } ], other_calling_params: [ '{}' ] }"
|
||||||
```
|
|
||||||
|
|
||||||
使用mock_all.json启动,重新捕获MockContainerForChiller1
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ros2 action send_goal /devices/host_node/create_resource unilabos_msgs/action/_resource_create_from_outer_easy/ResourceCreateFromOuterEasy "{ 'res_id': 'MockContainerForChiller1', 'device_id': 'MockChiller1', 'class_name': 'container', 'parent': 'MockChiller1', 'bind_locations': { 'x': 0.0, 'y': 0.0, 'z': 0.0 }, 'liquid_input_slot': [ -1 ], 'liquid_type': [ 'CuCl2' ], 'liquid_volume': [ 100.0 ], 'slot_on_deck': '' }"
|
|
||||||
```
|
```
|
||||||
@@ -3,9 +3,7 @@
|
|||||||
{
|
{
|
||||||
"id": "MockChiller1",
|
"id": "MockChiller1",
|
||||||
"name": "模拟冷却器",
|
"name": "模拟冷却器",
|
||||||
"children": [
|
"children": [],
|
||||||
|
|
||||||
],
|
|
||||||
"parent": null,
|
"parent": null,
|
||||||
"type": "device",
|
"type": "device",
|
||||||
"class": "mock_chiller",
|
"class": "mock_chiller",
|
||||||
@@ -27,22 +25,6 @@
|
|||||||
"purpose": ""
|
"purpose": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "MockContainerForChiller1",
|
|
||||||
"name": "模拟容器",
|
|
||||||
"type": "container",
|
|
||||||
"parent": "MockChiller1",
|
|
||||||
"position": {
|
|
||||||
"x": 5,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"liquid_type": "CuCl2",
|
|
||||||
"liquid_volume": "100"
|
|
||||||
},
|
|
||||||
"children": []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "MockFilter1",
|
"id": "MockFilter1",
|
||||||
"name": "模拟过滤器",
|
"name": "模拟过滤器",
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
container:
|
|
||||||
description: regular organic container
|
|
||||||
class:
|
|
||||||
module: unilabos.resources.container:RegularContainer
|
|
||||||
type: unilabos
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from unilabos_msgs.msg import Resource
|
|
||||||
|
|
||||||
from unilabos.ros.msgs.message_converter import convert_from_ros_msg
|
|
||||||
|
|
||||||
|
|
||||||
class RegularContainer(object):
|
|
||||||
# 第一个参数必须是id传入
|
|
||||||
# noinspection PyShadowingBuiltins
|
|
||||||
def __init__(self, id: str, data: dict = None):
|
|
||||||
self.id = id
|
|
||||||
self.ulr_resource = Resource()
|
|
||||||
self.ulr_resource_data = data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ulr_resource_data(self):
|
|
||||||
return json.loads(self.ulr_resource.data) if self.ulr_resource.data else {}
|
|
||||||
|
|
||||||
@ulr_resource_data.setter
|
|
||||||
def ulr_resource_data(self, value: dict):
|
|
||||||
self.ulr_resource.data = json.dumps(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def liquid_type(self):
|
|
||||||
return self.ulr_resource_data.get("liquid_type", None)
|
|
||||||
|
|
||||||
@liquid_type.setter
|
|
||||||
def liquid_type(self, value: str):
|
|
||||||
if value is not None:
|
|
||||||
self.ulr_resource_data["liquid_type"] = value
|
|
||||||
else:
|
|
||||||
self.ulr_resource_data.pop("liquid_type", None)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def liquid_volume(self):
|
|
||||||
return self.ulr_resource_data.get("liquid_volume", None)
|
|
||||||
|
|
||||||
@liquid_volume.setter
|
|
||||||
def liquid_volume(self, value: float):
|
|
||||||
if value is not None:
|
|
||||||
self.ulr_resource_data["liquid_volume"] = value
|
|
||||||
else:
|
|
||||||
self.ulr_resource_data.pop("liquid_volume", None)
|
|
||||||
|
|
||||||
def get_ulr_resource(self) -> Resource:
|
|
||||||
"""
|
|
||||||
获取UlrResource对象
|
|
||||||
:return: UlrResource对象
|
|
||||||
"""
|
|
||||||
return self.ulr_resource
|
|
||||||
|
|
||||||
def get_ulr_resource_as_dict(self) -> Resource:
|
|
||||||
"""
|
|
||||||
获取UlrResource对象
|
|
||||||
:return: UlrResource对象
|
|
||||||
"""
|
|
||||||
return convert_from_ros_msg(self.ulr_resource)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.id}"
|
|
||||||
@@ -5,8 +5,6 @@ from typing import Union
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
|
||||||
from unilabos.resources.container import RegularContainer
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from pylabrobot.resources.resource import Resource as ResourcePLR
|
from pylabrobot.resources.resource import Resource as ResourcePLR
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -468,9 +466,6 @@ def initialize_resource(resource_config: dict) -> list[dict]:
|
|||||||
if resource_config.get("position") is not None:
|
if resource_config.get("position") is not None:
|
||||||
r["position"] = resource_config["position"]
|
r["position"] = resource_config["position"]
|
||||||
r = tree_to_list([r])
|
r = tree_to_list([r])
|
||||||
elif resource_class_config["type"] == "unilabos":
|
|
||||||
res_instance: RegularContainer = RESOURCE(id=resource_config["name"], data=resource_config.get("data", {}))
|
|
||||||
r = [res_instance.get_ulr_resource_as_dict()]
|
|
||||||
elif isinstance(RESOURCE, dict):
|
elif isinstance(RESOURCE, dict):
|
||||||
r = [RESOURCE.copy()]
|
r = [RESOURCE.copy()]
|
||||||
|
|
||||||
|
|||||||
@@ -343,8 +343,6 @@ class BaseROS2DeviceNode(Node, Generic[T]):
|
|||||||
ADD_LIQUID_TYPE = other_calling_param.pop("ADD_LIQUID_TYPE", [])
|
ADD_LIQUID_TYPE = other_calling_param.pop("ADD_LIQUID_TYPE", [])
|
||||||
LIQUID_VOLUME = other_calling_param.pop("LIQUID_VOLUME", [])
|
LIQUID_VOLUME = other_calling_param.pop("LIQUID_VOLUME", [])
|
||||||
LIQUID_INPUT_SLOT = other_calling_param.pop("LIQUID_INPUT_SLOT", [])
|
LIQUID_INPUT_SLOT = other_calling_param.pop("LIQUID_INPUT_SLOT", [])
|
||||||
if len(LIQUID_INPUT_SLOT) and LIQUID_INPUT_SLOT[0] == -1:
|
|
||||||
print("create container")
|
|
||||||
slot = other_calling_param.pop("slot", "-1")
|
slot = other_calling_param.pop("slot", "-1")
|
||||||
if slot != "-1": # slot为负数的时候采用assign方法
|
if slot != "-1": # slot为负数的时候采用assign方法
|
||||||
other_calling_param["slot"] = slot
|
other_calling_param["slot"] = slot
|
||||||
|
|||||||
@@ -383,24 +383,18 @@ class HostNode(BaseROS2DeviceNode):
|
|||||||
liquid_volume: list[int],
|
liquid_volume: list[int],
|
||||||
slot_on_deck: str,
|
slot_on_deck: str,
|
||||||
):
|
):
|
||||||
res_creation_input = {
|
init_new_res = initialize_resource(
|
||||||
"name": res_id,
|
{
|
||||||
"class": class_name,
|
"name": res_id,
|
||||||
"parent": parent,
|
"class": class_name,
|
||||||
"position": {
|
"parent": parent,
|
||||||
"x": bind_locations.x,
|
"position": {
|
||||||
"y": bind_locations.y,
|
"x": bind_locations.x,
|
||||||
"z": bind_locations.z,
|
"y": bind_locations.y,
|
||||||
},
|
"z": bind_locations.z,
|
||||||
}
|
},
|
||||||
if len(liquid_input_slot) and liquid_input_slot[0] == -1: # 目前container只逐个创建
|
}
|
||||||
res_creation_input.update({
|
) # flatten的格式
|
||||||
"data": {
|
|
||||||
"liquid_type": liquid_type[0] if liquid_type else None,
|
|
||||||
"liquid_volume": liquid_volume[0] if liquid_volume else None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
init_new_res = initialize_resource(res_creation_input) # flatten的格式
|
|
||||||
resources = init_new_res # initialize_resource已经返回list[dict]
|
resources = init_new_res # initialize_resource已经返回list[dict]
|
||||||
device_ids = [device_id]
|
device_ids = [device_id]
|
||||||
bind_parent_id = [parent]
|
bind_parent_id = [parent]
|
||||||
|
|||||||
Reference in New Issue
Block a user