You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

444 lines
20 KiB

import FreeCAD
import math
import time
import Part
import copy
import os
import os.path
from jinja2 import Environment, FileSystemLoader
import io
header_src = """&ACCESS RVP
&REL 1
&PARAM TEMPLATE = C:\KRC\Roboter\Template\ExpertVorgabe
&PARAM EDITMASK = *
"""
z_up_pose = """{X 0.0, Y 0.0, Z 50.0, A 0.0, B 0.0, C 0.0, E1 0.0, E2 0.0}"""
class Kuka_Layer:
def __init__(self):
self.contours = []
self.hatchlines = []
class Kuka_Prog:
def __init__(self):
# each layer is a tuple of Contours[] and Hatchlines[]
self.layers = []
self.current_layer = -1
# self.contour_path_list = []
# self.hatchlines_list = []
self.baseorigin = (0, 0, 0)
self.tool = 6
self.base = 6
self.vproc = 0.023
self.vmax = 0.15
self.laser_power = 0.4
self.laser_out = 3
self.laser_pilot_out = 4 # default is pilot laser
self.use_laser_out = self.laser_pilot_out
self.inert_gas_out = 9
self.powder_out = 7
self.simulation = True
self.label = "REPLACEME"
def set_baseorigin(self, vec):
self.baseorigin = (vec.x, vec.y, vec.z)
def set_tool(self, tool):
self.tool = tool
def set_base(self, base):
self.base = base
def set_velocity(self, vproc, vmax):
self.vproc = vproc
self.vmax = vmax
def set_laser_power(self, power):
self.laser_power = power
def set_laser_out(self, laser_output):
self.laser_out = laser_output
def set_laser_pilot_out(self, laser_pilot_out):
self.laser_pilot_out = laser_pilot_out
def set_simulation(self, sim):
self.simulation = sim
if not self.simulation:
self.use_laser_out = self.laser_out
else:
self.use_laser_out = self.laser_pilot_out
def set_label(self, label):
self.label = label
def create_layer(self):
self.layers.append(Kuka_Layer())
self.current_layer += 1
return self.current_layer
def append_contour(self, poses, segmenttype='LIN'):
layer = self.layers[self.current_layer]
layer.contours.append((poses, segmenttype))
def append_hatchline(self, line, segmenttype='LIN'):
layer = self.layers[self.current_layer]
if not len(layer.hatchlines):
layer.hatchlines.append((line, segmenttype))
return
# poses are sorted
# but maybe we need to reverse
# get the point distance from first and last pose
last, _ = layer.hatchlines[-1]
nfirst = line[0]
nlast = line[-1]
last = FreeCAD.Base.Vector(last[1].X, last[1].Y, last[1].Z)
nlast = FreeCAD.Base.Vector(nlast.X, nlast.Y, nlast.Z)
nfirst = FreeCAD.Base.Vector(nfirst.X, nfirst.Y, nfirst.Z)
dnl = last.distanceToPoint(nlast)
dnf = last.distanceToPoint(nfirst)
if dnl < dnf:
line.reverse()
layer.hatchlines.append((line, segmenttype))
def draw_wire(self, obj):
path = Part.makePolygon([FreeCAD.Base.Vector(p.X, p.Y, p.Z) for p in self.pose_list ])
#s = Part.show(path)
obj.addObject(s)
s.ViewObject.LineColor=(1.0,0.5,0.0)
s.ViewObject.LineWidth=(2.5)
def get_vectors(self):
return [FreeCAD.Base.Vector(p.X, p.Y, p.Z) for p in poses for poses in self.contour_path_list ]
def save_with_template(self, article, path, templatename):
if article[0].isdigit():
article = "_"+article
if self.simulation:
filename_src = "{}_sim.src".format(article)
filename_dat = "{}_sim.dat".format(article)
else:
filename_src = "{}.src".format(article)
filename_dat = "{}.dat".format(article)
user_dir = FreeCAD.getUserAppDataDir()
template_dir = os.path.join(user_dir, "Mod", "fc_lasercladding_wb", "freecad", "LaserCladdingWorkbench", "templates")
environment = Environment(loader=FileSystemLoader(template_dir))
template_src = environment.get_template(templatename+".src")
with io.StringIO("") as f:
for layer_idx, layer in enumerate(self.layers):
f.write(";- =============================\n")
f.write(";- Layer {}\n".format(layer_idx))
f.write(";- Contourpaths\n")
for contour_idx, (poses, seg_type) in enumerate(layer.contours):
f.write(";- Contourpath {}\n".format(contour_idx))
# start laser code
f.write(";- Move to pose up from contour start\n")
f.write("$VEL.CP = TRAVELSPEED ; m/s (vmax)\n")
f.write("LIN_REL {Z 90.0} C_VEL; relative 90mm up\n")
f.write("LIN refpose:{}:{} C_VEL; move to start point but save z distance\n".format(poses[0].translate_with(self.baseorigin).to_string(), z_up_pose))
if seg_type == 'LIN':
f.write("LIN refpose:{} C_VEL; GENERATED\n".format(poses[0].translate_with(self.baseorigin).to_string()))
f.write("TRIGGER WHEN DISTANCE=0 DELAY=0 DO $OUT[%d]=TRUE ; Turn on Laser at point\n" % self.use_laser_out)
f.write("$VEL.CP = WELDSPEED ; m/s ; m/s (vproc)\n")
for pose in poses[1:]:
f.write("LIN refpose:{} C_VEL; GENERATED\n".format(pose.translate_with(self.baseorigin).to_string()))
if seg_type == 'SPLINE':
f.write("SPLINE\n")
for pose in poses:
f.write(" SPL refpose:{} ; GENERATED\n".format(pose.translate_with(self.baseorigin).to_string()))
f.write("ENDSPLINE\n")
f.write(";- Turn off Laser\n")
f.write("$OUT[%d] = FALSE\n" % self.use_laser_out)
# end of subroutine
f.write(";- =============================\n")
if len(layer.hatchlines):
print("Number Hatchlines: ", len(layer.hatchlines))
f.write(";- Hatchlines\n")
f.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vmax)
f.write("LIN_REL {Z 90.0} C_VEL; just move up \n")
for (line, seg_type) in layer.hatchlines:
# a line has many segments
# start laser at first segment
# stop with last
f.write(";- Hatchline\n")
segment = line[0]
f.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vmax)
f.write("LIN {}:{} C_VEL; move to first hatch point but with z_up\n".format(segment.translate_with(self.baseorigin).to_string(), z_up_pose))
# One Hatchline
f.write(";- First Point in line \n")
f.write("LIN {} C_VEL; GENERATED\n".format(segment.translate_with(self.baseorigin).to_string()))
f.write("TRIGGER WHEN DISTANCE=0 DELAY=0 DO $OUT[%d]=True; Turn on Laser at point \n" % self.use_laser_out)
# each segment
for segment in line[1:-1]:
f.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vproc)
f.write("LIN {} C_VEL; GENERATED\n".format(segment.translate_with(self.baseorigin).to_string()))
segment = line[-1]
f.write(";- Last Point in line \n")
f.write("LIN {} C_VEL; GENERATED\n".format(segment.translate_with(self.baseorigin).to_string()))
f.write("TRIGGER WHEN DISTANCE=0 DELAY=0 DO $OUT[%d]=FALSE; Turn off Laser at point\n" % self.use_laser_out)
f.write(";- End line \n")
f.write(";- ========= END LAYER =========\n")
f.write(";- =============================\n")
# end of subroutine
content = template_src.render(
simulation=self.simulation,
artikel=article,
tool=self.tool,
base=self.base,
powder_out=self.powder_out,
inert_gas_out=self.inert_gas_out,
laser_out=self.use_laser_out,
laserpower=self.laser_power,
vproc=self.vproc,
vmax=self.vmax,
paths=f.getvalue(),
label=self.label
)
# dat template
template_dat = environment.get_template(templatename+".dat")
datcontent = template_dat.render(
simulation=self.simulation,
artikel=article
)
### Save the rendere template to output file
with open(filename_src, mode="w", encoding="utf-8") as message:
message.write(content)
print(f"... wrote {filename_src}")
with open(filename_dat, mode="w", encoding="utf-8") as message:
message.write(datcontent)
print(f"... wrote {filename_dat}")
def save_prog(self, article, path):
if self.simulation:
filename = "kvt_{}_sim.src".format(article)
else:
filename = "kvt_{}.src".format(article)
srcfile = open(os.path.join(path, filename), 'w')
srcfile.write(header_src)
# subroutine definition
srcfile.write("DEF "+filename+"( )\n\n")
srcfile.write(";- Kuka src file, generated by KVT\n")
srcfile.write(";- " + time.asctime() + "\n\n")
# defining world and base
srcfile.write("E6POS startp\n")
srcfile.write("REAL WELDSPEED\n")
srcfile.write("REAL TRAVELSPEED\n")
srcfile.write("REAL LASERPOWER\n")
srcfile.write("E6POS point1\n")
# srcfile.write("DECL E6AXIS xp1={A1 -1.9, A2 -105.76, A3 79.97, A4 178.83, A5 -20.3, A6 -4.37, E1 -90, E2 0}\n")
srcfile.write(";------------- definitions ------------\n")
srcfile.write("EXT BAS (BAS_COMMAND :IN,REAL :IN ) ;set base to World\n")
srcfile.write("BAS (#INITMOV,0 ) ;Initialicing the defaults for Vel and so on \n\n")
srcfile.write("BAS (#TOOL,%d) ;Initialicing the defaults for Vel and so on \n\n" % self.tool)
srcfile.write("BAS (#BASE,%d) ;Initialicing the defaults for Vel and so on \n\n" % self.base)
srcfile.write("PTP {A1 -33.31, A2 -104.71, A3 114.60, A4 282.66, A5 -39.21, A6 -104.87, E1 -90, E2 1.0}\n")
srcfile.write("\n;------------- main part ------------\n")
#V = w.Velocity / 1000.0 # from mm/s to m/s
CDIS = 2.3
CVEL = 95.0
srcfile.write(";- Process Parameters (change here)\n")
srcfile.write("TRAVELSPEED = %f ; m/s\n" % self.vmax)
srcfile.write("WELDSPEED = %f ; m/s\n" % self.vproc)
srcfile.write("LASERPOWER = %f ; Set laser power\n" % self.laser_power)
#srcfile.write("; hier teach punkt eingeben\n;FOLD PTP P1 Vel=25 % PDAT1 Tool[2]:LASER Base[2]:Laser;%{PE}%R 8.2.24,%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:P1, 3:, 5:25, 7:PDAT1\n$BWDSTART=FALSE\nPDAT_ACT=PPDAT1\nFDAT_ACT=FP1\nBAS(#PTP_PARAMS,25)\nPTP XP1\n;ENDFOLD\n")
srcfile.write("startp=$POS_ACT\n")
srcfile.write(";- Ab hier nicht mehr aendern!\n")
srcfile.write(";- Movement parameters\n")
srcfile.write("$VEL.CP = TRAVELSPEED\n")
srcfile.write("$APO.CDIS = %f ; mm \n" % CDIS)
srcfile.write("$APO.CVEL = %f ; percent \n" % CVEL)
srcfile.write(";- Input/Output settings\n")
srcfile.write("$ANOUT[1] = LASERPOWER ; Set laser power\n")
srcfile.write("$OUT[%d] = FALSE ; Set Laser off\n" % self.use_laser_out) # don't know but must be on
if not self.simulation:
srcfile.write("$OUT[2] = TRUE ; Set Laser activation on\n") # don't know but must be on
srcfile.write("$OUT[%d] = TRUE ; Set powder on \n" % self.powder_out)
srcfile.write("$OUT[%d] = TRUE ; Set inert gas on \n" % self.inert_gas_out)
else:
srcfile.write("$OUT[%d] = FALSE ; set powder off \n" % self.powder_out)
srcfile.write("$OUT[%d] = FALSE ; set inert gas off\n" % self.inert_gas_out)
srcfile.write(";- Starting point\n")
srcfile.write("point1 = {X -110.0, Y 0.0, Z 0.0, A 0.0000, B 0.0000, C 0.0000, E1 0.0000, E2 0.0000}\n")
srcfile.write("point1.S = startp.S\n")
srcfile.write("point1.T = startp.T\n")
srcfile.write("LIN point1 C_VEL; GENERATED\n")
srcfile.write("WAIT SEC 7.0\n")
for layer_idx, layer in enumerate(self.layers):
srcfile.write(";- =============================\n")
srcfile.write(";- Layer {}\n".format(layer_idx))
srcfile.write(";- Contourpaths\n")
for contour_idx, (poses, seg_type) in enumerate(layer.contours):
srcfile.write(";- Contourpath {}\n".format(contour_idx))
# start laser code
srcfile.write(";- Move to pose up from contour start\n")
srcfile.write("$VEL.CP = %f ; m/s ; m/s (vmax)\n" % self.vmax)
srcfile.write("LIN_REL {Z 90.0} C_VEL; relative 90mm up\n")
srcfile.write("LIN {}:{} C_VEL; move to start point but save z distance\n".format(poses[0].translate_with(self.baseorigin).to_string(), z_up_pose))
if seg_type == 'LIN':
srcfile.write("LIN {} C_VEL; GENERATED\n".format(poses[0].translate_with(self.baseorigin).to_string()))
srcfile.write("TRIGGER WHEN DISTANCE=0 DELAY=0 DO $OUT[%d]=True ; Turn on Laser at point\n" % self.use_laser_out)
srcfile.write("$VEL.CP = %f ; m/s ; m/s (vproc)\n" % self.vproc)
for pose in poses[1:]:
srcfile.write("LIN {} C_VEL; GENERATED\n".format(pose.translate_with(self.baseorigin).to_string()))
if seg_type == 'SPLINE':
srcfile.write("SPLINE\n")
for pose in poses:
srcfile.write(" SPL {} ; GENERATED\n".format(pose.translate_with(self.baseorigin).to_string()))
srcfile.write("ENDSPLINE\n")
srcfile.write(";- Turn off Laser\n")
srcfile.write("$OUT[%d] = FALSE\n" % self.use_laser_out)
# end of subroutine
srcfile.write(";- =============================\n")
srcfile.write(";- Hatchlines\n")
srcfile.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vmax)
srcfile.write("LIN_REL {Z 90.0} C_VEL; just move up \n")
for (line, seg_type) in layer.hatchlines:
# a line has many segments
# start laser at first segment
# stop with last
segment = line[0]
srcfile.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vmax)
srcfile.write("LIN {}:{} C_VEL; move to first hatch point but with z_up\n".format(segment.translate_with(self.baseorigin).to_string(), z_up_pose))
# One Hatchline
srcfile.write(";- Hatchline\n")
srcfile.write("LIN {} C_VEL; GENERATED\n".format(segment.translate_with(self.baseorigin).to_string()))
srcfile.write("TRIGGER WHEN DISTANCE=0 DELAY=0 DO $OUT[%d]=True; Turn on Laser at point \n" % self.use_laser_out)
# each segment
for segment in line[1:-1]:
srcfile.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vproc)
srcfile.write("LIN {} C_VEL; GENERATED\n".format(segment.translate_with(self.baseorigin).to_string()))
segment = line[-1]
srcfile.write("LIN {} C_VEL; GENERATED\n".format(segment.translate_with(self.baseorigin).to_string()))
srcfile.write("TRIGGER WHEN DISTANCE=0 DELAY=0 DO $OUT[%d]=FALSE; Turn off Laser at point\n" % self.use_laser_out)
srcfile.write(";- ========= END LAYER =========\n")
srcfile.write(";- =============================\n")
# end of subroutine
srcfile.write("$OUT[%d] = FALSE; laser off\n" % self.use_laser_out)
srcfile.write("$OUT[%d] = FALSE; powder off\n" % self.powder_out)
srcfile.write("$OUT[%d] = FALSE; inert gas off\n" % self.inert_gas_out)
srcfile.write("$VEL.CP = %f ; m/s ; m/s \n" % self.vmax)
srcfile.write(";- Move to HOME position\n")
srcfile.write("PTP {A1 -33.31, A2 -104.71, A3 114.60, A4 282.66, A5 -39.21, A6 -104.87, E1 -90, E2 1.0}\n")
srcfile.write("\n;------------- end ------------\n")
srcfile.write("END \n\n")
srcfile.close()
class Kuka_Pose:
def __init__(self):
self.X = 0.0
self.Y = 0.0
self.Z = 0.0
self.A = 0.0
self.B = 0.0
self.C = 0.0
self.S = 0
self.T = 0
self.E1 = 0.0
self.E2 = 0.0
def set_from_point_and_normal(self, point, normal):
self.X = point.x
self.Y = point.y
self.Z = point.z
r = FreeCAD.Base.Rotation(FreeCAD.Base.Vector(0,0,1), normal)
ABC_in_deg = r.toEulerAngles('ZYX')
self.A = math.radians(ABC_in_deg[0])
self.B = math.radians(ABC_in_deg[1])
self.C = math.radians(ABC_in_deg[2])
#print("Rotation:", self.A, self.B, self.C)
def from_point_and_normal(point, normal):
pose = Kuka_Pose()
pose.X = point.x
pose.Y = point.y
pose.Z = point.z
r = FreeCAD.Base.Rotation(FreeCAD.Base.Vector(0,0,1), normal)
ABC_in_deg = r.toEulerAngles('ZYX')
pose.A = math.radians(ABC_in_deg[0])
pose.B = math.radians(ABC_in_deg[1])
pose.C = math.radians(ABC_in_deg[2])
#print("Rotation:", self.A, self.B, self.C)
return pose
def to_string(self, rot=False):
if rot:
pose_string="X {:.3f}, Y {:.3f}, Z {:.3f}, A {:.4f}, B {:.4f}, C {:.4f}, E1 {:.4f}, E2 {:.4f}"
return "{" + pose_string.format(self.X, self.Y, self.Z, self.A, self.B, self.C, self.E1, self.E2) + "}"
else:
pose_string="X {:.3f}, Y {:.3f}, Z {:.3f}, A {:.4f}, B {:.4f}, C {:.4f}, E1 {:.4f}, E2 {:.4f}"
return "{" + pose_string.format(self.X, self.Y, self.Z, 0,0,0,0,0) + "}"
def translate_with(self, vector):
pose = copy.copy(self)
pose.X = pose.X - vector[0]
pose.Y = pose.Y - vector[1]
pose.Z = pose.Z - vector[2]
return pose
def draw_pose(self):
#line=Part.makeLine(point, point+3*normal)
#lines.append(line)
# from euler to some line
# create upfacing vector then rotate around each axis?
up = FreeCAD.Base.Vector(0,0,1)
rotx = FreeCAD.Base.Rotation(FreeCAD.Base.Vector(1,0,0), math.degrees(self.C))
roty = FreeCAD.Base.Rotation(FreeCAD.Base.Vector(0,1,0), math.degrees(self.B))
rotz = FreeCAD.Base.Rotation(FreeCAD.Base.Vector(0,0,1), math.degrees(self.A))
rot = rotz.multiply(roty.multiply(rotx))
up_rotated = rot.multVec(up)
basepoint = FreeCAD.Base.Vector(self.X, self.Y, self.Z)
line = Part.makeLine(basepoint, basepoint+5*up_rotated)
#line.Placement.Rotation = rot
s = Part.show(line)
s.ViewObject.LineColor=(1.0,0.0,0.0)
def get_list_of_poses(face, edges):
poses = []
for edge in edges:
p0 = edge.Vertexes[0].Point
p1 = edge.Vertexes[1].Point
for p in [p0, p1]:
uv = face.Surface.parameter(p)
normal = face.normalAt(uv[0], uv[1])
pose = Kuka_Pose.from_point_and_normal(p, normal)
poses.append(pose)
return poses