puda-drivers 0.0.11__py3-none-any.whl → 0.0.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- puda_drivers/machines/first.py +115 -7
- {puda_drivers-0.0.11.dist-info → puda_drivers-0.0.12.dist-info}/METADATA +9 -14
- {puda_drivers-0.0.11.dist-info → puda_drivers-0.0.12.dist-info}/RECORD +5 -5
- {puda_drivers-0.0.11.dist-info → puda_drivers-0.0.12.dist-info}/WHEEL +0 -0
- {puda_drivers-0.0.11.dist-info → puda_drivers-0.0.12.dist-info}/licenses/LICENSE +0 -0
puda_drivers/machines/first.py
CHANGED
|
@@ -9,7 +9,9 @@ This class demonstrates the integration of:
|
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
11
|
import time
|
|
12
|
+
from pathlib import Path
|
|
12
13
|
from typing import Optional, Dict, Tuple, Type, Union
|
|
14
|
+
import numpy as np
|
|
13
15
|
from puda_drivers.move import GCodeController, Deck
|
|
14
16
|
from puda_drivers.core import Position
|
|
15
17
|
from puda_drivers.transfer.liquid.sartorius import SartoriusController
|
|
@@ -118,21 +120,44 @@ class First:
|
|
|
118
120
|
camera_index if camera_index is not None else self.DEFAULT_CAMERA_INDEX,
|
|
119
121
|
)
|
|
120
122
|
|
|
121
|
-
def
|
|
122
|
-
"""
|
|
123
|
-
|
|
123
|
+
def startup(self):
|
|
124
|
+
"""
|
|
125
|
+
Start up the machine by connecting all controllers and initializing subsystems.
|
|
126
|
+
|
|
127
|
+
This method:
|
|
128
|
+
- Connects to all controllers (gantry, pipette, camera)
|
|
129
|
+
- Homes the gantry to establish a known position
|
|
130
|
+
- Initializes the pipette to reset it to a known state
|
|
131
|
+
|
|
132
|
+
The machine is ready for operations after this method completes.
|
|
133
|
+
"""
|
|
134
|
+
self._logger.info("Starting up machine and connecting all controllers")
|
|
124
135
|
self.qubot.connect()
|
|
125
136
|
self.pipette.connect()
|
|
126
137
|
self.camera.connect()
|
|
127
138
|
self._logger.info("All controllers connected successfully")
|
|
128
139
|
|
|
129
|
-
|
|
130
|
-
"
|
|
131
|
-
self.
|
|
140
|
+
# Home the gantry to establish known position
|
|
141
|
+
self._logger.info("Homing gantry...")
|
|
142
|
+
self.qubot.home()
|
|
143
|
+
|
|
144
|
+
# Initialize the pipette (all pipette operations need to wait 5 seconds for completion)
|
|
145
|
+
self._logger.info("Initializing pipette...")
|
|
146
|
+
self.pipette.initialize()
|
|
147
|
+
time.sleep(5)
|
|
148
|
+
self._logger.info("Machine startup complete - ready for operations")
|
|
149
|
+
|
|
150
|
+
def shutdown(self):
|
|
151
|
+
"""
|
|
152
|
+
Gracefully shut down the machine by disconnecting all controllers.
|
|
153
|
+
|
|
154
|
+
This method ensures all connections are properly closed and resources are released.
|
|
155
|
+
"""
|
|
156
|
+
self._logger.info("Shutting down machine and disconnecting all controllers")
|
|
132
157
|
self.qubot.disconnect()
|
|
133
158
|
self.pipette.disconnect()
|
|
134
159
|
self.camera.disconnect()
|
|
135
|
-
self._logger.info("
|
|
160
|
+
self._logger.info("Machine shutdown complete")
|
|
136
161
|
|
|
137
162
|
def load_labware(self, slot: str, labware_name: str):
|
|
138
163
|
"""Load a labware object into a slot."""
|
|
@@ -350,3 +375,86 @@ class First:
|
|
|
350
375
|
else:
|
|
351
376
|
self._logger.debug("Absolute A position for slot '%s': %s", slot, pos)
|
|
352
377
|
return pos
|
|
378
|
+
|
|
379
|
+
def start_video_recording(
|
|
380
|
+
self,
|
|
381
|
+
filename: Optional[Union[str, Path]] = None,
|
|
382
|
+
fps: Optional[float] = None
|
|
383
|
+
) -> Path:
|
|
384
|
+
"""
|
|
385
|
+
Start recording a video.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
filename: Optional filename for the video. If not provided, a timestamped
|
|
389
|
+
filename will be generated. If provided without extension, .mp4 will be added.
|
|
390
|
+
fps: Optional frames per second for the video. Defaults to 30.0 if not specified.
|
|
391
|
+
|
|
392
|
+
Returns:
|
|
393
|
+
Path to the video file where recording is being saved
|
|
394
|
+
|
|
395
|
+
Raises:
|
|
396
|
+
IOError: If camera is not connected or recording fails to start
|
|
397
|
+
ValueError: If already recording
|
|
398
|
+
"""
|
|
399
|
+
return self.camera.start_video_recording(filename=filename, fps=fps)
|
|
400
|
+
|
|
401
|
+
def stop_video_recording(self) -> Optional[Path]:
|
|
402
|
+
"""
|
|
403
|
+
Stop recording a video.
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
Path to the saved video file, or None if no recording was in progress
|
|
407
|
+
|
|
408
|
+
Raises:
|
|
409
|
+
IOError: If video writer fails to release
|
|
410
|
+
"""
|
|
411
|
+
return self.camera.stop_video_recording()
|
|
412
|
+
|
|
413
|
+
def record_video(
|
|
414
|
+
self,
|
|
415
|
+
duration_seconds: float,
|
|
416
|
+
filename: Optional[Union[str, Path]] = None,
|
|
417
|
+
fps: Optional[float] = None
|
|
418
|
+
) -> Path:
|
|
419
|
+
"""
|
|
420
|
+
Record a video for a specified duration.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
duration_seconds: Duration of the video in seconds
|
|
424
|
+
filename: Optional filename for the video. If not provided, a timestamped
|
|
425
|
+
filename will be generated. If provided without extension, .mp4 will be added.
|
|
426
|
+
fps: Optional frames per second for the video. Defaults to 30.0 if not specified.
|
|
427
|
+
|
|
428
|
+
Returns:
|
|
429
|
+
Path to the saved video file
|
|
430
|
+
|
|
431
|
+
Raises:
|
|
432
|
+
IOError: If camera is not connected or recording fails
|
|
433
|
+
"""
|
|
434
|
+
return self.camera.record_video(
|
|
435
|
+
duration_seconds=duration_seconds,
|
|
436
|
+
filename=filename,
|
|
437
|
+
fps=fps
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
def capture_image(
|
|
441
|
+
self,
|
|
442
|
+
save: bool = False,
|
|
443
|
+
filename: Optional[Union[str, Path]] = None
|
|
444
|
+
) -> np.ndarray:
|
|
445
|
+
"""
|
|
446
|
+
Capture a single image from the camera.
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
save: If True, save the image to the captures folder
|
|
450
|
+
filename: Optional filename for the saved image. If not provided and save=True,
|
|
451
|
+
a timestamped filename will be generated. If provided without extension,
|
|
452
|
+
.jpg will be added.
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
Captured image as a numpy array (BGR format)
|
|
456
|
+
|
|
457
|
+
Raises:
|
|
458
|
+
IOError: If camera is not connected or capture fails
|
|
459
|
+
"""
|
|
460
|
+
return self.camera.capture_image(save=save, filename=filename)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: puda-drivers
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.12
|
|
4
4
|
Summary: Hardware drivers for the PUDA platform.
|
|
5
5
|
Project-URL: Homepage, https://github.com/zhao-bears/puda-drivers
|
|
6
6
|
Project-URL: Issues, https://github.com/zhao-bears/puda-drivers/issues
|
|
@@ -85,6 +85,7 @@ When file logging is enabled, logs are saved to timestamped files (unless a cust
|
|
|
85
85
|
The `First` machine integrates motion control, deck management, liquid handling, and camera capabilities:
|
|
86
86
|
|
|
87
87
|
```python
|
|
88
|
+
import time
|
|
88
89
|
import logging
|
|
89
90
|
from puda_drivers.machines import First
|
|
90
91
|
from puda_drivers.core.logging import setup_logging
|
|
@@ -102,14 +103,8 @@ machine = First(
|
|
|
102
103
|
camera_index=0,
|
|
103
104
|
)
|
|
104
105
|
|
|
105
|
-
#
|
|
106
|
-
machine.
|
|
107
|
-
|
|
108
|
-
# Home the gantry
|
|
109
|
-
machine.qubot.home()
|
|
110
|
-
|
|
111
|
-
# Initialize the pipette
|
|
112
|
-
machine.pipette.initialize()
|
|
106
|
+
# Start up the machine (connects all controllers, homes gantry, and initializes pipette)
|
|
107
|
+
machine.startup()
|
|
113
108
|
|
|
114
109
|
# Load labware onto the deck
|
|
115
110
|
machine.load_deck({
|
|
@@ -119,19 +114,19 @@ machine.load_deck({
|
|
|
119
114
|
})
|
|
120
115
|
|
|
121
116
|
# Start video recording
|
|
122
|
-
machine.
|
|
117
|
+
machine.start_video_recording()
|
|
123
118
|
|
|
124
119
|
# Perform liquid handling operations
|
|
125
120
|
machine.attach_tip(slot="A3", well="G8")
|
|
126
121
|
machine.aspirate_from(slot="C2", well="A1", amount=100, height_from_bottom=10.0)
|
|
127
122
|
machine.dispense_to(slot="C2", well="B4", amount=100, height_from_bottom=30.0)
|
|
128
|
-
machine.drop_tip(slot="C1", well="A1")
|
|
123
|
+
machine.drop_tip(slot="C1", well="A1", height_from_bottom=10)
|
|
129
124
|
|
|
130
125
|
# Stop video recording
|
|
131
|
-
machine.
|
|
126
|
+
machine.stop_video_recording()
|
|
132
127
|
|
|
133
|
-
#
|
|
134
|
-
machine.
|
|
128
|
+
# Shutdown the machine (gracefully disconnects all controllers)
|
|
129
|
+
machine.shutdown()
|
|
135
130
|
```
|
|
136
131
|
|
|
137
132
|
**Discovering Available Methods**: To explore what methods are available on any class instance, you can use Python's built-in `help()` function:
|
|
@@ -12,7 +12,7 @@ puda_drivers/labware/opentrons_96_tiprack_300ul.json,sha256=jmNaworu688GEgFdxMxN
|
|
|
12
12
|
puda_drivers/labware/polyelectric_8_wellplate_30000ul.json,sha256=esu2tej0ORs7Pfd4HwoQVUpU5mPvp2AYzE3zsCC2FDk,3104
|
|
13
13
|
puda_drivers/labware/trash_bin.json,sha256=Hk4MXO48P28jG7F87DUd9Ja4c_P7kAy3karPQ965i9Y,580
|
|
14
14
|
puda_drivers/machines/__init__.py,sha256=zmIk_r2T8nbPA68h3Cko8N6oL7ncoBpmvhNcAqzHmc4,45
|
|
15
|
-
puda_drivers/machines/first.py,sha256=
|
|
15
|
+
puda_drivers/machines/first.py,sha256=yk_Kh9f_yjSlRHjYEOzvrMxADBvlTH0AIV1VLvm2sp8,18339
|
|
16
16
|
puda_drivers/move/__init__.py,sha256=NKIKckcqgyviPM0EGFcmIoaqkJM4qekR4babfdddRzM,96
|
|
17
17
|
puda_drivers/move/deck.py,sha256=yq2B4WMqj0hQvHt8HoJskP10u1DUyKwUnjP2c9gJ174,1397
|
|
18
18
|
puda_drivers/move/gcode.py,sha256=Aw7la4RkPw737hW5sKl6WiPCmmTnsjLvG4mOb-RwVSc,22592
|
|
@@ -23,7 +23,7 @@ puda_drivers/transfer/liquid/sartorius/__init__.py,sha256=QGpKz5YUwa8xCdSMXeZ0iR
|
|
|
23
23
|
puda_drivers/transfer/liquid/sartorius/api.py,sha256=jxwIJmY2k1K2ts6NC2ZgFTe4MOiH8TGnJeqYOqNa3rE,28250
|
|
24
24
|
puda_drivers/transfer/liquid/sartorius/constants.py,sha256=mcsjLrVBH-RSodH-pszstwcEL9wwbV0vOgHbGNxZz9w,2770
|
|
25
25
|
puda_drivers/transfer/liquid/sartorius/sartorius.py,sha256=bW838jYOAfLlbUqtsKRipZ-RLjrNTcZ7riYV6I4w8G8,13728
|
|
26
|
-
puda_drivers-0.0.
|
|
27
|
-
puda_drivers-0.0.
|
|
28
|
-
puda_drivers-0.0.
|
|
29
|
-
puda_drivers-0.0.
|
|
26
|
+
puda_drivers-0.0.12.dist-info/METADATA,sha256=saXg221vJnpqzC4t6Cn7Kcc1ZX0WPBLQkclr_vFaRgQ,7071
|
|
27
|
+
puda_drivers-0.0.12.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
28
|
+
puda_drivers-0.0.12.dist-info/licenses/LICENSE,sha256=7EI8xVBu6h_7_JlVw-yPhhOZlpY9hP8wal7kHtqKT_E,1074
|
|
29
|
+
puda_drivers-0.0.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|