cnc-4-science 0.8.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Acceleration Consortium
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,241 @@
1
+ Metadata-Version: 2.4
2
+ Name: cnc-4-science
3
+ Version: 0.8.0
4
+ Summary: Control library for Genmitsu CNC machines used as low-cost lab automation platforms (liquid handling, fraction collection, vision-based capping, etc.).
5
+ Author: Owen Melville, Kelvin Chow
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/AccelerationConsortium/cnc-4-science
8
+ Project-URL: Repository, https://github.com/AccelerationConsortium/cnc-4-science
9
+ Project-URL: Issues, https://github.com/AccelerationConsortium/cnc-4-science/issues
10
+ Project-URL: Changelog, https://github.com/AccelerationConsortium/cnc-4-science/blob/main/CHANGELOG.md
11
+ Keywords: cnc,lab-automation,self-driving-lab,liquid-handling,opentrons,grbl
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: pyyaml
25
+ Requires-Dist: pyserial
26
+ Requires-Dist: opentrons-shared-data
27
+ Dynamic: license-file
28
+
29
+ <h1> CNC MACHINE CODE </h1>
30
+
31
+ Authors: Owen Melville, Kelvin Chow
32
+
33
+ Last Updated: 2026-03-18
34
+
35
+ <h2> Overall description </h2>
36
+ This package can be used to control Genmitsu CNC machines. This is useful for accelerated discovery because you can put your tools onto the CNC machine.
37
+
38
+ Install from PyPI:
39
+
40
+ ```bash
41
+ pip install cnc-4-science
42
+ ```
43
+
44
+ Then import `cnc_machine_core` and use its methods to intuitively and seamlessly move the CNC machine with whatever scientific tools you want to incorporate. See `examples/liquid_handling/picus_pipette/` for a full worked example.
45
+
46
+ <h3>Basic Functions:</h3>
47
+
48
+ - Home CNC machine
49
+
50
+ - Move to absolute points (x,y,z)
51
+
52
+ - Move to locations defined in a structured way (Eg move to Vial Position 0)
53
+
54
+ - Control of the spindle output
55
+
56
+ - Handles all gcode and CNC communication so you don't have to
57
+
58
+ - Makes sure you don't move the CNC machine to a position it can't go
59
+
60
+ - Automatic alarm detection and recovery (re-homes if a limit switch is triggered)
61
+
62
+ - Orthogonal waypoint moves for collision avoidance between deck slots
63
+
64
+ <h3>API Reference</h3>
65
+
66
+ | Method | Description |
67
+ |---|---|
68
+ | `home()` | Homes the robot and parks at the origin |
69
+ | `origin()` | Moves the robot to the origin |
70
+ | `connect()` / `close()` | Open and close serial connection to the CNC |
71
+ | `move_to_point(x, y, z)` | Move to absolute coordinates |
72
+ | `move_to_point_safe(x, y, z)` | Raises Z to clearance first, moves XY, then lowers Z. Prevents collisions with labware |
73
+ | `move_to_point_safe_orthogonal(x, y, z, waypoint, axis_order)` | Moves one axis at a time through waypoints for collision avoidance. Axis orders: `yxy`, `xyx`, `xyxy`, `yxyx` |
74
+ | `move_to_location(location, index)` | Move to a named location at the given index |
75
+ | `spindle_on(speed)` | Turn on spindle at given RPM (M3) |
76
+ | `spindle_off()` | Turn off spindle (M5) |
77
+ | `is_alarm()` | Returns `True` if GRBL is in alarm state (e.g. limit switch triggered) |
78
+ | `recover_if_alarm()` | Checks for alarm and auto-homes to recover. Called internally before every move |
79
+
80
+ <h3>Deck and Labware</h3>
81
+
82
+ The `cnc_deck` module provides `Well`, `Labware`, and `Deck` objects for coordinate resolution:
83
+
84
+ ```python
85
+ from cnc_machine_core import Deck
86
+
87
+ deck = Deck() # standard 4-slot deck
88
+ plate = deck.load_labware("1", "labware/my_labware.json") # returns Labware
89
+
90
+ well = plate["A1"] # Well object
91
+ x, y, z = well.position() # absolute CNC coordinates
92
+ x, y, z = well.position(offset={"x": 6.75, "y": -4.0}) # with tool offset
93
+
94
+ for well in plate.wells(): # iterate in ordering
95
+ print(well.name, well.position())
96
+ ```
97
+
98
+ Alternative deck layouts are in `deck/` (pass by name or path):
99
+ - `cnc_4_slot_deck.json` — standard 4-slot (2×2) **[default]**
100
+ - `cnc_1_slot_deck.json` — single slot at origin (open deck, no labware required)
101
+
102
+ Labware definitions are created using the [Opentrons Labware Creator](https://labware.opentrons.com/#/create). Only the X and Y well coordinates from the Opentrons JSON are used. Z heights are defined per-protocol as calibrated constants, since Z depends on the specific tool and labware combination rather than the labware geometry alone.
103
+
104
+ Custom labware JSON files go in `labware/`. See the existing files there for reference.
105
+
106
+ <h3>Direct Positioning (No Labware)</h3>
107
+
108
+ For simpler setups that don't need labware definitions, use the open deck and move directly to absolute coordinates:
109
+
110
+ ```python
111
+ from cnc_machine_core import Deck
112
+
113
+ deck = Deck("cnc_1_slot_deck") # built-in name; or pass a path to custom JSON
114
+ # No labware needed — move to raw coordinates
115
+ cnc.move_to_point_safe(x=100, y=50, z=-20)
116
+ ```
117
+
118
+ Alternatively, position arrays can be defined in a YAML file and addressed by index using `move_to_location()`. This is useful for regular grids where you don't need named wells. Positions are defined in `location_status.yaml`:
119
+
120
+ ```yaml
121
+ vial_rack:
122
+ num_x: 2 # columns
123
+ num_y: 4 # rows
124
+ x_origin: 166.5 # first position X
125
+ y_origin: 125 # first position Y
126
+ z_origin: 0
127
+ x_offset: 36 # spacing between columns
128
+ y_offset: -36 # spacing between rows
129
+ ```
130
+
131
+ The location index moves through a full column before advancing to the next. Index 0 is at the origin.
132
+
133
+ <img width="1580" height="1190" alt="image" src="https://github.com/user-attachments/assets/2022a495-b026-4f38-a9e6-7f2ad14fdd05" />
134
+
135
+ <h3>Z Calibration Helper</h3>
136
+
137
+ A Z calibration script is included at `examples/liquid_handling/picus_pipette/z_helper.py`. It moves the CNC to a selected slot/well (with tool offset applied), then lets the user step Z up and down at three granularity levels (coarse, medium, fine) to find the correct working height. This is much faster than manually jogging and reading coordinates. Copy it into your own application and update the deck/labware/tool configuration for your setup.
138
+
139
+ <h3>Deck State</h3>
140
+
141
+ The `deck_state` module tracks per-well status across all deck slots with YAML persistence:
142
+
143
+ ```python
144
+ from cnc_machine_core import DeckState
145
+
146
+ ds = DeckState()
147
+ ds.init_wells_from_labware("1", plate) # from Labware object
148
+ ds.init_from_preset({"1": {"A1": "sample"}}) # override specific wells
149
+ ds.set_status("1", "A1", "processed") # update (auto-saves)
150
+ loc = ds.find_next(["1", "2"], "sample") # first match -> ("1", "A2")
151
+ ds.count(["1"], "processed") # count by status
152
+ ds.summary() # print slot breakdown
153
+ ```
154
+
155
+ Status strings are application-defined — use whatever makes sense for your workflow.
156
+ A sample preset is in `examples/liquid_handling/picus_pipette/deck_preset.yaml`.
157
+
158
+ <h3>Starting a New Application</h3>
159
+
160
+ After physically setting up the CNC machine, run `examples/hello_cnc/hardware_check.py` as a sanity check to verify the serial connection, homing, movement, and spindle all work correctly. Edit `examples/hello_cnc/cnc_config.yaml` to match your COM port and bounds before running:
161
+
162
+ ```bash
163
+ python examples/hello_cnc/hardware_check.py
164
+ ```
165
+
166
+ Once the hardware check passes, create your application from the starter example at `examples/liquid_handling/picus_pipette/` (a full worked example using a Sartorius Picus 2 pipette for serial dilution).
167
+
168
+ 1. **Copy the example** — copy `examples/liquid_handling/picus_pipette/` to a new repository or directory
169
+ 2. **Install cnc-4-science** — install as a dependency in your project's virtual environment:
170
+
171
+ **Linux / macOS / Raspberry Pi:**
172
+ ```bash
173
+ python3 -m venv .venv
174
+ source .venv/bin/activate
175
+ pip install cnc-4-science
176
+ ```
177
+
178
+ **Windows:**
179
+ ```powershell
180
+ python -m venv .venv
181
+ .\.venv\Scripts\Activate.ps1
182
+ pip install cnc-4-science
183
+ ```
184
+
185
+ Or for local editable development against an unreleased core:
186
+ ```bash
187
+ pip install -e path/to/cnc-machine
188
+ ```
189
+
190
+ 3. **Configure your CNC** — edit `tools/cnc_config.yaml` (COM port, baud, bounds). Then load it in your script with `CNC_Machine.from_config("tools/cnc_config.yaml")`
191
+ 4. **Add your labware** — place custom labware JSON files in `custom_labware/`, or load standard Opentrons labware via `opentrons_shared_data.labware.load_definition(...)`
192
+ 5. **Configure each tool** — create `tools/<tool>_config.yaml` per pipette/effector with COM port, mounting offset, Z heights, and any tool-specific parameters
193
+ 6. **Calibrate Z heights** — run `python z_helper.py` to find working Z for each tool + labware combo; copy results into the tool's `<tool>_config.yaml`
194
+ 7. **Validate** — set `virtual: true` in `tools/cnc_config.yaml` for a dry run, then on hardware
195
+ 8. **Implement tools** — use `tools/picus_pipette.py` as a pattern for wrapping new tools
196
+
197
+ <h4>Architecture</h4>
198
+
199
+ ```
200
+ cnc-4-science (library, on PyPI) Your Application (copied example)
201
+ ├── src/cnc_machine_core/ ├── protocols/
202
+ │ ├── cnc_machine.py (motion) │ └── serial_dilution_demo.py
203
+ │ ├── cnc_deck.py (deck/wells) ├── z_helper.py
204
+ │ ├── deck_state.py (state) ├── deck_preset.yaml
205
+ │ ├── deck/ (definitions) ├── custom_labware/
206
+ │ └── labware/ (labware JSON) ├── tools/
207
+ ├── examples/ │ ├── cnc_config.yaml (CNC + deck layout + Z heights)
208
+ │ ├── hello_cnc/ │ ├── picus_config.yaml (tool: port, offset, volumes)
209
+ │ └── liquid_handling/ │ ├── picus_pipette.py (tool wrapper)
210
+ └── pyproject.toml │ └── picus_driver.py (vendored low-level driver)
211
+ └── requirements.txt (`cnc-4-science`)
212
+ ```
213
+
214
+ - **Library** owns: machine control, deck/labware primitives, standard definitions
215
+ - **App** owns: concrete tool implementations, calibrated configs, workflow protocols
216
+
217
+ <h4>Tool Contract</h4>
218
+
219
+ Every tool class must follow this interface:
220
+
221
+ ```python
222
+ class MyTool:
223
+ def __init__(self, cnc_machine, tool_config):
224
+ self.cnc = cnc_machine
225
+ self.offset = tool_config.get("offset", {"x": 0, "y": 0, "z": 0})
226
+ # extract parameters from tool_config["parameters"]
227
+ ```
228
+
229
+ See `examples/liquid_handling/picus_pipette/tools/picus_pipette.py` for a working reference implementation.
230
+
231
+ <h3>Advice on Integration with Scientific Instruments</h3>
232
+
233
+ - Create a separate python file for each tool (camera, force sensor, syringe pump, etc.)
234
+
235
+ - Create an instrument class that imports cnc_machine along with the python files for each tool (eg fraction_collector.py)
236
+
237
+ - In your instrument class make methods that intuitively describe the general actions of your instrument (eg dispense_fraction)
238
+
239
+ - Make your workflows in seperate python files or Jupyter notebook files that create an instance of your instrument class
240
+
241
+ - This will make your workflows as clean and simple as possible while hard to mess up!
@@ -0,0 +1,213 @@
1
+ <h1> CNC MACHINE CODE </h1>
2
+
3
+ Authors: Owen Melville, Kelvin Chow
4
+
5
+ Last Updated: 2026-03-18
6
+
7
+ <h2> Overall description </h2>
8
+ This package can be used to control Genmitsu CNC machines. This is useful for accelerated discovery because you can put your tools onto the CNC machine.
9
+
10
+ Install from PyPI:
11
+
12
+ ```bash
13
+ pip install cnc-4-science
14
+ ```
15
+
16
+ Then import `cnc_machine_core` and use its methods to intuitively and seamlessly move the CNC machine with whatever scientific tools you want to incorporate. See `examples/liquid_handling/picus_pipette/` for a full worked example.
17
+
18
+ <h3>Basic Functions:</h3>
19
+
20
+ - Home CNC machine
21
+
22
+ - Move to absolute points (x,y,z)
23
+
24
+ - Move to locations defined in a structured way (Eg move to Vial Position 0)
25
+
26
+ - Control of the spindle output
27
+
28
+ - Handles all gcode and CNC communication so you don't have to
29
+
30
+ - Makes sure you don't move the CNC machine to a position it can't go
31
+
32
+ - Automatic alarm detection and recovery (re-homes if a limit switch is triggered)
33
+
34
+ - Orthogonal waypoint moves for collision avoidance between deck slots
35
+
36
+ <h3>API Reference</h3>
37
+
38
+ | Method | Description |
39
+ |---|---|
40
+ | `home()` | Homes the robot and parks at the origin |
41
+ | `origin()` | Moves the robot to the origin |
42
+ | `connect()` / `close()` | Open and close serial connection to the CNC |
43
+ | `move_to_point(x, y, z)` | Move to absolute coordinates |
44
+ | `move_to_point_safe(x, y, z)` | Raises Z to clearance first, moves XY, then lowers Z. Prevents collisions with labware |
45
+ | `move_to_point_safe_orthogonal(x, y, z, waypoint, axis_order)` | Moves one axis at a time through waypoints for collision avoidance. Axis orders: `yxy`, `xyx`, `xyxy`, `yxyx` |
46
+ | `move_to_location(location, index)` | Move to a named location at the given index |
47
+ | `spindle_on(speed)` | Turn on spindle at given RPM (M3) |
48
+ | `spindle_off()` | Turn off spindle (M5) |
49
+ | `is_alarm()` | Returns `True` if GRBL is in alarm state (e.g. limit switch triggered) |
50
+ | `recover_if_alarm()` | Checks for alarm and auto-homes to recover. Called internally before every move |
51
+
52
+ <h3>Deck and Labware</h3>
53
+
54
+ The `cnc_deck` module provides `Well`, `Labware`, and `Deck` objects for coordinate resolution:
55
+
56
+ ```python
57
+ from cnc_machine_core import Deck
58
+
59
+ deck = Deck() # standard 4-slot deck
60
+ plate = deck.load_labware("1", "labware/my_labware.json") # returns Labware
61
+
62
+ well = plate["A1"] # Well object
63
+ x, y, z = well.position() # absolute CNC coordinates
64
+ x, y, z = well.position(offset={"x": 6.75, "y": -4.0}) # with tool offset
65
+
66
+ for well in plate.wells(): # iterate in ordering
67
+ print(well.name, well.position())
68
+ ```
69
+
70
+ Alternative deck layouts are in `deck/` (pass by name or path):
71
+ - `cnc_4_slot_deck.json` — standard 4-slot (2×2) **[default]**
72
+ - `cnc_1_slot_deck.json` — single slot at origin (open deck, no labware required)
73
+
74
+ Labware definitions are created using the [Opentrons Labware Creator](https://labware.opentrons.com/#/create). Only the X and Y well coordinates from the Opentrons JSON are used. Z heights are defined per-protocol as calibrated constants, since Z depends on the specific tool and labware combination rather than the labware geometry alone.
75
+
76
+ Custom labware JSON files go in `labware/`. See the existing files there for reference.
77
+
78
+ <h3>Direct Positioning (No Labware)</h3>
79
+
80
+ For simpler setups that don't need labware definitions, use the open deck and move directly to absolute coordinates:
81
+
82
+ ```python
83
+ from cnc_machine_core import Deck
84
+
85
+ deck = Deck("cnc_1_slot_deck") # built-in name; or pass a path to custom JSON
86
+ # No labware needed — move to raw coordinates
87
+ cnc.move_to_point_safe(x=100, y=50, z=-20)
88
+ ```
89
+
90
+ Alternatively, position arrays can be defined in a YAML file and addressed by index using `move_to_location()`. This is useful for regular grids where you don't need named wells. Positions are defined in `location_status.yaml`:
91
+
92
+ ```yaml
93
+ vial_rack:
94
+ num_x: 2 # columns
95
+ num_y: 4 # rows
96
+ x_origin: 166.5 # first position X
97
+ y_origin: 125 # first position Y
98
+ z_origin: 0
99
+ x_offset: 36 # spacing between columns
100
+ y_offset: -36 # spacing between rows
101
+ ```
102
+
103
+ The location index moves through a full column before advancing to the next. Index 0 is at the origin.
104
+
105
+ <img width="1580" height="1190" alt="image" src="https://github.com/user-attachments/assets/2022a495-b026-4f38-a9e6-7f2ad14fdd05" />
106
+
107
+ <h3>Z Calibration Helper</h3>
108
+
109
+ A Z calibration script is included at `examples/liquid_handling/picus_pipette/z_helper.py`. It moves the CNC to a selected slot/well (with tool offset applied), then lets the user step Z up and down at three granularity levels (coarse, medium, fine) to find the correct working height. This is much faster than manually jogging and reading coordinates. Copy it into your own application and update the deck/labware/tool configuration for your setup.
110
+
111
+ <h3>Deck State</h3>
112
+
113
+ The `deck_state` module tracks per-well status across all deck slots with YAML persistence:
114
+
115
+ ```python
116
+ from cnc_machine_core import DeckState
117
+
118
+ ds = DeckState()
119
+ ds.init_wells_from_labware("1", plate) # from Labware object
120
+ ds.init_from_preset({"1": {"A1": "sample"}}) # override specific wells
121
+ ds.set_status("1", "A1", "processed") # update (auto-saves)
122
+ loc = ds.find_next(["1", "2"], "sample") # first match -> ("1", "A2")
123
+ ds.count(["1"], "processed") # count by status
124
+ ds.summary() # print slot breakdown
125
+ ```
126
+
127
+ Status strings are application-defined — use whatever makes sense for your workflow.
128
+ A sample preset is in `examples/liquid_handling/picus_pipette/deck_preset.yaml`.
129
+
130
+ <h3>Starting a New Application</h3>
131
+
132
+ After physically setting up the CNC machine, run `examples/hello_cnc/hardware_check.py` as a sanity check to verify the serial connection, homing, movement, and spindle all work correctly. Edit `examples/hello_cnc/cnc_config.yaml` to match your COM port and bounds before running:
133
+
134
+ ```bash
135
+ python examples/hello_cnc/hardware_check.py
136
+ ```
137
+
138
+ Once the hardware check passes, create your application from the starter example at `examples/liquid_handling/picus_pipette/` (a full worked example using a Sartorius Picus 2 pipette for serial dilution).
139
+
140
+ 1. **Copy the example** — copy `examples/liquid_handling/picus_pipette/` to a new repository or directory
141
+ 2. **Install cnc-4-science** — install as a dependency in your project's virtual environment:
142
+
143
+ **Linux / macOS / Raspberry Pi:**
144
+ ```bash
145
+ python3 -m venv .venv
146
+ source .venv/bin/activate
147
+ pip install cnc-4-science
148
+ ```
149
+
150
+ **Windows:**
151
+ ```powershell
152
+ python -m venv .venv
153
+ .\.venv\Scripts\Activate.ps1
154
+ pip install cnc-4-science
155
+ ```
156
+
157
+ Or for local editable development against an unreleased core:
158
+ ```bash
159
+ pip install -e path/to/cnc-machine
160
+ ```
161
+
162
+ 3. **Configure your CNC** — edit `tools/cnc_config.yaml` (COM port, baud, bounds). Then load it in your script with `CNC_Machine.from_config("tools/cnc_config.yaml")`
163
+ 4. **Add your labware** — place custom labware JSON files in `custom_labware/`, or load standard Opentrons labware via `opentrons_shared_data.labware.load_definition(...)`
164
+ 5. **Configure each tool** — create `tools/<tool>_config.yaml` per pipette/effector with COM port, mounting offset, Z heights, and any tool-specific parameters
165
+ 6. **Calibrate Z heights** — run `python z_helper.py` to find working Z for each tool + labware combo; copy results into the tool's `<tool>_config.yaml`
166
+ 7. **Validate** — set `virtual: true` in `tools/cnc_config.yaml` for a dry run, then on hardware
167
+ 8. **Implement tools** — use `tools/picus_pipette.py` as a pattern for wrapping new tools
168
+
169
+ <h4>Architecture</h4>
170
+
171
+ ```
172
+ cnc-4-science (library, on PyPI) Your Application (copied example)
173
+ ├── src/cnc_machine_core/ ├── protocols/
174
+ │ ├── cnc_machine.py (motion) │ └── serial_dilution_demo.py
175
+ │ ├── cnc_deck.py (deck/wells) ├── z_helper.py
176
+ │ ├── deck_state.py (state) ├── deck_preset.yaml
177
+ │ ├── deck/ (definitions) ├── custom_labware/
178
+ │ └── labware/ (labware JSON) ├── tools/
179
+ ├── examples/ │ ├── cnc_config.yaml (CNC + deck layout + Z heights)
180
+ │ ├── hello_cnc/ │ ├── picus_config.yaml (tool: port, offset, volumes)
181
+ │ └── liquid_handling/ │ ├── picus_pipette.py (tool wrapper)
182
+ └── pyproject.toml │ └── picus_driver.py (vendored low-level driver)
183
+ └── requirements.txt (`cnc-4-science`)
184
+ ```
185
+
186
+ - **Library** owns: machine control, deck/labware primitives, standard definitions
187
+ - **App** owns: concrete tool implementations, calibrated configs, workflow protocols
188
+
189
+ <h4>Tool Contract</h4>
190
+
191
+ Every tool class must follow this interface:
192
+
193
+ ```python
194
+ class MyTool:
195
+ def __init__(self, cnc_machine, tool_config):
196
+ self.cnc = cnc_machine
197
+ self.offset = tool_config.get("offset", {"x": 0, "y": 0, "z": 0})
198
+ # extract parameters from tool_config["parameters"]
199
+ ```
200
+
201
+ See `examples/liquid_handling/picus_pipette/tools/picus_pipette.py` for a working reference implementation.
202
+
203
+ <h3>Advice on Integration with Scientific Instruments</h3>
204
+
205
+ - Create a separate python file for each tool (camera, force sensor, syringe pump, etc.)
206
+
207
+ - Create an instrument class that imports cnc_machine along with the python files for each tool (eg fraction_collector.py)
208
+
209
+ - In your instrument class make methods that intuitively describe the general actions of your instrument (eg dispense_fraction)
210
+
211
+ - Make your workflows in seperate python files or Jupyter notebook files that create an instance of your instrument class
212
+
213
+ - This will make your workflows as clean and simple as possible while hard to mess up!
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cnc-4-science"
7
+ version = "0.8.0"
8
+ description = "Control library for Genmitsu CNC machines used as low-cost lab automation platforms (liquid handling, fraction collection, vision-based capping, etc.)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ { name = "Owen Melville" },
15
+ { name = "Kelvin Chow" },
16
+ ]
17
+ keywords = ["cnc", "lab-automation", "self-driving-lab", "liquid-handling", "opentrons", "grbl"]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Intended Audience :: Science/Research",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Topic :: Scientific/Engineering",
28
+ ]
29
+ dependencies = [
30
+ "pyyaml",
31
+ "pyserial",
32
+ "opentrons-shared-data",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/AccelerationConsortium/cnc-4-science"
37
+ Repository = "https://github.com/AccelerationConsortium/cnc-4-science"
38
+ Issues = "https://github.com/AccelerationConsortium/cnc-4-science/issues"
39
+ Changelog = "https://github.com/AccelerationConsortium/cnc-4-science/blob/main/CHANGELOG.md"
40
+
41
+ [tool.setuptools]
42
+ package-dir = {"" = "src"}
43
+ packages = ["cnc_machine_core", "cnc_machine_core.deck", "cnc_machine_core.labware"]
44
+
45
+ [tool.setuptools.package-data]
46
+ "cnc_machine_core.deck" = ["*.json"]
47
+ "cnc_machine_core.labware" = ["*.json"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+