py3dcal 1.0.4__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.

Potentially problematic release.


This version of py3dcal might be problematic. Click here for more details.

Files changed (46) hide show
  1. py3dcal-1.0.4/LICENSE +21 -0
  2. py3dcal-1.0.4/MANIFEST.in +1 -0
  3. py3dcal-1.0.4/PKG-INFO +16 -0
  4. py3dcal-1.0.4/README.md +1 -0
  5. py3dcal-1.0.4/py3DCal/__init__.py +14 -0
  6. py3dcal-1.0.4/py3DCal/data_collection/Calibrator.py +298 -0
  7. py3dcal-1.0.4/py3DCal/data_collection/Printers/Ender3/Ender3.py +82 -0
  8. py3dcal-1.0.4/py3DCal/data_collection/Printers/Ender3/__init__.py +0 -0
  9. py3dcal-1.0.4/py3DCal/data_collection/Printers/Printer.py +63 -0
  10. py3dcal-1.0.4/py3DCal/data_collection/Printers/__init__.py +0 -0
  11. py3dcal-1.0.4/py3DCal/data_collection/Sensors/DIGIT/DIGIT.py +47 -0
  12. py3dcal-1.0.4/py3DCal/data_collection/Sensors/DIGIT/__init__.py +0 -0
  13. py3dcal-1.0.4/py3DCal/data_collection/Sensors/DIGIT/default.csv +1222 -0
  14. py3dcal-1.0.4/py3DCal/data_collection/Sensors/GelsightMini/GelsightMini.py +45 -0
  15. py3dcal-1.0.4/py3DCal/data_collection/Sensors/GelsightMini/__init__.py +0 -0
  16. py3dcal-1.0.4/py3DCal/data_collection/Sensors/GelsightMini/default.csv +1210 -0
  17. py3dcal-1.0.4/py3DCal/data_collection/Sensors/Sensor.py +35 -0
  18. py3dcal-1.0.4/py3DCal/data_collection/Sensors/__init__.py +0 -0
  19. py3dcal-1.0.4/py3DCal/data_collection/__init__.py +0 -0
  20. py3dcal-1.0.4/py3DCal/model_training/__init__.py +0 -0
  21. py3dcal-1.0.4/py3DCal/model_training/datasets/DIGIT_dataset.py +77 -0
  22. py3dcal-1.0.4/py3DCal/model_training/datasets/GelSightMini_dataset.py +75 -0
  23. py3dcal-1.0.4/py3DCal/model_training/datasets/__init__.py +3 -0
  24. py3dcal-1.0.4/py3DCal/model_training/datasets/split_dataset.py +38 -0
  25. py3dcal-1.0.4/py3DCal/model_training/datasets/tactile_sensor_dataset.py +83 -0
  26. py3dcal-1.0.4/py3DCal/model_training/lib/__init__.py +0 -0
  27. py3dcal-1.0.4/py3DCal/model_training/lib/add_coordinate_embeddings.py +29 -0
  28. py3dcal-1.0.4/py3DCal/model_training/lib/annotate_dataset.py +422 -0
  29. py3dcal-1.0.4/py3DCal/model_training/lib/depthmaps.py +82 -0
  30. py3dcal-1.0.4/py3DCal/model_training/lib/fast_poisson.py +51 -0
  31. py3dcal-1.0.4/py3DCal/model_training/lib/get_gradient_map.py +39 -0
  32. py3dcal-1.0.4/py3DCal/model_training/lib/precompute_gradients.py +61 -0
  33. py3dcal-1.0.4/py3DCal/model_training/lib/train_model.py +96 -0
  34. py3dcal-1.0.4/py3DCal/model_training/lib/validate_parameters.py +87 -0
  35. py3dcal-1.0.4/py3DCal/model_training/models/__init__.py +1 -0
  36. py3dcal-1.0.4/py3DCal/model_training/models/touchnet.py +211 -0
  37. py3dcal-1.0.4/py3DCal/utils/__init__.py +0 -0
  38. py3dcal-1.0.4/py3DCal/utils/utils.py +32 -0
  39. py3dcal-1.0.4/py3DCal.egg-info/PKG-INFO +16 -0
  40. py3dcal-1.0.4/py3DCal.egg-info/SOURCES.txt +62 -0
  41. py3dcal-1.0.4/py3DCal.egg-info/dependency_links.txt +1 -0
  42. py3dcal-1.0.4/py3DCal.egg-info/entry_points.txt +3 -0
  43. py3dcal-1.0.4/py3DCal.egg-info/requires.txt +13 -0
  44. py3dcal-1.0.4/py3DCal.egg-info/top_level.txt +1 -0
  45. py3dcal-1.0.4/setup.cfg +4 -0
  46. py3dcal-1.0.4/setup.py +41 -0
