Commit 655afdea authored by Chetan Sharma's avatar Chetan Sharma
Browse files

Polishing repo

parent eec2d671
""" """
Intended to be the brain box of this project. Intended to be the brain box of this project.
""" """
FAKE = False from optimize import Optimizer
from ml import UnifiedLinearModel
import numpy as np from models import T_lin, F_lin
import time from objects import EndMill, Conditions, MachineChar
import shelve
import logging
import os import os
import logging
import shelve
import time
import numpy as np
FAKE = True
# hacky fix for issues with serial library # hacky fix for issues with serial library
if not FAKE: if FAKE:
from fake_cut import ReplayCut
else:
from cut import Cut from cut import Cut
from objects import EndMill, Conditions, MachineChar
from fake_cut import ReplayCut
from models import T_lin, F_lin, T_lin_full, F_lin_full
from ml import UnifiedLinearModel, UnifiedLinearModelFull
from optimize import Optimizer #, OptimizerFull, OptimizerPSO, OptimizerPSOFull
logging.basicConfig(level="INFO") logging.basicConfig(level="INFO")
MACHINE_PORT = '/dev/ttyS25'
SPINDLE_PORT = '/dev/ttyS33' def ammp(MACHINE_PORT, SPINDLE_PORT, TFD_PORT, D, W, f_r, f_r_clearing, w, START_DEPTH, START_FACE_D, ENDMILL, D_A, N, X_TRAVEL, CONFIDENCE_RATE, USE_OLD_DATA, NAME, MODEL, EQUATIONS, OPTIMIZER, MACHINE):
TFD_PORT = '/dev/ttyS36' """
Runs the optimizing system.
# input variables System starts out by facing the stock flat (since we need to make sure the endmill bottom perfectly corresponds to the start of the stock).
D = 1e-3 # depth of cut (always unchanging...) Then does a bootstrap cut to initialize the model.
W = 1e-3 # initial width of cut for bootstrap Then starts optimizing process itself.
f_r = 0.001 # initial feedrate for bootstrap
f_r_clearing = 0.003 # feedrate for facing and cutting start groove Args:
w = 200 # spindle speed MACHINE_PORT: port name for machine
START_DEPTH = 0.0e-3 SPINDLE_PORT: port name for spindle
START_FACE_D = 0.2e-3 TFD_PORT: port name for tool force dyno
ENDMILL = EndMill(3, 3.175e-3, 3.175e-3, 12e-3, 5e-3) D: depth of cut (always unchanging...)
# ENDMILL = EndMill(3, 9.525e-3/2, 9.525e-3/2, 12.7e-3, 5e-3) W: initial width of cut for bootstrap
D_A = 0.1e-3 # maximum allowable deflection f_r: initial feedrate for bootstrap
N = 50 # total number of cuts to take, including bootstrap cuts f_r_clearing: feedrate for facing and cutting start groove
CONFIDENCE_RATE = np.linspace(0.2, 1, 5) # confidence progression during bootstrap cuts w: spindle speed
USE_OLD_DATA = False START_DEPTH: offset depth to start cutting at
START_FACE_D: how deep to face stock before starting ammp runs
NAME = "ammp-lcs-1_4" # name to save to / name to draw data from if doing a fake cut ENDMILL: endmill parameters
MODEL = UnifiedLinearModel D_A: maximum allowable deflection
EQUATIONS = (T_lin, F_lin) N: total number of cuts to take, including bootstrap cuts
OPTIMIZER = Optimizer # optimizer to use X_TRAVEL: travel in the x direction
CONFIDENCE_RATE: confidence progression during bootstrap cuts
# taig machine USE_OLD_DATA: whether or not to use datapoints from an older run. change this to run name to use this feature
MACHINE = MachineChar( NAME: name to save to / name to draw data from if doing a fake cut
r_e = 1, MODEL: model class to use
K_T = 0.10281, EQUATIONS: equations to use in optimizer
R_w = 0.188, OPTIMIZER: optimizer to use
V_max = 48, MACHINE: machine characteristics
I_max = 10, """
T_nom = 0.12, FIXED_CONDITIONS = Conditions(
f_r_max = 0.01, D=D,
K_machine = 1.25e6, W=W,
D_a = D_A f_r=f_r,
) w=w,
endmill=ENDMILL
FIXED_CONDITIONS = Conditions( )
D = D,
W = W, logging.info("Initializing all structures")
f_r = f_r,
w = w, cut = None
endmill = ENDMILL if FAKE:
) cut = ReplayCut(NAME, MODEL(), *EQUATIONS, [0, 0], [0.1, 2])
else:
logging.info("Initializing all structures") cut = Cut(MACHINE_PORT, SPINDLE_PORT, TFD_PORT, ENDMILL, X_TRAVEL,
50.8e-3, f_r_clearing, w, START_DEPTH, NAME, graceful_shutdown=True)
cut = None model = MODEL()
if FAKE: optimizer = OPTIMIZER(model, MACHINE, D_A, FIXED_CONDITIONS)
cut = ReplayCut(NAME, MODEL(), *EQUATIONS, [0,0], [0.1,2])
else: logging.info("Beginning facing operation, creating starting groove")
cut = Cut(MACHINE_PORT, SPINDLE_PORT, TFD_PORT, ENDMILL, 80e-3, 50.8e-3, f_r_clearing, w, START_DEPTH, NAME) if START_FACE_D:
model = MODEL() cut.face_layer(START_FACE_D)
optimizer = OPTIMIZER(model, MACHINE, D_A, FIXED_CONDITIONS) cut.begin_layer(D)
logging.info("Beginning facing operation, creating starting groove") logging.info("First bootstrap cut to obtain a basic characterization")
if START_FACE_D:
cut.face_layer(START_FACE_D) conditions_conservative = Conditions(D, W, f_r, w, ENDMILL)
cut.begin_layer(D) datum = cut.cut(conditions_conservative, save=True, auto_layer=True)
logging.info("First bootstrap cut to obtain a basic characterization")
conditions_conservative = Conditions(D, W, f_r, w, ENDMILL)
datum = cut.cut(conditions_conservative, save=True, auto_layer=True)
model.ingest_datum(datum)
logging.info("After bootstrap cut, model params are actually at: " + ", ".join(["{:.5e}".format(p) for p in model.params]))
if USE_OLD_DATA and not FAKE:
with shelve.open(os.path.join("saved_cuts", "db")) as db:
model.ingest_data(db[USE_OLD_DATA])
logging.info("Partially optimized bootstrap cuts starting now")
# start optimizing, but only slowly start accepting new datums
confidences = list(CONFIDENCE_RATE) + [1] * (N - len(CONFIDENCE_RATE))
for confidence in confidences:
logging.info("Confidence at : " + str(confidence))
conditions_optimized = optimizer.optimize(verbose = True)
logging.info("Optimized : " + str(conditions_optimized))
conditions_compromise = conditions_conservative.compromise(conditions_optimized, confidence)
logging.info("Compromised : " + str(conditions_compromise))
logging.info("Model guesses : " + str(model.predict_one(conditions_compromise)))
datum = cut.cut(conditions_compromise, save = True, auto_layer=True)
logging.info("Datum obtained : " + str(datum))
model.ingest_datum(datum) model.ingest_datum(datum)
logging.info("Params updated to: " + ", ".join(["{:.5e}".format(p) for p in model.params]))
if FAKE: logging.info("After bootstrap cut, model params are actually at: " +
logging.info("Actual cut params: " + ", ".join(["{:.5e}".format(p) for p in cut.params])) ", ".join(["{:.5e}".format(p) for p in model.params]))
\ No newline at end of file if USE_OLD_DATA and not FAKE:
with shelve.open(os.path.join("saved_cuts", "db")) as db:
model.ingest_data(db[USE_OLD_DATA])
logging.info("Partially optimized bootstrap cuts starting now")
# start optimizing, but only slowly start accepting new datums
confidences = list(CONFIDENCE_RATE) + [1] * (N - len(CONFIDENCE_RATE))
for i, confidence in enumerate(confidences):
logging.info("------------------ Run #" +
str(i+1) + " -----------------------")
logging.info("Confidence at : " + str(confidence))
conditions_optimized = optimizer.optimize(verbose=True)
logging.info("Optimized : " + str(conditions_optimized))
conditions_compromise = conditions_conservative.compromise(
conditions_optimized, confidence)
logging.info("Compromised : " + str(conditions_compromise))
logging.info("Model guesses : " +
str(model.predict_one(conditions_compromise)))
datum = cut.cut(conditions_compromise, save=True, auto_layer=True)
logging.info("Datum obtained : " + str(datum))
model.ingest_datum(datum)
logging.info("Params updated to: " +
", ".join(["{:.5e}".format(p) for p in model.params]))
if FAKE:
logging.info("Actual cut params: " +
", ".join(["{:.5e}".format(p) for p in cut.params]))
if __name__ == "__main__":
# input variables
MACHINE_PORT = '/dev/ttyS25'
SPINDLE_PORT = '/dev/ttyS33'
TFD_PORT = '/dev/ttyS36'
D = 1.5e-3
W = 1e-3
f_r = 0.001
f_r_clearing = 0.005
w = 200
START_DEPTH = 0e-3
START_FACE_D = 0.1e-3
ENDMILL = EndMill(3, 3.175e-3 / 2, 3.175e-3 / 2, 10e-3, 5e-3)
# ENDMILL = EndMill(3, 3.175e-3, 3.175e-3, 12e-3, 5e-3)
# ENDMILL = EndMill(3, 9.525e-3/2, 9.525e-3/2, 20e-3, 5e-3)
D_A = 0.1e-3
N = 10
X_TRAVEL = 30e-3
CONFIDENCE_RATE = np.linspace(0.2, 1, 5)
USE_OLD_DATA = False
NAME = "ammp-alu-1_8_coolant"
MODEL = UnifiedLinearModel
EQUATIONS = (T_lin, F_lin)
OPTIMIZER = Optimizer
# taig machine
MACHINE = MachineChar(
r_e=1,
K_T=0.10281,
R_w=0.188,
V_max=48,
I_max=10,
T_nom=0.12,
f_r_max=0.01,
K_machine=1.25e6,
D_a=D_A
)
ammp(MACHINE_PORT, SPINDLE_PORT, TFD_PORT, D, W, f_r, f_r_clearing, w, START_DEPTH, START_FACE_D,
ENDMILL, D_A, N, X_TRAVEL, CONFIDENCE_RATE, USE_OLD_DATA, NAME, MODEL, EQUATIONS, OPTIMIZER, MACHINE)
""" """
Intended to be the brain box of this project; for now, it just runs a test sweep to collect initial data. A tiny utility script that just collects sweep data.
""" """
import numpy as np import numpy as np
import time import time
...@@ -10,49 +10,41 @@ from ml import LinearModel ...@@ -10,49 +10,41 @@ from ml import LinearModel
from optimize import Optimizer from optimize import Optimizer
import logging import logging
logging.basicConfig(level="INFO") logging.basicConfig(level="INFO")
MACHINE_PORT = '/dev/ttyS25' MACHINE_PORT = "/dev/ttyS25"
SPINDLE_PORT = '/dev/ttyS33' SPINDLE_PORT = "/dev/ttyS33"
TFD_PORT = '/dev/ttyS36' TFD_PORT = "/dev/ttyS36"
IGNORE_FIRST = 0
endmill = EndMill(3, 3.175e-3, 3.175e-3, 12e-3, 5e-3)
machine = MachineChar(
r_e = 1,
K_T = 0.10281,
R_w = 0.188,
V_max = 48,
I_max = 10,
T_nom = 0.12,
f_r_max = 0.017,
K_machine = 5e6,
D_a = 1
)
endmill = EndMill(3, 3.175e-3, 3.175e-3, 9.5e-3, 3e-3)
fixed_conditions = Conditions( fixed_conditions = Conditions(
D = 1e-3, D=1e-3, W=1e-3, f_r=0.001, w=300, endmill=endmill)
W = 1e-3,
f_r = 0.001, cut = Cut(
w = 300, MACHINE_PORT,
endmill = endmill SPINDLE_PORT,
TFD_PORT,
endmill,
60e-3,
50.8e-3,
5e-3,
300,
initial_z=0.5e-3,
save_as="sweep-alu-1_4-v2",
) )
cut = Cut(MACHINE_PORT, SPINDLE_PORT, TFD_PORT, endmill, 80e-3, 50.8e-3, 5e-3, 300, save_as = "6061-sweep-speed") f_r_range = np.linspace(2e-3, 0.01, 6)
W_range = np.linspace(1e-3, 3.175e-3 * 1.8, 6)
f_r_range = np.linspace(2e-3, 0.011, 4) cut.face_layer(D=0.3e-3)
W_range = np.linspace(1e-3, 3.175e-3 * 1.8, 5)
w_range = np.linspace(100, 300, 5)
cut.begin_layer(D=1e-3)
cut.face_layer(D = 0.3e-3) for f_r in f_r_range:
cut.begin_layer(D = 1e-3)
for f_r in f_r_range:
for W in W_range: for W in W_range:
for w in w_range: conditions = Conditions(1e-3, W, f_r, 200, endmill)
conditions = Conditions(1e-3, W, f_r, w, endmill) cut.cut(conditions, save=True, auto_layer=True)
cut.cut(conditions, save = True, auto_layer=True)
cut.close()
cut.close()
\ No newline at end of file
...@@ -16,8 +16,9 @@ class MachineCrash(Exception): ...@@ -16,8 +16,9 @@ class MachineCrash(Exception):
class Cut: class Cut:
def __init__(self, machine_port, spindle_port, tfd_port, endmill, x_max, y_max, f_r_clearing, w_clearing, initial_z=0, save_as=None, graceful_shutdown = False): def __init__(self, machine_port, spindle_port, tfd_port, endmill, x_max, y_max, f_r_clearing, w_clearing, initial_z=0, save_as=None, graceful_shutdown=False):
self.machine = Machine(machine_port, graceful_shutdown = graceful_shutdown) self.machine = Machine(
machine_port, graceful_shutdown=graceful_shutdown)
self.machine.unlock() self.machine.unlock()
self.machine.zero() self.machine.zero()
self.spindle = Spindle_Applied(spindle_port) self.spindle = Spindle_Applied(spindle_port)
...@@ -29,7 +30,7 @@ class Cut: ...@@ -29,7 +30,7 @@ class Cut:
self.x_max = x_max self.x_max = x_max
self.y_max = y_max self.y_max = y_max
self.cut_x = 0 self.cut_x = 0
self.cut_z = -initial_z # initial z in positive units self.cut_z = -initial_z # initial z in positive units
self.D = 0 self.D = 0
self.f_r_clearing = f_r_clearing self.f_r_clearing = f_r_clearing
self.w_clearing = w_clearing self.w_clearing = w_clearing
...@@ -47,6 +48,9 @@ class Cut: ...@@ -47,6 +48,9 @@ class Cut:
self.spindle.set_w(0) self.spindle.set_w(0)
def warmup_spindle(self): def warmup_spindle(self):
"""
Just spins the spindle for a little while to get the bearings warmed up.
"""
log.info("Warming up spindle") log.info("Warming up spindle")
self.spindle.set_w(300) self.spindle.set_w(300)
time.sleep(30) time.sleep(30)
...@@ -60,16 +64,16 @@ class Cut: ...@@ -60,16 +64,16 @@ class Cut:
D: Depth of cut for this layer. D: Depth of cut for this layer.
f_r_clearing: feedrate used for this clearing pass. f_r_clearing: feedrate used for this clearing pass.
w_clearing: spindle speed used for this clearing pass. w_clearing: spindle speed used for this clearing pass.
""" """
log.info("Preparing to face layer to depth " + str(D) + log.info("Preparing to face layer to depth " + str(D) +
" at feedrate " + str(self.f_r_clearing) + " with speed " + str(self.w_clearing)) " at feedrate " + str(self.f_r_clearing) + " with speed " + str(self.w_clearing))
# define next cut # define next cut
self.D = D self.D = D
self.cut_z -= D self.cut_z -= D
cuts = np.append(np.arange(self.X_START, self.X_END, 1.8 * self.endmill.r_c), self.X_END) cuts = np.append(np.arange(self.X_START, self.X_END,
1.8 * self.endmill.r_c), self.X_END)
# perform cut # perform cut
self.spindle.set_w(self.w_clearing) self.spindle.set_w(self.w_clearing)
self.machine.rapid({'x': self.X_START, 'y': self.Y_START}) self.machine.rapid({'x': self.X_START, 'y': self.Y_START})
...@@ -100,8 +104,6 @@ class Cut: ...@@ -100,8 +104,6 @@ class Cut:
f_r_clearing: feedrate used for this clearing pass. f_r_clearing: feedrate used for this clearing pass.
w_clearing: spindle speed used for this clearing pass. w_clearing: spindle speed used for this clearing pass.
Returns:
A data blob from this operation.
""" """
log.info("Preparing to clear layer to depth " + str(D) + log.info("Preparing to clear layer to depth " + str(D) +
" at feedrate " + str(self.f_r_clearing) + " with speed " + str(self.w_clearing)) " at feedrate " + str(self.f_r_clearing) + " with speed " + str(self.w_clearing))
...@@ -122,12 +124,21 @@ class Cut: ...@@ -122,12 +124,21 @@ class Cut:
log.info("Layer prepared for clearing") log.info("Layer prepared for clearing")
def cut(self, conditions, save = True, auto_layer = True): def cut(self, conditions, save=True, auto_layer=True):
"""
Performs a stroke of facing. Returns a data blob.
""" """
Performes a new cut using the conditions provided.
Args:
conditions (Conditions): The conditions for this cut
save (bool, optional): Whether or not to save this cut. Defaults to True.
auto_layer (bool, optional): Whether or not to advance to the next layer if you hit X bounds. Defaults to True.
Raises:
MachineCrash: If auto_layer is false and you reach the end travel
Returns:
Data: A data blob for this cut
"""
_, W, f_r, w, _ = conditions.unpack() _, W, f_r, w, _ = conditions.unpack()
self.spindle.set_w(w) self.spindle.set_w(w)
...@@ -142,13 +153,13 @@ class Cut: ...@@ -142,13 +153,13 @@ class Cut:
self.machine.cut({'y': self.Y_END}, self.f_r_clearing) self.machine.cut({'y': self.Y_END}, self.f_r_clearing)
self.machine.rapid({'z': self.cut_z + self.D + 1e-3}) self.machine.rapid({'z': self.cut_z + self.D + 1e-3})
self.machine.hold_until_still() self.machine.hold_until_still()
# start next layer # start next layer
self.begin_layer(self.D) self.begin_layer(self.D)
log.info("Actually performing cut now.") log.info("Actually performing cut now.")
# try again, return result # try again, return result
return self.cut(conditions, save = save, auto_layer=False) return self.cut(conditions, save=save, auto_layer=False)
else: else:
raise MachineCrash( raise MachineCrash(
"Cutting too far in X direction: X = " + str(X_START)) "Cutting too far in X direction: X = " + str(X_START))
...@@ -204,7 +215,7 @@ class Cut: ...@@ -204,7 +215,7 @@ class Cut:
db[self.save_as] = existing db[self.save_as] = existing
else: else:
db[self.save_as] = [data] db[self.save_as] = [data]
db.sync() db.sync()
log.info("Data saved under name " + self.save_as) log.info("Data saved under name " + self.save_as)
...@@ -231,4 +242,3 @@ class Cut: ...@@ -231,4 +242,3 @@ class Cut:
if __name__ == "__main__": if __name__ == "__main__":
log.info("Hi") log.info("Hi")
This diff is collapsed.
...@@ -8,6 +8,7 @@ from ml import UnifiedLinearModel ...@@ -8,6 +8,7 @@ from ml import UnifiedLinearModel
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class Fake_Cut: class Fake_Cut:
""" """
Fake cutting process. Returns results using prebaked parameters and specified noise levels. Fake cutting process. Returns results using prebaked parameters and specified noise levels.
...@@ -37,6 +38,14 @@ class Fake_Cut: ...@@ -37,6 +38,14 @@ class Fake_Cut:
pass pass
def cut(self, conditions: Conditions, *args, **kwargs): def cut(self, conditions: Conditions, *args, **kwargs):
"""Performs a simulated cut with noise
Args:
conditions (Conditions): Conditions for this fake cut
Returns:
Data: A fake data blob with noise
"""
# use prediction as output # use prediction as output
T = self.T_func(conditions, *self.params) T = self.T_func(conditions, *self.params)
_, Fy = self.F_func(conditions, *self.params) _, Fy = self.F_func(conditions, *self.params)
...@@ -49,7 +58,8 @@ class Fake_Cut: ...@@ -49,7 +58,8 @@ class Fake_Cut:
# generate fake times # generate fake times
t = np.linspace(0, 1, 100) t = np.linspace(0, 1, 100)
# return fake reading # return fake reading
data = Data(*conditions.unpack(), np.array([t, T_noisy]).T, np.array([t, Fy_noisy]).T) data = Data(*conditions.unpack(),
np.array([t, T_noisy]).T, np.array([t, Fy_noisy]).T)
return data return data
def scale_coefs(self, scale): def scale_coefs(self, scale):
...@@ -62,4 +72,4 @@ class ReplayCut(Fake_Cut): ...@@ -62,4 +72,4 @@ class ReplayCut(Fake_Cut):
with shelve.open(os.path.join("saved_cuts", "db")) as db: with shelve.open(os.path.join("saved_cuts", "db")) as db:
data = db[replay_data] data = db[replay_data]
self.model.ingest_data(data) self.model.ingest_data(data)
super().__init__(self.model.params, T_func, F_func, error, noise) super().__init__(self.model.params, T_func, F_func, error, noise)
\ No newline at end of file
...@@ -9,12 +9,15 @@ from models import T_lin, F_lin, T_lin_full, F_lin_full, T_x_vector, T_x_vector_ ...@@ -9,12 +9,15 @@ from models import T_lin, F_lin, T_lin_full, F_lin_full, T_x_vector, T_x_vector_
from objects import Data, Conditions, EndMill, Prediction from objects import Data, Conditions, EndMill, Prediction
# https://stackoverflow.com/questions/11686720 # https://stackoverflow.com/questions/11686720
def mean_no_outliers(data, m=2): def mean_no_outliers(data, m=2):
d = np.abs(data - np.median(data)) d = np.abs(data - np.median(data))
mdev = np.median(d) mdev = np.median(d)
s = d / (mdev if mdev else 1.) s = d / (mdev if mdev else 1.)
return np.mean(data[s < m]) return np.mean(data[s < m])
<