py3dcal 1.0.0__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.
- py3DCal/__init__.py +12 -0
- py3DCal/data_collection/Calibrator.py +298 -0
- py3DCal/data_collection/Printers/Ender3/Ender3.py +82 -0
- py3DCal/data_collection/Printers/Ender3/__init__.py +0 -0
- py3DCal/data_collection/Printers/Printer.py +63 -0
- py3DCal/data_collection/Printers/__init__.py +0 -0
- py3DCal/data_collection/Sensors/DIGIT/DIGIT.py +47 -0
- py3DCal/data_collection/Sensors/DIGIT/__init__.py +0 -0
- py3DCal/data_collection/Sensors/DIGIT/default.csv +1222 -0
- py3DCal/data_collection/Sensors/GelsightMini/GelsightMini.py +45 -0
- py3DCal/data_collection/Sensors/GelsightMini/__init__.py +0 -0
- py3DCal/data_collection/Sensors/GelsightMini/default.csv +1210 -0
- py3DCal/data_collection/Sensors/Sensor.py +35 -0
- py3DCal/data_collection/Sensors/__init__.py +0 -0
- py3DCal/data_collection/__init__.py +0 -0
- py3DCal/model_training/__init__.py +0 -0
- py3DCal/model_training/datasets/DIGIT_dataset.py +75 -0
- py3DCal/model_training/datasets/GelSightMini_dataset.py +73 -0
- py3DCal/model_training/datasets/__init__.py +3 -0
- py3DCal/model_training/datasets/split_dataset.py +38 -0
- py3DCal/model_training/datasets/tactile_sensor_dataset.py +82 -0
- py3DCal/model_training/lib/__init__.py +0 -0
- py3DCal/model_training/lib/add_coordinate_embeddings.py +29 -0
- py3DCal/model_training/lib/depthmaps.py +74 -0
- py3DCal/model_training/lib/fast_poisson.py +51 -0
- py3DCal/model_training/lib/get_gradient_map.py +39 -0
- py3DCal/model_training/lib/precompute_gradients.py +61 -0
- py3DCal/model_training/lib/train_model.py +96 -0
- py3DCal/model_training/lib/validate_device.py +22 -0
- py3DCal/model_training/lib/validate_parameters.py +45 -0
- py3DCal/model_training/models/__init__.py +1 -0
- py3DCal/model_training/models/touchnet.py +211 -0
- py3DCal/model_training/touchnet/__init__.py +0 -0
- py3DCal/model_training/touchnet/dataset.py +78 -0
- py3DCal/model_training/touchnet/touchnet.py +736 -0
- py3DCal/model_training/touchnet/touchnet_architecture.py +72 -0
- py3DCal/utils/__init__.py +0 -0
- py3DCal/utils/utils.py +32 -0
- py3dcal-1.0.0.dist-info/LICENSE +21 -0
- py3dcal-1.0.0.dist-info/METADATA +29 -0
- py3dcal-1.0.0.dist-info/RECORD +44 -0
- py3dcal-1.0.0.dist-info/WHEEL +5 -0
- py3dcal-1.0.0.dist-info/entry_points.txt +3 -0
- py3dcal-1.0.0.dist-info/top_level.txt +1 -0
py3DCal/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .data_collection.Calibrator import Calibrator
|
|
2
|
+
from .data_collection.Printers.Printer import Printer
|
|
3
|
+
from .data_collection.Sensors.Sensor import Sensor
|
|
4
|
+
from .data_collection.Printers.Ender3.Ender3 import Ender3
|
|
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.train_model import train_model
|
|
11
|
+
from .model_training.lib.depthmaps import get_depthmap, save_2d_depthmap, show_2d_depthmap
|
|
12
|
+
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
|
|
File without changes
|
|
@@ -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)
|
|
File without changes
|
|
@@ -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)
|
|
File without changes
|