py3dcal-1.0.4/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Rohan Kota
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 @@
1
+ recursive-include py3DCal/data_collection *.csv
py3dcal-1.0.4/PKG-INFO ADDED
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.1
2
+ Name: py3dcal
3
+ Version: 1.0.4
4
+ Summary: UNKNOWN
5
+ Home-page: https://github.com/rohankotanu/py3DCal
6
+ Author: Rohan Kota
7
+ Author-email: rohankota2026@u.northwestern.edu
8
+ License: MIT
9
+ Platform: UNKNOWN
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+
15
+ # For instructions on how to use this library, please visit https://rohankotanu.github.io/3DCal/
16
+
@@ -0,0 +1 @@
1
+ # For instructions on how to use this library, please visit https://rohankotanu.github.io/3DCal/
@@ -0,0 +1,14 @@
1
+ from .data_collection.Calibrator import Calibrator
2
+ from .data_collection.printers.Printer import Printer
3
+ from .data_collection.printers.Ender3.Ender3 import Ender3
4
+ from .data_collection.sensors.Sensor import Sensor
5
+ from .data_collection.sensors.DIGIT.DIGIT import DIGIT
6
+ from .data_collection.sensors.GelsightMini.GelsightMini import GelsightMini
7
+ from .model_training import datasets, models
8
+ from .model_training.datasets.split_dataset import split_dataset
9
+ from .model_training.models.touchnet import SensorType
10
+ from .model_training.lib.annotate_dataset import annotate
11
+ from .model_training.lib.train_model import train_model
12
+ from .model_training.lib.depthmaps import get_depthmap, save_2d_depthmap, show_2d_depthmap
13
+ from .model_training.lib.fast_poisson import fast_poisson
14
+ from .utils.utils import list_com_ports
@@ -0,0 +1,298 @@
1
+ import numpy as np
2
+ import time
3
+ import csv
4
+ import os
5
+ from typing import Union
6
+ from pathlib import Path
7
+ from PIL import Image
8
+ from tqdm import tqdm
9
+
10
+ from .printers.Printer import Printer
11
+ from .sensors.Sensor import Sensor
12
+
13
+ class Calibrator:
14
+ """ Calibrator class to automatically probe a tactile sensor.
15
+ Args:
16
+ printer (Printer): An instance of a Printer class.
17
+ sensor (Sensor): An instance of a Sensor class.
18
+ """
19
+ def __init__(self, printer: Printer, sensor: Sensor):
20
+ self.printer = printer
21
+ self.sensor = sensor
22
+
23
+ self.printer_connected = False
24
+ self.sensor_connected = False
25
+
26
+ try:
27
+ self.printer_name = self.printer.name
28
+ except:
29
+ self.printer_name = "printer"
30
+ try:
31
+ self.sensor_name = self.sensor.name
32
+ except:
33
+ self.sensor_name = "tactile"
34
+
35
+ def connect_printer(self):
36
+ """ Connects to the 3D Printer
37
+
38
+ Returns:
39
+ bool: Returns True if connection was successful.
40
+ """
41
+ print("Connecting to " + str(self.printer_name) + "...")
42
+
43
+ try:
44
+ self.printer.connect()
45
+ self.printer_connected = True
46
+
47
+ print("Connected to " + str(self.printer_name) + "!")
48
+ print("")
49
+ return True
50
+ except:
51
+ self.printer_connected = False
52
+ print("Error connecting to " + str(self.printer_name) + ".")
53
+ print("")
54
+ return False
55
+
56
+ def disconnect_printer(self):
57
+ """ Disconnects from the 3D Printer
58
+
59
+ Returns:
60
+ bool: Returns True if disconnection was successful.
61
+ """
62
+ print("Disconnecting from " + str(self.printer_name) + "...")
63
+
64
+ try:
65
+ self.printer.disconnect()
66
+ self.printer_connected = False
67
+ print("Disconnected from " + str(self.printer_name) + "!")
68
+ print("")
69
+ return True
70
+ except:
71
+ print("Error disconnecting from " + str(self.printer_name) + ".")
72
+ print("")
73
+ return False
74
+
75
+ def initialize_printer(self):
76
+ """ Sends gcode to configure and home 3D Printer
77
+
78
+ Returns:
79
+ bool: Returns True if initialization was successful.
80
+ """
81
+ # Probe must be detached to home printer
82
+ print("Make sure probe is not attached to print head. ", end="")
83
+ input("Press Enter to continue...")
84
+ print("")
85
+
86
+ if not self.printer_connected:
87
+ self.connect_printer()
88
+
89
+ try:
90
+ print("Initializing printer...")
91
+
92
+ self.printer.initialize()
93
+
94
+ print("Printer initialization complete!")
95
+ print("")
96
+ return True
97
+ except:
98
+ print("Error sending initialization gcode to printer.")
99
+ print("")
100
+ return False
101
+
102
+ def connect_sensor(self):
103
+ """ Connects to the sensor
104
+
105
+ Returns:
106
+ bool: Returns True if connection was successful.
107
+ """
108
+ print("Connecting to " + self.sensor_name + " sensor...")
109
+
110
+ try:
111
+ # Connect to sensor
112
+ self.sensor.connect()
113
+ print("Connected to sensor!")
114
+ print("")
115
+ except:
116
+ print("Error connecting to sensor.")
117
+ print("")
118
+
119
+ def disconnect_sensor(self):
120
+ """ Disconnects from the sensor
121
+
122
+ Returns:
123
+ bool: Returns True if disconnection was successful.
124
+ """
125
+ print("Disconnecting from " + self.sensor.name + " sensor...")
126
+
127
+ self.sensor.connect()
128
+ try:
129
+ self.printer.disconnect()
130
+ self.printer_connected = False
131
+ print("Disconnected from sensor!")
132
+ print("")
133
+ return True
134
+ except:
135
+ print("Error disconnecting from sensor.")
136
+ print("")
137
+ return False
138
+
139
+ def probe(self, home_printer: bool = True, save_images: bool = True, calibration_file_path: Union[str, Path] = None, data_save_path: str = "."):
140
+ """ Executes the probing procedure on 3D printer
141
+
142
+ Args:
143
+ home_printer (bool, optional): Determines whether to home the printer prior to probing. Defaults to True.
144
+ save_images (bool, optional): Determines whether sensor images are saved. Defaults to True.
145
+ calibration_file_path (str, optional): The path of the calibration file. For the DIGIT and GelSight Mini,
146
+ if no file is specified, a default calibration file will be used.
147
+ data_save_path (str, optional): The folder in which the data should be saved. If no folder is specified,
148
+ data will be stored in a directory named "sensor_calibration_data" within the current working directory.
149
+
150
+ Returns:
151
+ bool: Returns True when the probing procedure is complete.
152
+ """
153
+ # Connect to 3D printer if not already connected
154
+ if not self.printer_connected:
155
+ self.connect_printer()
156
+ self.printer.send_gcode("M117 Sensor Calibration In Progress")
157
+
158
+ # Connect to sensor
159
+ if save_images == True:
160
+ self.connect_sensor()
161
+
162
+ for i in range(30):
163
+ self.sensor.capture_image()
164
+
165
+ # Send initialization gcode to printer
166
+ if home_printer == True:
167
+ self.initialize_printer()
168
+
169
+ # If no data path was provided, set default path to a folder called "sensor_calibration_data" in the Downloads folder
170
+ if data_save_path is not None:
171
+ data_save_path = os.path.join(data_save_path, "sensor_calibration_data")
172
+
173
+ # Create necessary directories if they don't exist
174
+ Path(data_save_path).mkdir(parents=True, exist_ok=True)
175
+ Path(os.path.join(data_save_path, "annotations")).mkdir(parents=True, exist_ok=True)
176
+ Path(os.path.join(data_save_path, "blank_images")).mkdir(parents=True, exist_ok=True)
177
+ Path(os.path.join(data_save_path, "probe_images")).mkdir(parents=True, exist_ok=True)
178
+
179
+ # Open a csv file to write calibration data
180
+ with open(os.path.join(data_save_path, "annotations", "probe_data.csv"), 'w', newline='') as csv_file:
181
+ csv_writer = csv.writer(csv_file)
182
+ csv_writer.writerow(['img_name', 'x_mm', 'y_mm', 'penetration_depth_mm'])
183
+
184
+ # Save blank image
185
+ if save_images == True:
186
+ blank_img = self.sensor.capture_image()
187
+ img = Image.fromarray(blank_img)
188
+ img.save(os.path.join(data_save_path, "blank_images", "blank.png"))
189
+
190
+ # If no calibration file path was provided, use the default calibration file for the specified sensor
191
+ if calibration_file_path == None:
192
+ calibration_file_path = self.sensor.default_calibration_file
193
+
194
+ # Load CSV file into numpy array
195
+ self.calibration_points = np.genfromtxt(calibration_file_path, delimiter=',', skip_header=1)
196
+
197
+ # Get number of rows (i.e. calibration points)
198
+ N = self.calibration_points.shape[0]
199
+
200
+ # Variable to keep track of image number
201
+ img_idx = 0
202
+
203
+ # Move to offset Z position
204
+ self.printer.send_gcode("G0 Z" + str(self.sensor.z_offset + self.sensor.z_clearance))
205
+
206
+ time.sleep(1 + (self.sensor.z_offset + self.sensor.z_clearance) / 4)
207
+
208
+ print("Attach probe to printer head. ", end="")
209
+ input("Press Enter to continue...")
210
+ print("")
211
+
212
+ # Move to offset XY position
213
+ self.printer.send_gcode("G0 X" + str(self.sensor.x_offset) + " Y" + str(self.sensor.y_offset))
214
+
215
+ time.sleep(1 + max(self.sensor.x_offset, self.sensor.y_offset) / 10)
216
+
217
+ print("Beginning sensor calibration procedure...")
218
+ print("")
219
+
220
+ x_prev = self.sensor.x_offset
221
+ y_prev = self.sensor.y_offset
222
+ z_prev = self.sensor.z_offset + self.sensor.z_clearance
223
+
224
+ # Loop through every calibration point
225
+ for i in tqdm(range(N), desc="Sensor Calibration Progress"):
226
+ # If specified penetration depth exceeds maximum value, print message
227
+ if abs(self.calibration_points[i][2]) > self.sensor.max_penetration:
228
+ print("Line " + str(i+1) + ": Maximum penetration depth for sensor exceeded. Skipping calibration point.")
229
+ # If penetration depth does not exceed maximum value, move to calibration point
230
+ else:
231
+ # Get absolute XYZ coordinates
232
+ x = self.sensor.x_offset + self.calibration_points[i][0]
233
+ y = self.sensor.y_offset + self.calibration_points[i][1]
234
+ z = self.sensor.z_offset - abs(self.calibration_points[i][2])
235
+
236
+ # Move to Z clearance height
237
+ self.printer.send_gcode("G0 Z" + str(self.sensor.z_offset + self.sensor.z_clearance))
238
+
239
+ # Move to desired XY location
240
+ self.printer.send_gcode("G0 X" + str(x) + " Y" + str(y))
241
+
242
+ # Move to desired Z penetration
243
+ self.printer.send_gcode("G0 Z" + str(z))
244
+
245
+ # Calculate time required to reach position
246
+ # Assumes x and y speed of 10 mm/s, z speed of 4 mm/s
247
+ travel_time = abs(self.sensor.z_offset + self.sensor.z_clearance - z_prev) / 4 + max(abs(x - x_prev), abs(y - y_prev)) / 10 + abs(z - (self.sensor.z_offset + self.sensor.z_clearance)) / 4
248
+ time.sleep(travel_time + 1)
249
+
250
+ # Update variables
251
+ x_prev = x
252
+ y_prev = y
253
+ z_prev = z
254
+
255
+ # Take desired number of images
256
+ if save_images == True:
257
+ with open(os.path.join(data_save_path, "annotations", "probe_data.csv"), 'a', newline='') as csv_file:
258
+ csv_writer = csv.writer(csv_file)
259
+
260
+ for j in range(int(self.calibration_points[i][3])):
261
+ frame = self.sensor.capture_image()
262
+
263
+ img_name = str(img_idx) + "_" + "X" + str(self.calibration_points[i][0]) + "Y" + str(self.calibration_points[i][1]) + "Z" + str(self.calibration_points[i][2]) + ".png"
264
+ img_path = os.path.join(data_save_path, "probe_images",img_name)
265
+
266
+ img = Image.fromarray(frame)
267
+ img.save(img_path)
268
+
269
+ csv_writer.writerow([img_name, self.calibration_points[i][0], self.calibration_points[i][1], self.calibration_points[i][2]])
270
+
271
+ img_idx += 1
272
+
273
+ time.sleep(0.5)
274
+
275
+ else:
276
+ with open(os.path.join(data_save_path, "annotations", "probe_data.csv"), 'a', newline='') as csv_file:
277
+ csv_writer = csv.writer(csv_file)
278
+ csv_writer.writerow(["---", self.calibration_points[i][0], self.calibration_points[i][1], self.calibration_points[i][2]])
279
+
280
+ # Move to Z clearance height
281
+ self.printer.send_gcode("G0 Z" + str(self.sensor.z_offset + self.sensor.z_clearance))
282
+
283
+ print("")
284
+
285
+ # Update printer display
286
+ self.printer.send_gcode("M117 Sensor Calibration Complete!")
287
+
288
+ # Disconnect from 3D printer
289
+ self.disconnect_printer()
290
+
291
+ # Disconnect from sensor
292
+ if save_images == True:
293
+ self.disconnect_sensor()
294
+
295
+ print("Sensor calibration procedure complete!")
296
+ print("")
297
+
298
+ return True
@@ -0,0 +1,82 @@
1
+ from ..Printer import Printer
2
+ import serial
3
+ from typing import Union
4
+ from pathlib import Path
5
+
6
+ class Ender3(Printer):
7
+ """
8
+ Ender3: A Printer Class for the Ender 3
9
+ Args:
10
+ port (str or pathlib.Path): The COM port the printer is connected to.
11
+ """
12
+ def __init__(self, port: Union[str, Path]):
13
+ self.port = port
14
+ self.name = "Ender 3"
15
+
16
+ def connect(self):
17
+ """
18
+ Connects to the Ender 3 printer.
19
+ """
20
+ # Code to connect to the printer
21
+ self.ser = serial.Serial(self.port, 115200)
22
+
23
+ def disconnect(self):
24
+ """
25
+ Disconnects from the Ender 3 printer.
26
+ """
27
+ # Code to disconnect from the printer
28
+ self.ser.close()
29
+
30
+ def send_gcode(self, command: str):
31
+ """
32
+ Sends a G-code command to the Ender 3 printer.
33
+ Args:
34
+ command (str): The G-code command to be sent to the 3D printer.
35
+ """
36
+ # Code to execute gcode command on the printer
37
+ self.ser.write(str.encode(command + "\r\n"))
38
+
39
+ def get_response(self):
40
+ """
41
+ Gets messages sent by the Ender 3 printer.
42
+
43
+ Returns:
44
+ response (str): The message sent by the printer.
45
+ """
46
+ # Code to return message from the printer
47
+ response = self.ser.readline().decode('utf-8')
48
+
49
+ return response
50
+
51
+ def initialize(self, xy_only: bool = False):
52
+ """
53
+ Initializes the Ender 3 printer (homes the printer, sets units, adjusts fans, etc).
54
+ Args:
55
+ xy_only (bool): If True, only homes the X and Y axes.
56
+ """
57
+ # Code to initialize printer (home, set units, set absolute/relative movements, adjust fan speeds, etc.)
58
+
59
+ # Use Metric Values
60
+ self.send_gcode("G21")
61
+
62
+ # Absolute Positioning
63
+ self.send_gcode("G90")
64
+
65
+ # Fan Off
66
+ self.send_gcode("M107")
67
+
68
+ if xy_only:
69
+ # Home Printer X Y
70
+ self.send_gcode("G28 X Y")
71
+ else:
72
+ # Home Printer X Y Z
73
+ self.send_gcode("G28")
74
+
75
+ # Check if homing is complete
76
+ ok_count = 0
77
+
78
+ while ok_count < 4:
79
+ if "ok" in self.get_response():
80
+ ok_count += 1
81
+
82
+ return True
@@ -0,0 +1,63 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class Printer(ABC):
4
+ """
5
+ Printer: An abstract base class for 3D printers.
6
+ """
7
+ def __init__(self):
8
+ self.name = ""
9
+
10
+ @abstractmethod
11
+ def connect(self):
12
+ """ Connects to the 3D printer.
13
+ """
14
+ pass
15
+
16
+ @abstractmethod
17
+ def disconnect(self):
18
+ """ Disconnects from the 3D printer.
19
+ """
20
+ pass
21
+
22
+ @abstractmethod
23
+ def send_gcode(self, command: str):
24
+ """ Sends a G-code command to the 3D printer.
25
+
26
+ Args:
27
+ command (str): The G-code command to be sent to the 3D printer.
28
+ """
29
+ pass
30
+
31
+ @abstractmethod
32
+ def get_response(self):
33
+ """ Gets messages sent by the 3D printer.
34
+
35
+ Returns:
36
+ str: The message sent by the printer.
37
+ """
38
+ pass
39
+
40
+ @abstractmethod
41
+ def initialize(self):
42
+ """ Initializes the 3D printer (homes the printer, sets units, adjusts fans, etc).
43
+ """
44
+ pass
45
+
46
+ def go_to(self, x: float = None, y: float = None, z: float = None):
47
+ """
48
+ Moves the printer to a specific position.
49
+ Args:
50
+ x (float, optional): The X coordinate to move to.
51
+ y (float, optional): The Y coordinate to move to.
52
+ z (float, optional): The Z coordinate to move to.
53
+ """
54
+ # Code to move the printer to a specific position
55
+ command = "G0"
56
+ if x is not None:
57
+ command += f" X{x}"
58
+ if y is not None:
59
+ command += f" Y{y}"
60
+ if z is not None:
61
+ command += f" Z{z}"
62
+
63
+ self.send_gcode(command)
@@ -0,0 +1,47 @@
1
+ from ..Sensor import Sensor
2
+ import cv2
3
+ import os
4
+
5
+ try:
6
+ from digit_interface import Digit
7
+ except:
8
+ pass
9
+
10
+ class DIGIT(Sensor):
11
+ """
12
+ DIGIT: A Sensor Class for the DIGIT sensor
13
+ Args:
14
+ serial_number (str): The serial number of the DIGIT sensor.
15
+ """
16
+ def __init__(self, serial_number: str):
17
+ self.serial_number = serial_number
18
+ self.name = "DIGIT"
19
+ self.x_offset = 110
20
+ self.y_offset = 111.5
21
+ self.z_offset = 137
22
+ self.z_clearance = 2
23
+ self.max_penetration = 4
24
+ self.default_calibration_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "default.csv")
25
+
26
+ def connect(self):
27
+ """
28
+ Connects to the DIGIT sensor.
29
+ """
30
+ # Code to connect to the sensor
31
+ self.sensor = Digit(self.serial_number)
32
+ self.sensor.connect()
33
+ self.sensor.set_fps(30)
34
+
35
+ def disconnect(self):
36
+ """
37
+ Disconnects from the DIGIT sensor.
38
+ """
39
+ # Code to disconnect from the sensor
40
+ self.sensor.disconnect()
41
+
42
+ def capture_image(self):
43
+ """
44
+ Captures an image from the DIGIT sensor.
45
+ """
46
+ # Code to return an image from the sensor
47
+ return cv2.flip(self.sensor.get_frame(), 1)