Source code for parts

# ----------------------------------------------------------------------------
# -- Parts to print
# -- comps library
# -- Python FreeCAD functions and classes that groups components
# ----------------------------------------------------------------------------
# -- (c) Felipe Machado
# -- Area of Electronics. Rey Juan Carlos University (urjc.es)
# -- November-2016
# ----------------------------------------------------------------------------
# --- LGPL Licence
# ----------------------------------------------------------------------------

import FreeCAD
import Part
import Draft
import Mesh
import MeshPart
import DraftVecUtils
import logging
import inspect

# ---------------------- can be taken away after debugging
import os
# directory this file is
filepath = os.getcwd()
import sys
# to get the components
# In FreeCAD can be added: Preferences->General->Macro->Macro path
sys.path.append(filepath)
# ---------------------- can be taken away after debugging

import kcomp 
import kcomp_optic
import fcfun
import comps
import kparts
import shp_clss
import fc_clss

from fcfun import V0, VX, VY, VZ, V0ROT, addBox, addCyl, addCyl_pos, fillet_len
from fcfun import VXN, VYN, VZN
from fcfun import addBolt, addBoltNut_hole, NutHole
from kcomp import TOL


stl_dir = "/stl/"

logging.basicConfig(level=logging.DEBUG,
                    format='%(%(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# ----------- class AluProfBracketPerp -----------------------------------

[docs]class AluProfBracketPerp (object): """ Bracket to join 2 aluminum profiles that are perpendicular, that is, they are not on the same plane :: aluprof_perp (perpendicular to the bracket) / / / bracket (not drawn) / / /_____ / / /_____/| /__/ /______|/ aluprof_lin (it is in line with the bracket) |__|/ fc_perp_ax (is not the axis of the perpendicular : profile, but the axis of the bracket aluprof_perp : attached to the perpendicular profile ___:_ | | \ bracket _|___|____\___ .........> fc_line_ax alusize_lin + aluprof_lin :_______________ fc_perp_ax : :br_perp_thick .+. ....:__: : | |\ alusize_perp + | | \ : | |______\.. :...|_________|..: br_lin_thick .........> fc_lin_ax :.........: Parameters ---------- alusize_lin : float Width of the aluminum profile on the line alusize_perp : float Width of the perpendicular aluminum profile br_lin_thick : float Thickness of the line bracket br_perp_thick : float Thickness of the perpendicular bracket bolt_lin_d : int Metric of the bolt 3, 4, ... (integer) bolt_perp_d : int Metric of the bolt 3, 4, ... (integer) on the profile line if 0, the same as bolt_lin_d nbolts_lin : int Number of bolts one bolt on the fc_lin_ax, number of bolts: two bolts on the fc_lin_ax bolts_lin_dist : float If more than one bolt on fc_lin_ax, defines the distance between them. if zero, takes min distance bolts_lin_rail : int Instead of bolt holes, it will be a rail it doesnt make sense to have number of bolts with this option it will work on 2 bolts or more. If nbolts_lin == 3, it will make a rail between them. so it will be the same to have nbolts_lin = 2 and bolts_lin_dist = 20 nbolts_lin = 3 and bolts_lin_dist = 10 The rail will be 20, and it will look the same, it will be more clear to have the first option: 2 bolts xtr_bolt_head : float Extra space for the bolt head length, and making a space for it xtr_bolt_head_d : float Extra space for the bolt head diameter, and making a space for it. For the wall bolt reinforce : int 1, if it is reinforced on the sides of lin profile fc_perp_ax : FreeCAD.Vector Axis of the bracket on the perpendicular prof, see picture fc_lin_ax : FreeCAD.Vector Axis of the bracket on the aligned profile, see picture pos : FreeCAD.Vector Position of the center of the bracket on the intersection wfco : int * if 1: With FreeCad Object: a freecad object is created * if 0: only the shape name : str Name of the freecad object, if created """ def __init__(self, alusize_lin, alusize_perp, br_perp_thick = 3., br_lin_thick = 3., bolt_lin_d = 3, #metric of the bolt bolt_perp_d = 0, #metric of the bolt nbolts_lin = 1, bolts_lin_dist = 0, bolts_lin_rail = 0, xtr_bolt_head = 3, xtr_bolt_head_d = 0, reinforce = 1, fc_perp_ax = VZ, fc_lin_ax = VX, pos = V0, wfco=1, name = 'bracket'): doc = FreeCAD.ActiveDocument self.name = name # bolt lin dimensions boltli_dict = kcomp.D912[bolt_lin_d] boltlihead_r = boltli_dict['head_r'] boltlihead_r_tol = boltli_dict['head_r_tol'] boltlishank_r_tol = boltli_dict['shank_r_tol'] boltlihead_l = boltli_dict['head_l'] if bolt_perp_d == 0: bolt_perp_d = bolt_lin_d boltpe_dict = kcomp.D912[bolt_perp_d] boltpehead_r = boltpe_dict['head_r'] boltpehead_r_tol = boltpe_dict['head_r_tol'] boltpeshank_r_tol = boltpe_dict['shank_r_tol'] boltpehead_l = boltpe_dict['head_l'] boltmaxhead_r = max(boltlihead_r, boltpehead_r) boltmaxhead_r_tol = max(boltlihead_r_tol, boltpehead_r_tol) # normalize axis, just in case: axis_perp = DraftVecUtils.scaleTo(fc_perp_ax,1) axis_lin = DraftVecUtils.scaleTo(fc_lin_ax,1) axis_perp_neg = axis_perp.negative() axis_lin_neg = axis_lin.negative() axis_wid = axis_perp.cross(axis_lin) #Calculate the length of the brlin_l # br_perp_thick :boltpehead_l # : : : boltlihead_r # ....:__: : : # : | |_ : # alusize_perp + | |_| _:_ # : | |__|___|___ # :...|_____________| # :.......: # bolt1li_dist = br_perp_thick+boltpehead_l+boltlihead_r # : : : # 2 x boltlihead_r # :.............: # + brlin_l bolt1li_dist = ( br_perp_thick + boltpehead_l + boltlihead_r_tol + xtr_bolt_head ) brlin_l = bolt1li_dist + 2 * boltlihead_r if nbolts_lin > 1: if bolts_lin_dist == 0: # for every new bolt, add 3 times the bolt head radius bolts_lin_dist = 3 * boltlihead_r elif bolts_lin_dist < (3 * boltlihead_r) : logger.warning ('bolt_lin_dist too short') bolts_lin_dist = 3 * boltlihead_r brlin_l = brlin_l + (nbolts_lin-1)* bolts_lin_dist # ....:__: : : _________ # : | |_ : || || # alusize_perp + | |_| _:_ || O || # : | |__|___|___ ||_______|| # :...|_____________| |___:_:___|......axis_wid # :.............: :.........: # + brlin_l + alusize_lin shp_box = fcfun.shp_box_dir (box_w = alusize_lin, box_d = brlin_l, box_h = alusize_perp, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = pos) chmf_out_r = min(brlin_l-br_perp_thick, alusize_perp-br_lin_thick) chmf_out_pos = ( pos + DraftVecUtils.scaleTo(axis_lin, brlin_l) + DraftVecUtils.scaleTo(axis_perp, alusize_perp)) shp_box = fcfun.shp_filletchamfer_dirpt(shp_box, fc_axis = axis_wid, fc_pt = chmf_out_pos, fillet = 0, radius = chmf_out_r) # inside_w # ...+... # ....:__: : : :_______: # : | |_ : || || # alusize_perp + | |_| _:_ || O || # : | |__|___|___ ||_______|| # :...|_____________| |___:_:___| # :.............: :.........: # + brlin_l + alusize_lin # cut the box inside # Inside width # add one, to have it a minimum of one mm if (reinforce == 1 and (alusize_lin > 2*(boltmaxhead_r + kcomp.TOL) + 1 )): inside_w = 2*(boltmaxhead_r + kcomp.TOL) #print ("inside width " + str(inside_w)) else: #no space for reinforcement, or reinforcement 0 inside_w = alusize_lin + 2 # +2 to make the cut # chamfer of the inside box chmf_in_r = alusize_perp/2. - br_lin_thick -boltpehead_r_tol logger.debug ("chamfer radius" + str(chmf_in_r)) # inside box: insbox_pos = ( pos + DraftVecUtils.scale(axis_lin,br_perp_thick) + DraftVecUtils.scale(axis_perp,br_lin_thick)) shp_insbox = fcfun.shp_box_dir (box_w = inside_w, box_d = brlin_l, box_h = alusize_perp, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = insbox_pos) if chmf_in_r > 0 : shp_insbox = fcfun.shp_filletchamfer_dirpt(shp_insbox, fc_axis = axis_wid, fc_pt = insbox_pos, fillet = 0, radius = chmf_in_r) #Part.show(shp_insbox) shp_box = shp_box.cut(shp_insbox) #pos_boltpe = pos + DraftVecUtils.scale(axis_perp,alusize_perp/2.) #shp_boltpe= fcfun.shp_cylcenxtr(r=boltshank_r_tol, # h=brack_thick, # normal = axis_lin, # ch = 0, xtr_top = 1, xtr_bot=1, # pos = pos_boltpe) boltholes = [] pos_boltpe = (pos + DraftVecUtils.scale(axis_perp,alusize_perp/2.) + DraftVecUtils.scale(axis_lin,br_perp_thick+boltpehead_l)) shp_boltpe = fcfun.shp_bolt_dir(r_shank = boltpeshank_r_tol, l_bolt = br_perp_thick + boltpehead_l, r_head = boltpehead_r_tol + xtr_bolt_head_d/2., l_head = boltpehead_l, xtr_head = xtr_bolt_head, xtr_shank = 1, support = 0, fc_normal = axis_lin_neg, fc_verx1 = axis_perp, #it doesnt matter pos = pos_boltpe) boltholes.append(shp_boltpe) # position of the first bolt pos_boltli = pos + DraftVecUtils.scale(axis_lin,bolt1li_dist) pos_boltli_top = (pos_boltli + DraftVecUtils.scale(axis_perp, alusize_perp)) if bolts_lin_rail == 1 and nbolts_lin > 1: # there is a rail rail_l = (nbolts_lin - 1) * bolts_lin_dist # 2 Stadium to cut the chamfer if it is too big shp_railli = fcfun.shp_2stadium_dir (length = rail_l, r_s = boltlishank_r_tol, r_l = boltlihead_r_tol + kcomp.TOL/2., #extra TOL h_tot = alusize_perp, h_rl = alusize_perp-br_lin_thick, fc_axis_h = axis_perp_neg, fc_axis_l = axis_lin, ref_l = 2, #ref on the circle center rl_h0 = 1, #bolt head is on pos xtr_h = 1, xtr_nh = 1, pos = pos_boltli_top) boltholes.append(shp_railli) else: # holes for the bolts # first boltli hole , make a bolt, in case there is chamfer to cut shp_boltli = fcfun.shp_bolt_dir(r_shank = boltlishank_r_tol, l_bolt = alusize_perp, r_head = boltlihead_r_tol + kcomp.TOL/2., #extra TOL l_head = alusize_perp-br_lin_thick, xtr_head = 1, xtr_shank = 1, support = 0, fc_normal = axis_perp_neg, fc_verx1 = axis_lin, #it doesnt matter pos = pos_boltli_top) boltholes.append(shp_boltli) # the rest of boltli holes for ibolt in range (1, nbolts_lin): pos_boltli = ( pos_boltli + DraftVecUtils.scale(axis_lin,bolts_lin_dist)) shp_boltli= fcfun.shp_cylcenxtr(r=boltlishank_r_tol, h=br_lin_thick, normal = axis_perp, ch = 0, xtr_top = 1, xtr_bot=1, pos = pos_boltli) boltholes.append(shp_boltli) shp_boltfuse = fcfun.fuseshplist(boltholes) shp_bracket = shp_box.cut(shp_boltfuse) doc.recompute() shp_bracket =shp_bracket.removeSplitter() doc.recompute() self.shp = shp_bracket self.wfco = wfco if wfco == 1: # a freeCAD object is created fco_bracket = doc.addObject("Part::Feature", name ) fco_bracket.Shape = shp_bracket self.fco = fco_bracket def color (self, color = (1,1,1)): if self.wfco == 1: self.fco.ViewObject.ShapeColor = color else: logger.debug("Bracket object with no fco") # exports the shape into stl format # exportStl has problems in FreeCAD 0.17 when there are cylinders # or fillets def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name stlPath = filepath + "/stl/" stlFileName = stlPath + name + "2.stl" # not working well with FreeCAD 0.17 #self.shp.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.shp, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp
#doc = FreeCAD.newDocument() #al = AluProfBracketPerp ( alusize_lin = 10, alusize_perp = 10, # br_perp_thick = 3., # br_lin_thick = 3., # bolt_lin_d = 3, # bolt_perp_d = 3, # nbolts_lin = 1, # xtr_bolt_head = 4, # xtr_bolt_head_d = 2*kcomp.TOL, # space for the nut # reinforce = 0, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket_lin3_1bolt_noreinfore') #al.export_stl() #AluProfBracketPerp ( alusize_lin = 10, alusize_perp = 10, # br_perp_thick = 3., # br_lin_thick = 3., # bolt_d = 3, # nbolts_lin = 2, # xtr_bolt_head = 3, # xtr_bolt_head_d = 2*kcomp.TOL, # space for the nut # reinforce = 0, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket_lin3_2bolts_noreinfore') #doc = FreeCAD.newDocument() #AluProfBracketPerp ( alusize_lin = 10, alusize_perp = 20, # br_perp_thick = 3., # br_lin_thick = 3., # bolt_lin_d = 3, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 0, # bolts_lin_rail = 0, # xtr_bolt_head = 3, # xtr_bolt_head_d = 2*kcomp.TOL, # space for the nut # reinforce = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket_lin3_1bolt_noreinfore') #AluProfBracketPerp ( alusize_lin = 20, alusize_perp = 10, # br_perp_thick = 3., # br_lin_thick = 3., # bolt_lin_d = 3, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 0, # bolts_lin_rail = 0, # xtr_bolt_head = 3, # xtr_bolt_head_d = 2*kcomp.TOL, # space for the nut # reinforce = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket_lin3_1bolt_noreinfore') #AluProfBracketPerp ( alusize_lin = 10, alusize_perp = 10, # br_perp_thick = 3., # br_lin_thick = 3., # bolt_lin_d = 4, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 25, # bolts_lin_rail = 1, # xtr_bolt_head = 3, # xtr_bolt_head_d = 2*kcomp.TOL, # space for the nut # reinforce = 0, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket_lin3_1bolt_noreinfore') # #AluProfBracketPerp ( alusize_lin = 25, alusize_perp = 10, # br_perp_thick = 3., # br_lin_thick = 3., # bolt_lin_d = 6, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 50, # bolts_lin_rail = 1, # xtr_bolt_head = 3, # xtr_bolt_head_d = 2*kcomp.TOL, # space for the nut # reinforce = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket_lin3_1bolt_noreinfore') # ----------- class AluProfBracketPerpWide -----------------------------------
[docs]class AluProfBracketPerpFlap (object): """ Bracket to join 2 aluminum profiles that are perpendicular, that is, they are not on the same plane It is wide because it has 2 ears/flaps? on the sides, to attach to the perpendicular profile :: aluprof_perp (perpendicular to the bracket) / / / bracket (not drawn) / / /_____ / / /_____/| /__/ /______|/ aluprof_lin (it is in line with the bracket) |__|/ fc_perp_ax (is not the axis of the perpendicular : profile, but the axis of the bracket aluprof_perp : attached to the perpendicular profile ___:_ | | \ bracket _|___|____\___ .........> fc_line_ax alusize_lin + aluprof_lin :_______________ fc_perp_ax : :br_perp_thick .+. ....:__: : | |\ alusize_perp + | | \ : | |______\.. :...|__|______|..: br_lin_thick .........> fc_lin_ax :.........: Parameters ---------- alusize_lin : float Width of the aluminum profile on the line alusize_perp : float Width of the perpendicular aluminum profile br_lin_thick : float Thickness of the line bracket br_perp_thick : float Thickness of the perpendicular bracket bolt_lin_d : int Metric of the bolt 3, 4, ... (integer) bolt_perp_d : int Metric of the bolt 3, 4, ... (integer) on the profile line if 0, the same as bolt_lin_d nbolts_lin : int * 1: just one bolt on the fc_lin_ax, or two bolts * 2: two bolts on the fc_lin_ax, or two bolts bolts_lin_dist : float If more than one bolt on fc_lin_ax, defines the distance between them. if zero, takes min distance bolts_lin_rail : int Instead of bolt holes, it will be a rail it doesnt make sense to have number of bolts with this option it will work on 2 bolts or more. If nbolts_lin == 3, it will make a rail between them. so it will be the same to have nbolts_lin = 2 and bolts_lin_dist = 20 nbolts_lin = 3 and bolts_lin_dist = 10 The rail will be 20, and it will look the same, it will be more clear to have the first option: 2 bolts xtr_bolt_head : float Extra space for the bolt head on the line to the wall (perpendicular) sunk : int * 0: just drilled * 1: if the top part is removed, * 2: No reinforcement at all flap : int If it has flaps, if it hasnt flaps, it is kind of useless because it is just the middle part without bolts on the wall, but it can be used to make an union with other parts fc_perp_ax : FreeCAD.Vector Axis of the bracket on the perpendicular prof, see picture fc_lin_ax : FreeCAD.Vector Axis of the bracket on the aligned profile, see picture pos : FreeCAD.Vector Position of the center of the bracket on the intersection wfco : * 1: With FreeCad Object: a freecad object is created * 0: only the shape name : str Name of the freecad object, if created """ def __init__(self, alusize_lin, alusize_perp, br_perp_thick = 3., br_lin_thick = 3., bolt_lin_d = 3, #metric of the bolt bolt_perp_d = 0, #metric of the bolt nbolts_lin = 1, bolts_lin_dist = 0, bolts_lin_rail = 0, xtr_bolt_head = 1, sunk = 1, flap = 1, fc_perp_ax = VZ, fc_lin_ax = VX, pos = V0, wfco=1, name = 'bracket_flap'): doc = FreeCAD.ActiveDocument self.name = name boltli_dict = kcomp.D912[bolt_lin_d] boltlihead_r = boltli_dict['head_r'] boltlihead_r_tol = boltli_dict['head_r_tol'] boltlishank_r_tol = boltli_dict['shank_r_tol'] boltlihead_l = boltli_dict['head_l'] if bolt_perp_d == 0: bolt_perp_d = bolt_lin_d boltpe_dict = kcomp.D912[bolt_perp_d] boltpehead_r = boltpe_dict['head_r'] boltpehead_r_tol = boltpe_dict['head_r_tol'] boltpeshank_r_tol = boltpe_dict['shank_r_tol'] boltpehead_l = boltpe_dict['head_l'] # normalize axis, just in case: axis_perp = DraftVecUtils.scaleTo(fc_perp_ax,1) axis_lin = DraftVecUtils.scaleTo(fc_lin_ax,1) axis_perp_neg = axis_perp.negative() axis_lin_neg = axis_lin.negative() axis_wid = axis_perp.cross(axis_lin) #Calculate the length of the brlin_l # :+ br_perp_thick :boltpehead_l # : :+xtr_bolt_head # : : : + boltlihead_r # ....:__: : : # : | | : # alusize_perp + | | _:_ # : | |__|___|___ # :...|_____________| # :.......: # +bolt1li_dist=br_perp_thick+xtr_bolt_head+boltlihead_r # : : : # 2 x boltlihead_r # :.............: # + brlin_l bolt1li_dist = br_perp_thick + xtr_bolt_head + boltlihead_r brlin_l = bolt1li_dist + 2 * boltlihead_r if nbolts_lin > 1: if bolts_lin_dist == 0: # for every new bolt, add 3 times the bolt head radius bolts_lin_dist = 3 * boltlihead_r elif bolts_lin_dist < (3 * boltlihead_r) : logger.warning ('bolt_lin_dist too short') bolts_lin_dist = 3 * boltlihead_r brlin_l = brlin_l + (nbolts_lin-1)* bolts_lin_dist # 1 # ....:__: : : _____________________ # : | | : | || || | # alusize_perp + | | _:_ | O || || O | # : | |_|___|___ | ||_______|| | # :...|____________| |_____|___:_:___|_____|..axis_wid # :............: : :.........: # + brlin_l : :alusize_lin # :.....: # oneflap_w: # min(4xboltpehead_r, alusize_lin) # :.....................: # totalflap_w shp_boxbr = fcfun.shp_box_dir (box_w = alusize_lin, box_d = brlin_l, box_h = alusize_perp, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = pos) oneflap_w = 0 if flap == 1: oneflap_w = min(4*boltpehead_r, alusize_lin) totalflap_w = alusize_lin + 2 * oneflap_w shp_flap = fcfun.shp_box_dir (box_w = totalflap_w, box_d = br_perp_thick, box_h = alusize_perp, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = pos) shp_boxbr = shp_boxbr.fuse(shp_flap) chmf_pts = [] for isg in [-0.5,0.5]: chmf_pt_pos = (pos + DraftVecUtils.scale(axis_lin, br_perp_thick) + DraftVecUtils.scale(axis_wid, isg * alusize_lin)) chmf_pts.append(chmf_pt_pos) # reinforcement of the flaps with the central space shp_boxbr = fcfun.shp_filletchamfer_dirpts(shp_boxbr, fc_axis = axis_perp, fc_pts = chmf_pts, fillet = 0, radius = boltpehead_r ) doc.recompute() shp_boxbr =shp_boxbr.removeSplitter() chmf_out_r = min(brlin_l-br_perp_thick, alusize_perp-br_lin_thick) chmf_out_pos = ( pos + DraftVecUtils.scaleTo(axis_lin, brlin_l) + DraftVecUtils.scaleTo(axis_perp, alusize_perp)) shp_boxbr = fcfun.shp_filletchamfer_dirpt(shp_boxbr, fc_axis = axis_wid, fc_pt = chmf_out_pos, fillet = 0, radius = chmf_out_r) # ....:__: : : _____________________ # : | | : | || || | # alusize_perp + | | _:_ | O || || O | # : | |_|___|___ | ||_______|| | # :...|____________| |_____|___:_:___|_____|..axis_wid # :.............: :.........: # + brlin_l + alusize_lin boltholes = [] # inside box: (sunk == 1) if sunk > 0: # cut the box inside # Inside width # add one, to have it a minimum of one mm if (sunk == 1) and (alusize_lin > 2*(boltlihead_r + kcomp.TOL) + 1): inside_w = 2*(boltlihead_r + kcomp.TOL) #print ("inside width " + str(inside_w)) else: # no space for reinforcement, or no reinforcement (sunk == 2) inside_w = alusize_lin + oneflap_w + 2 # +2 to make the cut # chamfer of the inside box chmf_in_r = alusize_perp/2. - br_lin_thick -boltlihead_r_tol logger.debug ("chamfer radius" + str(chmf_in_r)) insbox_pos = ( pos + DraftVecUtils.scale(axis_lin,br_perp_thick) + DraftVecUtils.scale(axis_perp,br_lin_thick)) shp_insbox = fcfun.shp_box_dir (box_w = inside_w, box_d = brlin_l, box_h = alusize_perp, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = insbox_pos) if chmf_in_r > 0 : shp_insbox = fcfun.shp_filletchamfer_dirpt(shp_insbox, fc_axis = axis_wid, fc_pt = insbox_pos, fillet = 0, radius = chmf_in_r) shp_boxbr = shp_boxbr.cut(shp_insbox) #pos_boltpe = pos +DraftVecUtils.scale(axis_perp,alusize_perp/2.) #shp_boltpe= fcfun.shp_cylcenxtr(r=boltshank_r_tol, # h=brack_thick, # normal = axis_lin, # ch = 0, xtr_top = 1, xtr_bot=1, # pos = pos_boltpe) if flap == 1: boltpe_dist_w = (alusize_lin+oneflap_w)/2 for iboltpe in [-boltpe_dist_w,boltpe_dist_w]: pos_boltpe = (pos + DraftVecUtils.scale(axis_perp,alusize_perp/2.) + DraftVecUtils.scale(axis_lin,br_perp_thick+boltpehead_l) + DraftVecUtils.scale(axis_wid, iboltpe)) shp_boltpe = fcfun.shp_bolt_dir(r_shank = boltpeshank_r_tol, l_bolt = br_perp_thick + boltpehead_l, r_head = boltpehead_r_tol + kcomp.TOL, #extra TOL l_head = boltpehead_l, xtr_head = 2, xtr_shank = 1, support = 0, fc_normal = axis_lin_neg, fc_verx1 = axis_perp, #it doesnt matter pos = pos_boltpe) boltholes.append(shp_boltpe) # position of the first bolt, on top pos_boltli = ( pos + DraftVecUtils.scale(axis_lin,bolt1li_dist) + DraftVecUtils.scale(axis_perp, alusize_perp)) if bolts_lin_rail == 1 and nbolts_lin > 1: # there is rail rail_l = (nbolts_lin - 1) * bolts_lin_dist # make the hole also for the head of the bolts, even that maybe # it is not necessary because it is sunk shp_railli = fcfun.shp_2stadium_dir (length = rail_l, r_s = boltlishank_r_tol, r_l = boltlihead_r_tol + kcomp.TOL/2., #extra TOL h_tot = alusize_perp, h_rl = alusize_perp-br_lin_thick, fc_axis_h = axis_perp_neg, fc_axis_l = axis_lin, ref_l = 2, #ref on the circle center rl_h0 = 1, #bolt head is on pos xtr_h = 1, xtr_nh = 1, pos = pos_boltli) boltholes.append(shp_railli) else : # first bolt hole: shp_boltli = fcfun.shp_bolt_dir(r_shank = boltlishank_r_tol, l_bolt = alusize_perp, r_head = boltlihead_r_tol + kcomp.TOL/2., #extra TOL l_head = alusize_perp-br_lin_thick, xtr_head = 1, xtr_shank = 1, support = 0, fc_normal = axis_perp_neg, fc_verx1 = axis_lin, #it doesnt matter pos = pos_boltli) boltholes.append(shp_boltli) #if nbolts_lin > 1: for ibolt in range (1, nbolts_lin): pos_boltli = ( pos_boltli + DraftVecUtils.scale(axis_lin,bolts_lin_dist)) shp_boltli = fcfun.shp_bolt_dir(r_shank = boltlishank_r_tol, l_bolt = alusize_perp, r_head = boltlihead_r_tol + kcomp.TOL/2., #extra TOL l_head = alusize_perp-br_lin_thick, xtr_head = 1, xtr_shank = 1, support = 0, fc_normal = axis_perp_neg, fc_verx1 = axis_lin, #it doesnt matter pos = pos_boltli) boltholes.append(shp_boltli) shp_boltfuse = fcfun.fuseshplist(boltholes) shp_bracket = shp_boxbr.cut(shp_boltfuse) doc.recompute() shp_bracket =shp_bracket.removeSplitter() doc.recompute() self.shp = shp_bracket self.wfco = wfco if wfco == 1: # a freeCAD object is created fco_bracket = doc.addObject("Part::Feature", name ) fco_bracket.Shape = shp_bracket self.fco = fco_bracket def color (self, color = (1,1,1)): if self.wfco == 1: self.fco.ViewObject.ShapeColor = color else: logger.debug("Bracket object with no fco") # exports the shape into stl format def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name stlPath = filepath + "/stl/" stlFileName = stlPath + name + ".stl" # exportStl is not working well with FreeCAD 0.17 #self.shp.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.shp, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp
#doc = FreeCAD.newDocument() #AluProfBracketPerpFlap ( alusize_lin = 10, alusize_perp = 15, # br_perp_thick = 4., # br_lin_thick = 3., # bolt_lin_d = 3, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 0, # bolts_lin_rail = 0, # xtr_bolt_head = 1, # sunk = 0, # flap = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket3_flap') #AluProfBracketPerpFlap ( alusize_lin = 15, alusize_perp = 10, # br_perp_thick = 4., # br_lin_thick = 3., # bolt_lin_d = 3, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 0, # bolts_lin_rail = 0, # xtr_bolt_head = 1, # sunk = 0, # flap = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket3_flap') #AluProfBracketPerpFlap ( alusize_lin = 25, alusize_perp = 20, # br_perp_thick = 4., # br_lin_thick = 4., # bolt_lin_d = 6, # bolt_perp_d = 4., # nbolts_lin = 2, # bolts_lin_dist = 50, # bolts_lin_rail = 1, # xtr_bolt_head = 1, # sunk = 0, # flap = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket3_flap') #AluProfBracketPerpFlap ( alusize_lin = 10, alusize_perp = 10, # br_perp_thick = 3., # br_lin_thick = 3., # nbolts_lin = 2, # xtr_bolt_head = 1, # sunk = 2, # flap = 1, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'bracket3_flap_sunk') # ----------- class AluProfBracketPerpTwin -----------------------------------
[docs]class AluProfBracketPerpTwin (object): """ Bracket to join 3 aluminum profiles that are perpendicular, that is, they are not on the same plane to the perpendicular profile :: aluprof_perp (perpendicular to the bracket) . fc_wide_ax ___ . / /|. / / /______ / / /______/| aluprof_lin (it is in line with the bracket) / / /_______|/----------- / / /_____ . alu_sep / / *_____/| . /__/ /______|/----------- |__|/ aluprof_lin (it is in line with the bracket) * shows the reference for the position (argument pos) the direction of fc_wide_ax indicates where the other line of the bracket will be fc_perp_ax (is not the axis of the perpendicular : profile, but the axis of the bracket aluprof_perp : attached to the perpendicular profile ___:_ | | \ bracket _|___|____\___ .........> fc_line_ax alusize_lin + aluprof_lin :_______________ fc_perp_ax : :br_perp_thick .+. ....:__: : | |\ alusize_perp + | | \ : | |______\.. :...|_________|..: br_lin_thick .........> fc_lin_ax :.........: * bolt_perp_line 1: * there is a bolt hole 0: * no bolt hole there ....:__: : : __________________________ : | | : || || || || alusize_perp + | | _:_ || * || O || * || : | |_|___|___ ||_______|| ||_______|| :...|____________| |___:_:___|_____|___:_:__||..axis_wid :.............: :.........:..+..: + brlin_l + union_w alusize_lin : :..alu_sep......: Parameters ---------- alusize_lin : float Width of the aluminum profile on the line alusize_perp : float Width of the perpendicular aluminum profile alu_sep : float Separation of the 2 paralell profiles, from their centers br_lin_thick : float Thickness of the line bracket br_perp_thick : float Thickness of the perpendicular bracket bolt_lin_d : int Metric of the bolt 3, 4, ... (integer) bolt_perp_d : int Metric of the bolt 3, 4, ... (integer) on the profile line if 0, the same as bolt_lin_d nbolts_lin : int * 1: just one bolt on the fc_lin_ax, or two bolts * 2: two bolts on the fc_lin_ax, or two bolts bolts_lin_dist : float If more than one bolt on fc_lin_ax, defines the distance between them. if zero, takes min distance bolts_lin_rail : int Instead of bolt holes, it will be a rail it doesnt make sense to have number of bolts with this option it will work on 2 bolts or more. If nbolts_lin == 3, it will make a rail between them. so it will be the same to have nbolts_lin = 2 and bolts_lin_dist = 20 nbolts_lin = 3 and bolts_lin_dist = 10 The rail will be 20, and it will look the same, it will be more clear to have the first option: 2 bolts bolt_perp_line : int * 1: if it has a bolt on the wall (perp) but in line with the line aluminum profiles * 0: no bolt xtr_bolt_head : float Extra space for the bolt head, and making a space for it only makes sense if bolt_perp_line == 1 sunk : int * 0: No sunk, just drill holes: bolt_perp_line should be 0 * 1: sunk, but with reinforcement if possible * 2: no reinforcement fc_perp_ax : FreeCAD.Vector Axis of the bracket on the perpendicular prof, see picture fc_lin_ax : FreeCAD.Vector Axis of the bracket on the aligned profile, see picture fc_wide_ax : FreeCAD.Vector Axis of the bracket on wide direction, see picture its direction shows where the other aligned profile is pos : FreeCAD.Vector Position of the center of the bracket on the intersection wfco : int * 1: With FreeCad Object: a freecad object is created * 0: only the shape name : str Name of the freecad object, if created """ def __init__(self, alusize_lin, alusize_perp, alu_sep, br_perp_thick = 3., br_lin_thick = 3., bolt_lin_d = 3, #metric of the bolt bolt_perp_d = 0, #metric of the bolt nbolts_lin = 1, bolts_lin_dist = 1, bolts_lin_rail = 0, bolt_perp_line = 0, xtr_bolt_head = 3, sunk = 0, fc_perp_ax = VZ, fc_lin_ax = VX, fc_wide_ax = VY, pos = V0, wfco=1, name = 'bracket_twin'): doc = FreeCAD.ActiveDocument self.name = name boltli_dict = kcomp.D912[bolt_lin_d] boltlihead_r = boltli_dict['head_r'] boltlihead_r_tol = boltli_dict['head_r_tol'] boltlishank_r_tol = boltli_dict['shank_r_tol'] boltlihead_l = boltli_dict['head_l'] if bolt_perp_d == 0: bolt_perp_d = bolt_lin_d boltpe_dict = kcomp.D912[bolt_perp_d] boltpehead_r = boltpe_dict['head_r'] boltpehead_r_tol = boltpe_dict['head_r_tol'] boltpeshank_r_tol = boltpe_dict['shank_r_tol'] boltpehead_l = boltpe_dict['head_l'] # normalize axis, just in case: axis_perp = DraftVecUtils.scaleTo(fc_perp_ax,1) axis_lin = DraftVecUtils.scaleTo(fc_lin_ax,1) axis_perp_neg = axis_perp.negative() axis_lin_neg = axis_lin.negative() axis_wid = DraftVecUtils.scaleTo(fc_wide_ax,1) # position of the other profile brlin2_pos = pos + DraftVecUtils.scale(axis_wid, alu_sep) if bolt_perp_line == 1: # there is bolt if sunk == 2: reinforce = 0 else: reinforce = 1 h_brlin1 = AluProfBracketPerp(alusize_lin = alusize_lin, alusize_perp = alusize_perp, br_perp_thick = br_perp_thick, br_lin_thick = br_lin_thick, bolt_lin_d = bolt_lin_d, bolt_perp_d = bolt_perp_d, nbolts_lin = nbolts_lin, bolts_lin_dist = bolts_lin_dist, bolts_lin_rail = bolts_lin_rail, xtr_bolt_head = xtr_bolt_head, reinforce = reinforce, fc_perp_ax = axis_perp, fc_lin_ax = axis_lin, pos = pos, wfco = 0) h_brlin2 = AluProfBracketPerp(alusize_lin = alusize_lin, alusize_perp = alusize_perp, br_perp_thick = br_perp_thick, br_lin_thick = br_lin_thick, bolt_lin_d = bolt_lin_d, bolt_perp_d = bolt_perp_d, nbolts_lin = nbolts_lin, bolts_lin_dist = bolts_lin_dist, bolts_lin_rail = bolts_lin_rail, xtr_bolt_head = xtr_bolt_head, reinforce = reinforce, fc_perp_ax = axis_perp, fc_lin_ax = axis_lin, pos = brlin2_pos, wfco = 0) else: # no hole: h_brlin1 = AluProfBracketPerpFlap ( alusize_lin = alusize_lin, alusize_perp = alusize_perp, br_perp_thick = br_perp_thick, br_lin_thick = br_lin_thick, bolt_lin_d = bolt_lin_d, bolt_perp_d = bolt_perp_d, nbolts_lin = nbolts_lin, bolts_lin_dist = bolts_lin_dist, bolts_lin_rail = bolts_lin_rail, xtr_bolt_head = xtr_bolt_head, sunk = sunk, flap = 0, #no flap fc_perp_ax = axis_perp, fc_lin_ax = axis_lin, pos = pos, wfco = 0) h_brlin2 = AluProfBracketPerpFlap ( alusize_lin = alusize_lin, alusize_perp = alusize_perp, br_perp_thick = br_perp_thick, br_lin_thick = br_lin_thick, bolt_lin_d = bolt_lin_d, bolt_perp_d = bolt_perp_d, nbolts_lin = nbolts_lin, bolts_lin_dist = bolts_lin_dist, bolts_lin_rail = bolts_lin_rail, xtr_bolt_head = xtr_bolt_head, sunk = sunk, flap = 0, #no flap fc_perp_ax = axis_perp, fc_lin_ax = axis_lin, pos = brlin2_pos, wfco = 0) shp_brlin1 = h_brlin1.shp shp_brlin2 = h_brlin2.shp # center of the 2, to make the union between both pos_mid = pos + DraftVecUtils.scale(axis_wid, alu_sep/2.) # box_w has +2 to make the union union_w = alu_sep-alusize_lin shp_union = fcfun.shp_box_dir (box_w = union_w + 2, box_d = br_perp_thick, box_h = alusize_perp, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = pos_mid) shp_twinbr = fcfun.fuseshplist([shp_brlin1, shp_union, shp_brlin2]) doc.recompute() shp_twinbr = shp_twinbr.removeSplitter() # chamfer the union chmf_pts = [] chmf_pt_pos = (pos + DraftVecUtils.scaleTo(axis_lin, br_perp_thick) + DraftVecUtils.scaleTo(axis_wid, alu_sep- alusize_lin/2.)) chmf_pts.append(chmf_pt_pos) chmf_pt_pos = (pos + DraftVecUtils.scaleTo(axis_lin, br_perp_thick) + DraftVecUtils.scaleTo(axis_wid, alusize_lin/2.)) chmf_pts.append(chmf_pt_pos) shp_twinbr = fcfun.shp_filletchamfer_dirpts(shp_twinbr, fc_axis = axis_perp, fc_pts = chmf_pts, fillet = 0, radius = boltpehead_r ) doc.recompute() shp_twinbr = shp_twinbr.removeSplitter() bolthole_list = [] if bolt_perp_line == 1 or union_w < 8 * boltpehead_r: # one bolt in the middle pos_boltpe = (pos + DraftVecUtils.scale(axis_perp,alusize_perp/2.) + DraftVecUtils.scale(axis_lin,br_perp_thick+boltpehead_l) + DraftVecUtils.scale(axis_wid, alu_sep/2.)) shp_boltpe = fcfun.shp_bolt_dir(r_shank = boltpeshank_r_tol, l_bolt = br_perp_thick + boltpehead_l, r_head = boltpehead_r_tol + kcomp.TOL, #extra TOL l_head = boltpehead_l, xtr_head = 2, xtr_shank = 1, support = 0, fc_normal = axis_lin_neg, fc_verx1 = axis_perp, #it doesnt matter pos = pos_boltpe) bolthole_list.append(shp_boltpe) else: # 2 holes: boltpe_w_pos1 = alusize_lin/2. + 2* boltpehead_r boltpe_w_pos2 = alu_sep - alusize_lin/2. - 2* boltpehead_r for w_pos in [boltpe_w_pos1, boltpe_w_pos2]: pos_boltpe = (pos + DraftVecUtils.scale(axis_perp,alusize_perp/2.) + DraftVecUtils.scale(axis_lin,br_perp_thick+boltpehead_l) + DraftVecUtils.scale(axis_wid, w_pos)) shp_boltpe = fcfun.shp_bolt_dir(r_shank = boltpeshank_r_tol, l_bolt = br_perp_thick + boltpehead_l, r_head = boltpehead_r_tol + kcomp.TOL, #extra TOL l_head = boltpehead_l, xtr_head = 2, xtr_shank = 1, support = 0, fc_normal = axis_lin_neg, fc_verx1 = axis_perp, #it doesnt matter pos = pos_boltpe) bolthole_list.append(shp_boltpe) shp_boltpe = fcfun.fuseshplist(bolthole_list) shp_twinbr = shp_twinbr.cut(shp_boltpe) doc.recompute() shp_bracket =shp_twinbr.removeSplitter() doc.recompute() self.shp = shp_bracket self.wfco = wfco if wfco == 1: # a freeCAD object is created fco_bracket = doc.addObject("Part::Feature", name ) fco_bracket.Shape = shp_bracket self.fco = fco_bracket def color (self, color = (1,1,1)): if self.wfco == 1: self.fco.ViewObject.ShapeColor = color else: logger.debug("Bracket object with no fco") # exports the shape into stl format def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name stlPath = filepath + "/stl/" stlFileName = stlPath + name + ".stl" # exportStl not working well with FreeCAD 0.17 #self.shp.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.shp, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp
#doc = FreeCAD.newDocument() #AluProfBracketPerpTwin ( alusize_lin = 10, alusize_perp = 10, # alu_sep = 40., # br_perp_thick = 3., # br_lin_thick = 3., # bolt_d = 3, # nbolts_lin = 2, # bolt_perp_line = 0, # xtr_bolt_head = 2, # sunk = 2, # fc_perp_ax = VZ, # fc_lin_ax = VX, # fc_wide_ax = VY, # pos = V0, # wfco=1, # name = 'bracket_twin3') #AluProfBracketPerpTwin ( alusize_lin = 16, alusize_perp = 30, # alu_sep = 25., # br_perp_thick = 4., # br_lin_thick = 4., # bolt_lin_d = 6, # bolt_perp_d = 4, # nbolts_lin = 2, # bolts_lin_dist = 15, # bolts_lin_rail = 1, # bolt_perp_line = 0, # xtr_bolt_head = 4, # more extra because of the perp bolt # sunk = 0, # fc_perp_ax = VZ, # fc_lin_ax = VX, # fc_wide_ax = VY, # pos = V0, # wfco=1, # name = 'bracket_twin3_perp') #AluProfBracketPerpTwin ( alusize_lin = 16, alusize_perp = 15, # alu_sep = 25., # br_perp_thick = 4., # br_lin_thick = 4., # bolt_lin_d = 6, # bolt_perp_d = 3, # nbolts_lin = 2, # bolts_lin_dist = 15, # bolts_lin_rail = 1, # bolt_perp_line = 0, # xtr_bolt_head = 4, # more extra because of the perp bolt # sunk = 0, # fc_perp_ax = VZ, # fc_lin_ax = VX, # fc_wide_ax = VY, # pos = V0, # wfco=1, # name = 'bracket_twin3_perp') #AluProfBracketPerpTwin ( alusize_lin = 16, alusize_perp = 10, # alu_sep = 25., # br_perp_thick = 3., # br_lin_thick = 3., # bolt_lin_d = 6, # bolt_perp_d = 3., # nbolts_lin = 2, # bolts_lin_dist = 15, # bolts_lin_rail = 1, # bolt_perp_line = 0, # xtr_bolt_head = 4, # more extra because of the perp bolt # sunk = 0, # fc_perp_ax = VZ, # fc_lin_ax = VX, # fc_wide_ax = VY, # pos = V0, # wfco=1, # name = 'bracket_twin3_perp') # ----------- class IdlePulleyHolder --------------------------- # Creates a holder for a IdlePulley. Usually made of bolts, washers and bearings # It may include a space for a endstop # It is centered at the idle pulley, but at the back, and at the profile height # # hole for endstop # / []: hole for the nut # ________ ___ # ||__| | + above_h # ___| [] |____:__________ Z=0 # | | : aluminum profile # | O O | : # |________| + profile_size # __________________:________ # # O: holes for bolts to attach to the profile # # Z # : # _______:__ ... # / /| : # /________ / | : # ||__| | | + height # | [] | | : # | | | ..: # | O O | / # |________|/.. + depth # : : # :........: # + width # # attach_dir = '-y' enstop_side= 1 TOP VIEW # # # Y # : # : # __:_________ # | : |__| | # | (:) | # ...|__:________|..... X # # ----- Arguments: # profile_size: size of the aluminum profile. 20mm, 30mm # pulleybolt_d: diameter of the bolt used to hold the pulley # holdbolt_d: diameter of the bolts used to attach this part to the aluminum # profile # above_h: height of this piece above the aluminum profile # rail: posibility of having a rail instead of holes for mounting the # holder. It has been made fast, so there may be bugs # mindepth: If there is a minimum depth. Sometimes needed for the endstop # to reach its target # attach_dir: Normal vector to where the holder is attached:'x','-x','y','-y' # NOW ONLY -y IS SUPPORTED. YOU CAN ROTATE IT # endstop_side: -1, 0, 1. Side where the enstop will be # if attach_dir= 'x', this will be referred to the y axis # if 0, there will be no endstop # endstop_h: height of the endstop. If 0 it will be just on top of the profile # ----- Attributes: # depth : depth of the holder # width : depth of the holder # height : depth of the holder # fco : cad object of the compound
[docs]class IdlePulleyHolder (object): """ Creates a holder for a IdlePulley. Usually made of bolts, washers and bearings It may include a space for a endstop It is centered at the idle pulley, but at the back, and at the profile height :: hole for endstop / []: hole for the nut ________ ___ ||__| | + above_h ___| [] |____:__________ Z=0 | | : aluminum profile | O O | : |________| + profile_size __________________:________ O: holes for bolts to attach to the profile Z : _______:__ ... / /| : /________ / | : ||__| | | + height | [] | | : | | | ..: | O O | / |________|/.. + depth : : :........: + width attach_dir = '-y' enstop_side= 1 TOP VIEW Y : : __:_________ | : |__| | | (:) | ...|__:________|..... X Parameters ---------- profile_size : float Size of the aluminum profile. 20mm, 30mm pulleybolt_d : float Diameter of the bolt used to hold the pulley holdbolt_d : float Diameter of the bolts used to attach this part to the aluminum profile above_h : float Height of this piece above the aluminum profile rail : float Posibility of having a rail instead of holes for mounting the holder. It has been made fast, so there may be bugs mindepth : float If there is a minimum depth. Sometimes needed for the endstop to reach its target attach_dir : str Normal vector to where the holder is attached:'x','-x','y','-y' NOW ONLY -y IS SUPPORTED. YOU CAN ROTATE IT endstop_side : int -1, 0, 1. Side where the enstop will be if attach_dir= 'x', this will be referred to the y axis if 0, there will be no endstop endstop_h : float Height of the endstop. If 0 it will be just on top of the profile pos : FreeCAD.Vector Object Placement Attributes ---------- depth : float Depth of the holder width : float Width of the holder height : float Height of the holder fcoFat : Cad object of the compound """ def __init__ (self, profile_size, pulleybolt_d, holdbolt_d, above_h, rail = 0, mindepth = 0, attach_dir = '-y', endstop_side = 0, endstop_posh = 0, pos = V0, name = "idlepulleyhold"): doc = FreeCAD.ActiveDocument self.profile_size = profile_size self.pulleybolt_d = pulleybolt_d self.holdbolt_d = holdbolt_d self.above_h = above_h # extra width on each side of the nut extra_w = 4. # ----------------- Depth calculation pulleynut_d = kcomp.NUT_D934_D[int(pulleybolt_d)] pulleynut_d_tol = pulleynut_d + 3*TOL pulleydepth = pulleynut_d + 2 * extra_w depth = max(pulleydepth, mindepth) if endstop_side != 0: extra_endstop = 3. endstop_l = kcomp.ENDSTOP_B['L'] endstop_ht = kcomp.ENDSTOP_B['HT'] endstop_h = kcomp.ENDSTOP_B['H'] endstopdepth = endstop_ht + extra_endstop + extra_w depth = max (endstopdepth, depth) endstop_boltsep = kcomp.ENDSTOP_B['BOLT_SEP'] endstop_bolt_h = kcomp.ENDSTOP_B['BOLT_H'] endstop_bolt_d = kcomp.ENDSTOP_B['BOLT_D'] # distance of the bolt to the end endstop_bolt2lend = (endstop_l - endstop_boltsep)/2. # distance of the bolt to the topend endstop_bolt2hend = endstop_h - endstop_bolt_h self.depth = depth # ----------------- Width calculation holdbolthead_d = kcomp.D912_HEAD_D[int(holdbolt_d)] # the minimum width due to the holding bolts minwidth_holdbolt = 2 * holdbolthead_d + 4*extra_w # the minimum width due to the endstop if endstop_side == 0: endstop_l = 0 endstop_ht = 0 minwidth_endstop = 0 else: minwidth_endstop = ( endstop_l + 2*TOL + pulleynut_d_tol + 3*extra_w ) width = max(minwidth_holdbolt, minwidth_endstop) self.width = width # ----------------- Height calculation base_h = .9 * profile_size # no need to go all the way down height = base_h + above_h self.height = height # attach_dir = '-y' enstop_side= 1 # # # Y # : # : # p10 __:_________ p11 # | : |__| | # | (:) | depth # ...|__:________|..... X # p00 p01 # width # : # # Y # : # p11 ________:__ p01 # | |__| : | # | (:) | depth # ...|________:__|..... X # p10 p00 # width # Constants to dimensions # holding bolts that will be shank in the piece, the rest will be # for the head bolt_shank = 5. # holes for the holding bolts # separation from the center of the hole to the end hbolt_endsep = extra_w + holdbolthead_d/2. # separation between the holding bolts hbolt_sep = width - 2 * ( extra_w + holdbolthead_d/2.) # Nut for the pulley bolt pulleynut_h = kcomp.NUT_D934_L[int(pulleybolt_d)] pulleynut_hole_h = kcomp.NUT_HOLE_MULT_H * pulleynut_h # height inside the piece of the pulley bolt # adding 1 to give enough space to the 25mm bolt, it was to tight pulleybolt_h = 2 * extra_w + pulleynut_hole_h +1 if attach_dir == '-y': if endstop_side == 0: p0x = - width/2. p1x = + width/2. sg = 1 #sign else: sg = endstop_side # sign p0x = sg * (- pulleynut_d_tol/2. - extra_w) p1x = p0x + sg * width p00 = FreeCAD.Vector ( p0x, 0, - base_h) p01 = FreeCAD.Vector ( p1x, 0, - base_h) p11 = FreeCAD.Vector ( p1x, depth, - base_h) p10 = FreeCAD.Vector ( p0x, depth, - base_h) shp_wire_base = Part.makePolygon([p00,p01, p11, p10, p00]) shp_face_base = Part.Face(shp_wire_base) shp_box = shp_face_base.extrude(FreeCAD.Vector(0,0,height)) hbolt_p0x = p0x + sg * hbolt_endsep #shank of holding bolt pos_shank_hbolt0 = FreeCAD.Vector(hbolt_p0x, -1, -profile_size/2.) if rail == 0: shp_shank_hbolt0 = fcfun.shp_cyl ( r = holdbolt_d/2. + TOL, h= bolt_shank + 2, normal = VY, pos = pos_shank_hbolt0) if depth > bolt_shank : pos_head_hbolt0 = FreeCAD.Vector(hbolt_p0x, bolt_shank, -profile_size/2.) shp_head_hbolt0 = fcfun.shp_cyl ( r = holdbolthead_d/2. + TOL, h = depth - bolt_shank + 1, normal = VY, pos = pos_head_hbolt0) shp_hbolt0 = shp_shank_hbolt0.fuse(shp_head_hbolt0) else: # no head shp_hbolt0 = shp_shank_hbolt0 shp_hbolt1 = shp_hbolt0.copy() # It is in zero shp_hbolt1.Placement.Base.x = sg * hbolt_sep else: rail = min(rail, above_h-profile_size/2.) shp_shank_hbolt0 = fcfun.shp_stadium_dir ( length = rail, radius = holdbolt_d/2. + TOL, height= bolt_shank + 2, fc_axis_l = VZ, fc_axis_h = VY, ref_l = 2, ref_h = 2, pos = pos_shank_hbolt0) if depth > bolt_shank : pos_head_hbolt0 = FreeCAD.Vector(hbolt_p0x, bolt_shank, -profile_size/2.) shp_head_hbolt0 = fcfun.shp_stadium_dir ( length = rail, radius = holdbolthead_d/2. + TOL, height = depth - bolt_shank + 1, fc_axis_l = VZ, fc_axis_h = VY, ref_l = 2, ref_h = 2, pos = pos_head_hbolt0) shp_hbolt0 = shp_shank_hbolt0.fuse(shp_head_hbolt0) else: # no head shp_hbolt0 = shp_shank_hbolt0 shp_hbolt1 = shp_hbolt0.copy() # It is in zero shp_hbolt1.Placement.Base.x = sg * hbolt_sep # hole for the pulley bolt pulleybolt_pos = FreeCAD.Vector (0, depth - pulleydepth/2., above_h - pulleybolt_h) shp_pulleybolt = fcfun.shp_cyl (r = pulleybolt_d/2. + 0.9*TOL/2, h = pulleybolt_h + 1, normal = VZ, pos = pulleybolt_pos) holes_list = [shp_hbolt0, shp_hbolt1] # hole for the nut: # hole for the endstop if endstop_side != 0: #endstopbox_l = endstop_l + 2*TOL #endstopbox_w = endstop_ht + extra_endstop + TOL endstopbox_l = endstop_l + 2*TOL + extra_w + 1 endstopbox_w = depth + 2 #endstop_posx = p1x + sg*(extra_w + endstopbox_l/2.) endstop_posx = p1x - sg*(endstopbox_l/2. -1) endstop_posy = (depth - endstopbox_w ) #endstop_posy = (depth - endstopbox_w ) endstop_posy = -1 endstop_pos = FreeCAD.Vector(endstop_posx, endstop_posy, endstop_posh) shp_endstop = fcfun.shp_boxcen(x=endstopbox_l, y=endstopbox_w, z=above_h-endstop_posh +1, cx=1, pos=endstop_pos) holes_list.append(shp_endstop) # hole for the bolts of the endstop endstopbolt0_pos = FreeCAD.Vector( endstop_posx - endstop_boltsep/2., depth - endstop_bolt2hend, endstop_posh + 1) shp_endstopbolt0 = fcfun.shp_cyl ( r= endstop_bolt_d/2. + TOL/2., h = extra_w + 1, normal = fcfun.VZN, pos=endstopbolt0_pos) holes_list.append(shp_endstopbolt0) shp_endstopbolt1 = shp_endstopbolt0.copy() shp_endstopbolt1.Placement.Base.x = endstop_boltsep holes_list.append(shp_endstopbolt1) shp_holes = shp_pulleybolt.multiFuse(holes_list) shp_pulleyhold = shp_box.cut(shp_holes) pulleyhold_aux = doc.addObject("Part::Feature", name + '_aux') pulleyhold_aux.Shape = shp_pulleyhold # fillet the top part if it has no endstop. So the belt doesnt # hit the corner if endstop_side == 0: fillet_r = (width - pulleynut_d_tol - 2 * extra_w) / 2. pulleyhold_aux = fcfun.filletchamfer( fco = pulleyhold_aux, e_len = depth, name = name + '_chmf', fillet = 1, radius = fillet_r, axis = 'y', zpos_chk = 1, zpos = above_h) h_nuthole = fcfun.NutHole (nut_r = pulleynut_d_tol/2., nut_h = pulleynut_hole_h, hole_h = pulleydepth/2. + TOL, name = name + '_nuthole', extra = 1, nuthole_x = 0, cx = 1, cy = 0, holedown = 0) nuthole = h_nuthole.fco nuthole.Placement.Rotation = FreeCAD.Rotation(VX,-90) nuthole.Placement.Base.y = depth - pulleydepth/2. - TOL nuthole.Placement.Base.z = above_h - extra_w pulley_holder = doc.addObject("Part::Cut", name) pulley_holder.Base = pulleyhold_aux pulley_holder.Tool = nuthole pulley_holder.Placement.Base = pos self.fco = pulley_holder doc.recompute() def color (self, color = (1,1,1)): self.fco.ViewObject.ShapeColor = color
#doc = FreeCAD.newDocument() #idp = IdlePulleyHolder( profile_size=20., # pulleybolt_d=3., # holdbolt_d = 5, # #above_h = 47-15-9.5, # above_h = 35. - 1., # mindepth = 0, # attach_dir = '-y', # endstop_side = 0, # endstop_posh = 0, # name = "idlepulleyhold") #idp = IdlePulleyHolder( profile_size=30., # pulleybolt_d=3., # holdbolt_d = 4, # above_h = 40, # rail = 30, # mindepth = 0, # attach_dir = '-y', # endstop_side = 0, # endstop_posh = 0, # name = "idlepulleyhold") # Holder for the endstop to be attached to the rail of SEB15A_R # Made fast and with hardcoded constants, no parametric def endstopholder_rail (): in_w = kcomp.SEB15A_R['rw'] add_w = 4. #out_w = in_w + 2 * add_w out_w = 36. ends_d = 6. #endstop depth supp_d = 12.5 # support depth total_d = supp_d - ends_d + add_w bolt_h = 18. extra_h = 5. total_h = bolt_h + extra_h + add_w obox = fcfun.shp_boxcenfill(out_w, total_d, total_h, 1, cx=1, cy=0, cz=0) ibox = fcfun.shp_boxcen(in_w + 1.5 * TOL, add_w + 1, total_h + 2, cx=1, cy=0, cz=0, pos = FreeCAD.Vector(0, -1,-1)) endsbolt2top = 7. # distance of the endstop bolt to the top endsboltsep = 9.6 # distance between endstop bolts endsbolt_depth = 5.5 # depth of the holes endsbolt_diam = 2.5 # diameter ends_bolt_pos0 = FreeCAD.Vector ( endsboltsep/2., total_d +1, total_h - endsbolt2top) ends_bolt0 = fcfun.shp_cyl (r=endsbolt_diam/2.+TOL/2., h = endsbolt_depth +1, normal = VYN, pos = ends_bolt_pos0) ends_bolt_pos1 = FreeCAD.Vector ( -endsboltsep/2., total_d +1, total_h - endsbolt2top) ends_bolt1 = fcfun.shp_cyl (r=endsbolt_diam/2.+TOL/2., h = endsbolt_depth +1, normal = VYN, pos = ends_bolt_pos1) ends_bolt_pos00 = FreeCAD.Vector ( endsboltsep*1.5, total_d +1, total_h - endsbolt2top) ends_bolt00 = fcfun.shp_cyl (r=endsbolt_diam/2.+TOL/2., h = endsbolt_depth +1, normal = VYN, pos = ends_bolt_pos00) ends_bolt_pos11 = FreeCAD.Vector ( -endsboltsep*1.5, total_d +1, total_h - endsbolt2top) ends_bolt11 = fcfun.shp_cyl (r=endsbolt_diam/2.+TOL/2., h = endsbolt_depth +1, normal = VYN, pos = ends_bolt_pos11) railbolt_d = 3. railbolt = fcfun.shp_boxcenfill ( x=railbolt_d + 0.8*TOL, y= total_d + 2, z = railbolt_d + extra_h, fillrad = railbolt_d/2., fx = 0, fy=1, fz=0, cx=1, cy=0, cz=0, pos = FreeCAD.Vector(0, -1, add_w)) railbolthead_d = kcomp.D912_HEAD_D[int(railbolt_d)] railbolt_head_pos = FreeCAD.Vector( 0, add_w+3, add_w-railbolthead_d/2. + railbolt_d/2. ) railbolt_head = fcfun.shp_boxcenfill (x=railbolthead_d + TOL, y= total_d + 2, z = railbolthead_d + extra_h, fillrad = railbolthead_d/2., fx = 0, fy=1, fz=0, cx=1, cy=0, cz=0, pos = railbolt_head_pos) shp_fusecut = ibox.multiFuse([ends_bolt0, ends_bolt1, ends_bolt00, ends_bolt11, railbolt, railbolt_head]) box = obox.cut(shp_fusecut) #Part.show (box) return (box)
[docs]class SimpleEndstopHolder (object): """ Very simple endstop holder to be attached to a alu profile and that can be adjusted :: rail_l fc_axis_w ...+.... : : : : ______________________: | ________ | | (________) O | | ________ |-----> fc_axis_d | (________) O | |______________________| : : estp_tot_h ref_d points: fc_axis_h : 1___2______3_______4___5............. ref_h = 2 | :..........: : : |:..... + h |__:________:_____:_:_|:.....base_h.: ref_h = 1 ref_w points fc_axis_w _____________________ : | ________ | |: | (________) ---| 0 |: 1 ________ ---| |:-----> fc_axis_d. 3 (________) ---| 2 |: 4________________|____|: _____________________ ....... | : : : : |:.....: endstop_nut_dist | :..........: : :|: |__:________:____:___:|:..... if endstop_nut_dist == 0 just take the length+TOL of the nut _____________________ | : : : : |: | :..........: : : |:..... |__:________:____:___:|:.....kcomp.NUT_D934_L[estp_bolt_d]+TOL Parameters ---------- d_endstop : Dictionary of the endstop rail_l : float Length of the rail, but only the internal length, not counting the arches to make the semicircles for the bolts just from semicircle center to the other semicircle center h : float Total height, if 0 it will be the minimum height base_h : float Height for the base (for the mounting bolts) holder_out : float The endstop holder can end a little bit before to avoid it to be the endstop mbolt_d : float Diameter (metric) of the mounting bolts (for the holder not for the endstop endstop_nut_dist : Distance from the top to the endstop nut. if zero min_d : int 1: make the endstop axis_d dimension the minimum fc_axis_d : FreeCAD Vector Axis along the depth fc_axis_w : FreeCAD Vector Axis along the width fc_axis_h : FreeCAD Vector Axis along the height ref_d : int Reference (zero) of fc_axis_d * 1 = at the end on the side of the rails * 2 = at the circle center of one rail (closer to 1) * 3 = at the circle center of the other rail, closer to endstop * 4 = at the bolt of the endstop * 5 = at the end of the endstop (the holder ends before that) ref_w : int Reference on fc_axis_w. it is symmetrical, only the negative side * 1 = centered * 2 = at one endstop bolt the other endstop bolt will be on the direction of fc_axis_w * 3 = at one rail center the rail center will be on the direction of fc_axis_w * 4 = at the end the end will be on the direction of fc_axis_w ref_h : int Reference (zero) of fc_axis_h * 1: at the bottom * 2: on top pos : FreeCAD.Vector Object placement wfco : int 1 a freecad object will be created name : str Name of the freecad object, if created the rails can be countersunk to make space for the bolts """ def __init__(self, d_endstop, rail_l = 15, base_h = 5., h = 0, holder_out = 2., #csunk = 1, mbolt_d = 3., endstop_nut_dist = 0, min_d = 0, fc_axis_d = VX, fc_axis_w = V0, fc_axis_h = VZ, ref_d = 1, ref_w = 1, ref_h = 1, pos = V0, wfco = 1, name = 'simple_enstop_holder'): self.wfco = wfco self.name = name self.base_h = base_h, doc = FreeCAD.ActiveDocument # normalize the axis axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) axis_d = DraftVecUtils.scaleTo(fc_axis_d,1) if fc_axis_w == V0: axis_w = axis_h.cross(axis_d) else: axis_w = DraftVecUtils.scaleTo(fc_axis_w,1) axis_h_n = axis_h.negative() axis_d_n = axis_d.negative() axis_w_n = axis_w.negative() self.axis_h = axis_h self.axis_d = axis_d self.axis_w = axis_w # best axis to print, to be pointing up: self.axis_print = axis_h self.d_endstop = d_endstop # :holder_out # __:________:____________: :.................. # | _________ | | : # | (_________) ----| 0 | + tot_w # | _________ ----| |-----> fc_axis_d : # | (_________) ----| 0 | : # |__________________|_____|...................: # : : : : : : : # : :..rail_l.: : : : : # : : : : :.: : # :bolthead_d : : : +estp_bolt_dist # : : : : # bolthead_r: :.......: # : +estp_d # : : # :.estp_tot_d: # :...................._..: : # tot_d # The width depend which side is larger # # ...... ______________________ .... # mbolt_head_r ......| ________ | | : # mbolt_head_d ......| (________) ---| 0 | : #mbolt_head_d or more ......| ________ ---| | + estp_w or more # mbolt_head_d ......| (________) ---| 0 | : # mbolt_head_r ......|________________|_____|....: # it can have a second hole: # : :estop_topbolt_dist # : holder_out # __:________:______________: :.................. # | _________ | | : # | (_________) ----| 0 0 | + tot_w # | _________ ----| |-----> fc_axis_d : # | (_________) ----| 0 0 | : # |__________________|_______|...................: # : : # mounting bolt data d_mbolt = kcomp.D912[int(mbolt_d)] #dictionary of the mounting bolt #print(str(d_mbolt)) mbolt_r_tol = d_mbolt['shank_r_tol'] mbolt_head_r = d_mbolt['head_r'] mbolt_head_r_tol = d_mbolt['head_r_tol'] mbolt_head_l = d_mbolt['head_l'] print (str(mbolt_head_l)) # endstop data. change h->d, d->h, l->w estp_tot_d = d_endstop['HT'] estp_d = d_endstop['H'] estp_bolt_dist = d_endstop['BOLT_H'] estp_bolt_sep = d_endstop['BOLT_SEP'] estp_bolt_d = d_endstop['BOLT_D'] #diameter, not depth estp_w = d_endstop['L'] # if there is a second bolt if 'BOLT_TOP_H' in d_endstop: estop_2ndbolt_topdist = d_endstop['BOLT_TOP_H'] else: estop_2ndbolt_topdist = 0 # length of the pins: estp_pin_d = estp_tot_d - estp_d if min_d == 0: tot_d = 3*mbolt_head_r + rail_l + estp_tot_d - holder_out # nut axis: (nut axis of the hexagon vertex hex_verx = axis_d else: # Taking the minimum lenght, very tight tot_d = (3*mbolt_head_r + rail_l + estp_d - holder_out + estp_pin_d/2.) hex_verx = axis_w # less space # Total width is the largest value from: # - the width(length) of the endstop # - the rail width: 2 bolt head diameters, and 2 more: 1 diameter # between, and a radius to the end tot_w = max(estp_w, 8 * mbolt_head_r) if h== 0: tot_h = base_h + mbolt_head_l else: tot_h = base_h + mbolt_head_l if tot_h > h: logger.debug('h is smaller that it should, taking: ') logger.debug(str(tot_h)) else: tot_h = h self.tot_h = tot_h self.tot_w = tot_w self.tot_d = tot_d if endstop_nut_dist == 0: endstop_nut_l = kcomp.NUT_D934_L[estp_bolt_d]+TOL else: if endstop_nut_dist > tot_h - kcomp.NUT_D934_L[estp_bolt_d]+TOL: logger.debug('endstop_nut_dist: ' + str(endstop_nut_dist) + ' larger than total height - (nut length+tol): ' + str(tot_h) + ' - ' + str( kcomp.NUT_D934_L[estp_bolt_d] + TOL)) endstop_nut_l = kcomp.NUT_D934_L[estp_bolt_d]+TOL else: endstop_nut_l = tot_h - endstop_nut_dist # ------------ DISTANCES ON AXIS_D # ref_d points: fc_axis_h # 1___2______3_______4__.5............. ref_h = 2 # | :..........: : : |:..... + h # |__:________:_____:_:_|:.....base_h.: ref_h = 1 # the end it is not on the holder because of -holder_out # distance from 1 to 2 in axis_d dis_1_2_d = 2* mbolt_head_r dis_1_3_d = dis_1_2_d + rail_l #dis_2_3_d = rail_l dis_1_5_d = tot_d + holder_out dis_1_4_d = dis_1_5_d - (estp_d - estp_bolt_dist) # distances to the new point, that is the second bolt hole, if exists if estop_2ndbolt_topdist > 0 : dis_1_6_d = dis_1_5_d - estop_2ndbolt_topdist else: # same as 4: (to avoid errors) it will be the same hole dis_1_6_d = dis_1_4_d fc_1_2_d = DraftVecUtils.scale(axis_d, dis_1_2_d) fc_1_3_d = DraftVecUtils.scale(axis_d, dis_1_3_d) fc_1_4_d = DraftVecUtils.scale(axis_d, dis_1_4_d) fc_1_5_d = DraftVecUtils.scale(axis_d, dis_1_5_d) fc_1_6_d = DraftVecUtils.scale(axis_d, dis_1_6_d) # vector from the reference point to point 1 on axis_d if ref_d == 1: refto_1_d = V0 elif ref_d == 2: refto_1_d = fc_1_2_d.negative() elif ref_d == 3: refto_1_d = fc_1_3_d.negative() elif ref_d == 4: refto_1_d = fc_1_4_d.negative() elif ref_d == 5: refto_1_d = fc_1_5_d.negative() else: logger.error('wrong reference point') # ------------ DISTANCES ON AXIS_W # ref_w points # fc_axis_w # _____________________ : # | ________ | |: # | (________) ---| 0 |: # 1 ________ ---| |:-----> fc_axis_d. # 3 (________) ---| 2 |: # 4________________|____|: # distance from 1 to 2 on axis_w dis_1_2_w = estp_bolt_sep/2. dis_1_4_w = tot_w/2. dis_1_3_w = dis_1_4_w - 2* mbolt_head_r fc_1_2_w = DraftVecUtils.scale(axis_w_n, dis_1_2_w) fc_1_3_w = DraftVecUtils.scale(axis_w_n, dis_1_3_w) fc_1_4_w = DraftVecUtils.scale(axis_w_n, dis_1_4_w) # vector from the reference point to point 1 on axis_w if ref_w == 1: refto_1_w = V0 elif ref_w == 2: refto_1_w = fc_1_2_w.negative() elif ref_w == 3: refto_1_w = fc_1_3_w.negative() elif ref_w == 4: refto_1_w = fc_1_4_w.negative() else: logger.error('wrong reference point') # ------------ DISTANCES ON AXIS_H fc_1_2_h = DraftVecUtils.scale(axis_h, tot_h) fc_2_1_h = fc_1_2_h.negative() if ref_h == 1: refto_2_h = fc_1_2_h elif ref_h == 2: refto_2_h = V0 else: logger.error('wrong reference point') # Situation of the point on d=1, s=1, h=2 # ____________ # / # * d1_w1_h2 # /____________ # | # # this is an absolute position d1_w1_h2_pos = pos + refto_1_d + refto_1_w + refto_2_h d1_w1_h1_pos = d1_w1_h2_pos + fc_2_1_h # draw the box from this point d1 s1 h2 shp_box = fcfun.shp_box_dir(box_w = tot_w, box_d = tot_d, box_h = tot_h, fc_axis_h = axis_h_n, fc_axis_d = axis_d, cw = 1, cd = 0, ch = 0, pos = d1_w1_h2_pos) shp_box = fcfun.shp_filletchamfer_dir(shp_box, fc_axis = axis_h, fillet=1, radius = 2) holes = [] # holes for the endstop bolts, point: d4 w2 h1 for fc_1_2_wi in [fc_1_2_w, fc_1_2_w.negative()]: pos_estpbolt = d1_w1_h1_pos + fc_1_4_d + fc_1_2_wi # hole with the nut hole shp_estpbolt = fcfun.shp_bolt_dir ( r_shank= (estp_bolt_d+TOL)/2., l_bolt = tot_h, # 1 TOL didnt fit r_head = (kcomp.NUT_D934_D[estp_bolt_d]+2*TOL)/2., l_head = endstop_nut_l, hex_head = 1, xtr_head = 1, xtr_shank = 1, fc_normal = axis_h, fc_verx1 = hex_verx, pos = pos_estpbolt) holes.append(shp_estpbolt) # it can have a second hole if estop_2ndbolt_topdist >0: pos_estp_top_bolt = d1_w1_h1_pos + fc_1_6_d + fc_1_2_wi # hole with the nut hole shp_estpbolt = fcfun.shp_bolt_dir ( r_shank= (estp_bolt_d+TOL)/2., l_bolt = tot_h, # 1 TOL didnt fit r_head = (kcomp.NUT_D934_D[estp_bolt_d]+2*TOL)/2., l_head = endstop_nut_l, hex_head = 1, xtr_head = 1, xtr_shank = 1, fc_normal = axis_h, fc_verx1 = hex_verx, pos = pos_estp_top_bolt) holes.append(shp_estpbolt) # holes for the rails, point d2 w3 h2 for fc_1_3_wi in [fc_1_3_w, fc_1_3_w.negative()]: #hole for the rails, use the function stadium rail_pos = d1_w1_h2_pos + fc_1_2_d + fc_1_3_wi shp_rail_sunk = fcfun.shp_stadium_dir ( length = rail_l, radius = mbolt_head_r_tol, height = mbolt_head_l, fc_axis_l = axis_d, fc_axis_h = axis_h_n, ref_l = 2, #at the center of semicircle ref_s = 1, # symmetrical on the short side ref_h = 2, xtr_h = 0, xtr_nh = 1, pos = rail_pos) shp_rail = fcfun.shp_stadium_dir ( length = rail_l, radius = mbolt_r_tol, height = tot_h, fc_axis_l = axis_d, fc_axis_h = axis_h_n, ref_l = 2, ref_s = 1, ref_h = 2, xtr_h = 1, xtr_nh = 0, pos = rail_pos) holes.append(shp_rail) holes.append(shp_rail_sunk) shp_holes = fcfun.fuseshplist(holes) shp_holder = shp_box.cut(shp_holes) self.shp = shp_holder if wfco == 1: # a freeCAD object is created fco = doc.addObject("Part::Feature", name ) fco.Shape = self.shp self.fco = fco def color (self, color = (1,1,1)): if self.wfco == 1: self.fco.ViewObject.ShapeColor = color else: logger.debug("Object with no fco") # exports the shape to STL format def export_stl (self, name = ""): if not name: name = self.name stlPath = filepath + stl_dir stlFileName = stlPath + name + ".stl" # exportStl not working well with FreeCAD 0.17 #self.fco.Shape.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.fco.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp
#doc = FreeCAD.newDocument() #h_estp = SimpleEndstopHolder( # d_endstop = kcomp.ENDSTOP_D3V, # rail_l = 25, # base_h = 3., # h = 0, # holder_out = 0, # #csunk = 1, # mbolt_d = 4., # endstop_nut_dist = 2., # min_d = 1, # fc_axis_d = VX, # fc_axis_w = V0, # fc_axis_h = VZ, # ref_d = 2, # ref_w = 1, # ref_h = 1, # pos = V0, # wfco = 1, # name = 'simple_endstop_holder') # ----------- thin linear bearing housing with one rail to be attached
[docs]class ThinLinBearHouse1rail (object): """ Makes a housing for a linear bearing, but it is very thin and intented to be attached to one rail, instead of 2 it has to parts, the lower and the upper part :: ________ ______________ | ::...::| | ::........:: | | :: ::| Upper part |.:: ::.| |-::( )::|------ |.:: ::.| --> fc_slide_axis | ::...::| Lower part | ::........:: | |_::___::| ______| :: :: |______ |_::|_|::| |__:_:___::________::__:_:__| : _________ : |____O____| v | 0: :0 | fc_bot_axis | : : | | : : | | : : | | :.....: | |__0:_:0__| |____O____| ________ ______________ | ::...::| | ::........:: | | :: ::| Upper part |.:: ::.| |-::( )::|------ |.:: *axis_center = 1 | ::...::| Lower part | ::........:: | |_::___::| ______| :: :: |______ |_::|_|::| |__:_:___::___*____::__:_:__| | axis_center = 0 | V always centered in this axis ______________ 1: axis_center=1 | ::........:: | mid_center =1 |.:: ::.| 2: axis_center=0 4 |.:: 1 --> fc_slide_axis mid_center =1 | ::........:: | 3: axis_center=0 ______| :: :: |______ mid_center =0 |_:3:___::___2____::__:_:__| 4: axis_center=1 mid_center =0 Parameters ---------- d_lbear : dictionary Dictionary with the dimensions of the linear bearing fc_slide_axis : FreeCAD.Vector Direction of the slide fc_bot_axis : FreeCAD.Vector Direction of the bottom axis_center : int See picture, indicates the reference point mid_center : int See picture, indicates the reference point pos : FreeCAD.Vector Position of the reference point, Attributes ---------- n1_slide_axis : FreeCAD.Vector n1_bot_axis : FreeCAD.Vector n1_perp : FreeCAD.Vector axis_h : float boltcen_axis_dist : float boltcen_perp_dist : float Dimensions: * tot_h, tot_w, tot_l * housing_l, base_h FreeCAD objects: * fco_top : Top part of the linear bearing housing * fco_bot : Bottom part of the linear bearing housing :: ________ ______________ | ::...::| | ::........:: | | :: ::| |.:: ::.| |-::( )::|---: |.:: ::.| --> n1_slide_axis | ::...::| +axis_h | ::........:: | |_::___::| : ______| :: :: |______ |_::|_|::|...: |__:_:___::________::__:_:__| : _________ v |____O____| n1_bot_axis | 0: :0 | | : : | | : : |---+ boltcen_axis_dist .. --> n1_perp | : : | : : | :.....: | : + boltrailcen_dist |__0:_:0__|---- : |____O____|------------------------: : : : : :...: +boltcen_perp_dist ....housing_l.. : : ________.... :______________: | ::...::| : | ::........:: | | :: ::| : |.:: ::.| |-::( )::| : |.:: ::.| --> n1_slide_axis | ::...::| +tot_h | ::........:: | |_::___::| : ... ______| :: :: |______ |_::|_|::|...: base_h ...|__:_:___::________::__:_:__| : : : : :........: :...........................: + + tot_w tot_l """ MIN_SEP_WALL = 3. # min separation of a wall MIN2_SEP_WALL = 2. # min separation of a wall OUT_SEP_H = kparts.OUT_SEP_H MTOL = kparts.MTOL MLTOL = kparts.MLTOL TOL_BEARING_L = kparts.TOL_BEARING_L # Radius to fillet the sides FILLT_R = kparts.FILLT_R def __init__(self, d_lbear, fc_slide_axis = VX, fc_bot_axis =VZN, axis_center = 1, mid_center = 1, pos = V0, name = 'thinlinbearhouse1rail' ): # normalize, just in case n1_slide_axis = DraftVecUtils.scaleTo(fc_slide_axis,1) n1_bot_axis = DraftVecUtils.scaleTo(fc_bot_axis,1) n1_bot_axis_neg = DraftVecUtils.neg(n1_bot_axis) # vector perpendicular to the others n1_perp = n1_slide_axis.cross(n1_bot_axis) rod_d = d_lbear['Di'] self.rod_r = d_lbear['Di']/2. rod_r = self.rod_r self.bear_r = d_lbear['Di'] if rod_d >= 12: BOLT_D = 4 else: BOLT_D = 3 # M3 bolts doc = FreeCAD.ActiveDocument MIN_SEP_WALL = self.MIN_SEP_WALL MIN2_SEP_WALL = self.MIN2_SEP_WALL OUT_SEP_H = self.OUT_SEP_H # bolt dimensions: MTOL = self.MTOL MLTOL = self.MLTOL BOLT_HEAD_R = kcomp.D912_HEAD_D[BOLT_D] / 2.0 BOLT_HEAD_L = kcomp.D912_HEAD_L[BOLT_D] + MTOL BOLT_HEAD_R_TOL = BOLT_HEAD_R + MTOL # More toler/2.0 BOLT_SHANK_R_TOL = BOLT_D / 2.0 + MTOL # more tolerance: MTOL/2. BOLT_NUT_R = kcomp.NUT_D934_D[BOLT_D] / 2.0 BOLT_NUT_L = kcomp.NUT_D934_L[BOLT_D] + MTOL # 1.5 TOL because diameter values are minimum, so they may be larger BOLT_NUT_R_TOL = BOLT_NUT_R + 1.5*MTOL # bearing dimensions: bearing_l = d_lbear['L'] bearing_l_tol = bearing_l + self.TOL_BEARING_L bearing_d = d_lbear['De'] bearing_d_tol = bearing_d + 2.0 * self.MLTOL bearing_r = bearing_d / 2.0 bearing_r_tol = bearing_r + self.MLTOL #There are two basic pieces: the base and the housing for the linear # bearing # dimensions of the housing: # length on the direction of the sliding rod bolt2wall = fcfun.get_bolt_end_sep(BOLT_D, hasnut=1) #housing_l = bearing_l_tol + 2 * (2*BOLT_HEAD_R_TOL + 2* MIN_SEP_WALL) housing_l = bearing_l_tol + 2 * (2* bolt2wall) print ("housing_l: %", housing_l) # width of the housing (very tight) if rod_d > 8 : housing_w = max ((bearing_d_tol + 2* MIN_SEP_WALL), (d_lbear['Di'] + 4* MIN2_SEP_WALL + 2*BOLT_D)) else: # 8 is very thight housing_w = max ((bearing_d_tol + 2* MIN_SEP_WALL), (d_lbear['Di'] + 4* MIN_SEP_WALL + 2*BOLT_D)) print ("housing_w: %", housing_w) # dimensions of the base: # length on the direction of the sliding rod base_l = housing_l + 4* MIN_SEP_WALL + 4 * BOLT_HEAD_R_TOL print ("base_l: %", base_l) # width of the base (very tight), the same as the housing base_w = housing_w print ("base_w: %", base_w) # height of the base (not tight). twice the mininum height base_h = 2 * OUT_SEP_H print ("base_h: %", base_h) # height of the housing (not tight, can be large) housing_h = base_h + 2* BOLT_HEAD_L + bearing_d_tol print ("housing_h: %", housing_h) # distance on the slide_axis from midcenter=0 to midcenter 1. # the bolt to join the housing to the rail boltrailcen_dist = housing_l/2. + BOLT_HEAD_R_TOL + MIN_SEP_WALL # distance on the bot_axis from the rod to the bottom # the base and the housing are overlapped. # Not taking the tolerance #axis_h = bearing_d/2. + 2 * OUT_SEP_H + BOLT_HEAD_L axis_h = ( rod_r + kparts.ROD_SPACE_MIN + base_h + 2 * BOLT_HEAD_L) #To make the boxes, we take the reference on midcenter=1 and # axis_center = 0. Point 2 on the drawing if mid_center == 0: # get the vector to the center: fc_tomidcenter = DraftVecUtils.scale(n1_slide_axis,boltrailcen_dist) else: fc_tomidcenter = V0 if axis_center == 1: fc_tobottom = DraftVecUtils.scale(n1_bot_axis,axis_h) fc_toaxis = V0 else: fc_tobottom = V0 fc_toaxis = DraftVecUtils.scale(n1_bot_axis,-axis_h) botcenter_pos = pos + fc_tomidcenter + fc_tobottom # point 1 on the drawing axiscenter_pos = pos + fc_tomidcenter + fc_toaxis shp_base = fcfun.shp_box_dir(box_w = base_w, box_d = base_l, #dir of n1_slide_axis box_h = base_h, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = botcenter_pos) # fillet the base: shp_base_fllt = fcfun.shp_filletchamfer_dir(shp_base, fc_axis=fc_bot_axis, radius=kparts.FILLT_R) shp_housing = fcfun.shp_box_dir(box_w = housing_w, box_d = housing_l, #dir of n1_slide_axis box_h = housing_h, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = botcenter_pos) #Part.show(shp_housing) shp_block = shp_base_fllt.fuse(shp_housing) # the rod hole shp_rod = fcfun.shp_cylcenxtr(r = rod_r + kparts.ROD_SPACE_MIN, h = base_l, normal = n1_slide_axis, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) # the linear bearing hole shp_lbear = fcfun.shp_cylcenxtr(r = bearing_r_tol, h = bearing_l_tol, normal = n1_slide_axis, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) shp_rodlbear = shp_rod.fuse(shp_lbear) shp_block_hole = shp_block.cut(shp_rodlbear) # bolts to atach to the support bolt1_atch_pos = ( botcenter_pos + DraftVecUtils.scale(n1_slide_axis,boltrailcen_dist)) bolt2_atch_pos = ( botcenter_pos + DraftVecUtils.scale(n1_slide_axis,-boltrailcen_dist)) print('shank tol' + str(BOLT_SHANK_R_TOL)) shp_bolt1_atch = fcfun.shp_cylcenxtr(r=BOLT_SHANK_R_TOL, h = base_h, normal = n1_bot_axis_neg, ch = 0, xtr_top = 1, xtr_bot = 1, pos = bolt1_atch_pos) shp_bolt2_atch = fcfun.shp_cylcenxtr(r=BOLT_SHANK_R_TOL, h = base_h, normal = n1_bot_axis_neg, ch = 0, xtr_top = 1, xtr_bot = 1, pos = bolt2_atch_pos) bolt_holes = [shp_bolt2_atch] # 4 bolts to join the upper and lower parts # distance of the bolts to the center, on n1_slide_axis dir boltcen_axis_dist = housing_l/2. - bolt2wall # distance of the bolts to the center, on n1_perp dir boltcen_perp_dist = housing_w/2. - bolt2wall for vec_axis in [DraftVecUtils.scale(n1_slide_axis,boltcen_axis_dist), DraftVecUtils.scale(n1_slide_axis,-boltcen_axis_dist)]: for vec_perp in [DraftVecUtils.scale(n1_perp, boltcen_perp_dist), DraftVecUtils.scale(n1_perp, -boltcen_perp_dist)]: pos_i = botcenter_pos + vec_axis + vec_perp # the nut hole will be on the bottom side, shp_bolt = fcfun.shp_boltnut_dir_hole ( r_shank = BOLT_SHANK_R_TOL, l_bolt = housing_h, r_head = BOLT_HEAD_R_TOL, l_head = BOLT_HEAD_L, r_nut = BOLT_NUT_R_TOL, # more space, because we want it well inside l_nut = 1.5*BOLT_NUT_L, hex_head = 0, xtr_head=1, xtr_nut=1, supp_head=1, supp_nut=1, headstart=0, fc_normal = n1_bot_axis_neg, fc_verx1=V0, pos = pos_i) bolt_holes.append(shp_bolt) # ----------------- Attributes self.n1_slide_axis = n1_slide_axis self.n1_bot_axis = n1_bot_axis self.n1_perp = n1_perp self.axis_h = axis_h self.boltcen_axis_dist = boltcen_axis_dist self.boltcen_perp_dist = boltcen_perp_dist self.tot_h = housing_h self.tot_w = housing_w # == base_w self.tot_l = base_l self.housing_l = housing_l self.base_h = base_h shp_bolt_holes = shp_bolt1_atch.multiFuse(bolt_holes) shp_lbear_housing = shp_block_hole.cut(shp_bolt_holes) doc.recompute() # making 2 parts, intersection with 2 boxes: shp_box_top = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_l + 2, box_h = housing_h /2. + 2, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = axiscenter_pos) shp_lbear_housing_top = shp_lbear_housing.common(shp_box_top) shp_lbear_housing_top = shp_lbear_housing_top.removeSplitter() fco_lbear_top = doc.addObject("Part::Feature", name + '_' + str(rod_d) + '_top') fco_lbear_top.Shape = shp_lbear_housing_top shp_box_bot = fcfun.shp_box_dir( box_w = base_w + 2, box_d = base_l + 2, # larger, just in case box_h = housing_h/2. + base_h + 2, fc_axis_h = n1_bot_axis, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = axiscenter_pos) shp_lbear_housing_bot = shp_lbear_housing.common(shp_box_bot) shp_lbear_housing_bot = shp_lbear_housing_bot.removeSplitter() fco_lbear_bot = doc.addObject("Part::Feature", name + '_' + str(rod_d) + '_bot') fco_lbear_bot.Shape = shp_lbear_housing_bot self.fco_top = fco_lbear_top self.fco_bot = fco_lbear_bot def color (self, color = (1,1,1)): self.fco_top.ViewObject.ShapeColor = color self.fco_bot.ViewObject.ShapeColor = color
#doc = FreeCAD.newDocument() #ThinLinBearHouse1rail (kcomp.LMUU[8]) #ThinLinBearHouse (kcomp.LMEUU[10], mid_center=0) # ----------- thin linear bearing housing with one rail to be attached
[docs]class ThinLinBearHouse (object): """ Makes a housing for a linear bearing, but it is very thin and intented to be attached to 2 rail it has to parts, the lower and the upper part :: ________ ______________ | ::...::| | ::........:: | | :: ::| Upper part |.:: ::.| |-::( )::|------ |.:: ::.| --> fc_slide_axis | ::...::| Lower part | ::........:: | |_::___::| |_::________::_| : : _________ v | 0: :0 | fc_bot_axis | : : | | : : | | : : |--------> fc_perp_axis | : : | | :.....: | |__0:_:0__| ________ ______________ | ::...::| | ::........:: | | :: ::| Upper part |.:: ::.| |-::( )::|------> fc_perp_axis |.:: *axis_center = 1 | ::...::| Lower part | ::........:: | |_::___::| |_::___*____::_| | | axis_center = 0 | | V V centered in any of these axes ______________ 1: axis_center=1 | ::........:: | mid_center =1 |.:: ::.| 2: axis_center=0 |.:4 1 --> fc_slide_axis mid_center =1 | ::........:: | 3: axis_center=0 | :: :: | mid_center =0 |_:3___2____::_| 4: axis_center=1 And 8 more posibilities: 5: bolt_center = 1 6: bolt_center = 0 _________ | 5:6: | | : : | | : : | | : : |--------> fc_perp_axis | : : | | :.....: | |__0:_:0__| mid_center =0 Parameters ---------- d_lbear : dictionary Dictionary with the dimensions of the linear bearing fc_slide_axis : FreeCAD.Vector Direction of the slide fc_bot_axis : FreeCAD.Vector Direction of the bottom fc_perp_axis : FreeCAD.Vector Direction of the other perpendicular direction. Not useful unless bolt_center == 1 if = V0 it doesn't matter axis_h : int Distance from the bottom to the rod axis * 0: take the minimum distance * X: (any value) take that value, if it is smaller than the minimum it will raise an error and would not take that value bolts_side : int See picture, indicates the side where is bolt axis_center : int See picture, indicates the reference point mid_center : int See picture, indicates the reference point bolt_center : int See picture, indicates the reference point, if it is on the bolt or on the axis pos : FreeCAD.Vector Position of the reference point, Attributes ---------- n1_slide_axis : FreeCAD.Vector n1_bot_axis : FreeCAD.Vector n1_perp : FreeCAD.Vector axis_h : float boltcen_axis_dist : float boltcen_perp_dist : float Dimensions: * H, W, L FreeCAD objects: * fco_top : Top part of the linear bearing housing * fco_bot : Bottom part of the linear bearing housing :: ________ ______________ | ::...::| | ::........:: | | :: ::| |.:: ::.| |-::( )::|---: |.:: ::.| --> n1_slide_axis | ::...::| +axis_h | ::........:: | |_::___::| : | :: :: | |_::___::|...: |_::________::_| : v _________ n1_bot_axis | 0: :0 | | : : | | : : |........ --> n1_perp | : : | : | :.....: | + boltcen_axis_dist |__0:_:0__|---: : : : : :...: +boltcen_perp_dist ...... L ....... : : ________.... :______________: | ::...::| : | ::........:: | | :: ::| : |.:: ::.| |-::( )::| : |.:: ::.| --> n1_slide_axis | ::...::| + H | ::........:: | |_::___::|...: |_::________::_| : : :........: + W bolts_side = 0 bolts_side = 1 _________ | 0: :0 | ___________ | : : | | 0: :0 | | : : | | : : | | : : | | : : | | :.....: | |_0:_____:0_| |__0:_:0__| """ MIN_SEP_WALL = 3. # min separation of a wall MIN2_SEP_WALL = 2. # min separation of a wall OUT_SEP_H = kparts.OUT_SEP_H # minimun separation of the linear bearing MTOL = kparts.MTOL MLTOL = kparts.MLTOL TOL_BEARING_L = kparts.TOL_BEARING_L # Radius to fillet the sides FILLT_R = kparts.FILLT_R def __init__(self, d_lbear, fc_slide_axis = VX, fc_bot_axis =VZN, fc_perp_axis = V0, axis_h = 0, bolts_side = 1, axis_center = 1, mid_center = 1, bolt_center = 0, pos = V0, name = 'thinlinbearhouse' ): self.name = name self.base_place = (0,0,0) # normalize, just in case n1_slide_axis = DraftVecUtils.scaleTo(fc_slide_axis,1) n1_bot_axis = DraftVecUtils.scaleTo(fc_bot_axis,1) n1_bot_axis_neg = DraftVecUtils.neg(n1_bot_axis) # vector perpendicular to the others v_cross = n1_slide_axis.cross(n1_bot_axis) if fc_perp_axis == V0: n1_perp = v_cross else: n1_perp = DraftVecUtils.scaleTo(fc_perp_axis,1) if not fcfun.fc_isparal (v_cross,n1_perp): logger.debug("fc_perp_axis not perpendicular") n1_perp = v_cross self.rod_r = d_lbear['Di']/2. rod_r = self.rod_r self.bear_r = d_lbear['Di'] if rod_r >= 6: BOLT_D = 4 else: BOLT_D = 3 # M3 bolts doc = FreeCAD.ActiveDocument MIN_SEP_WALL = self.MIN_SEP_WALL MIN2_SEP_WALL = self.MIN2_SEP_WALL OUT_SEP_H = self.OUT_SEP_H # bolt dimensions: MTOL = self.MTOL MLTOL = self.MLTOL BOLT_HEAD_R = kcomp.D912_HEAD_D[BOLT_D] / 2.0 BOLT_HEAD_L = kcomp.D912_HEAD_L[BOLT_D] + MTOL BOLT_HEAD_R_TOL = BOLT_HEAD_R + MTOL/2.0 BOLT_SHANK_R_TOL = BOLT_D / 2.0 + MTOL/2.0 # bearing dimensions: bearing_l = d_lbear['L'] bearing_l_tol = bearing_l + self.TOL_BEARING_L bearing_d = d_lbear['De'] bearing_d_tol = bearing_d + 2.0 * self.MLTOL bearing_r = bearing_d / 2.0 bearing_r_tol = bearing_r + self.MLTOL # dimensions of the housing: # length on the direction of the sliding rod bolt2wall = fcfun.get_bolt_end_sep(BOLT_D, hasnut=0) #housing_l = bearing_l_tol + 2 * (2*BOLT_HEAD_R_TOL + 2* MIN_SEP_WALL) if bolts_side == 1: # bolts on the side of the linear bearing # bolt2axis: distance from the center (axis) to the bolt center bolt2axis = fcfun.get_bolt_bearing_sep (BOLT_D, hasnut=0, lbearing_r = bearing_r) # it will be shorter (on L), and wider (on W) housing_l = bearing_l + 2 * MIN_SEP_WALL housing_w = 2 * (bolt2wall + bolt2axis) else: # bolts after the linear bearing # it will be longer (on L), and shorter (on W) bolt2axis = fcfun.get_bolt_bearing_sep (BOLT_D, hasnut=0, lbearing_r = rod_r ) #lbearing_r = rod_r + kparts.ROD_SPACE_MIN) housing_l = bearing_l + 4*bolt2wall #bolt_r is included in bolt2wall housing_w = max ((bearing_d + 2* MIN_SEP_WALL), 2 * (bolt2wall + bolt2axis)) print("housing_l: %", housing_l) print("housing_w: %", housing_w) # bolt distance # distance of the bolts to the center, on n1_slide_axis dir boltcen_axis_dist = housing_l/2. - bolt2wall # distance of the bolts to the center, on n1_perp dir boltcen_perp_dist = bolt2axis # minimum height of the housing housing_min_h = bearing_d + 2 * OUT_SEP_H axis_min_h = housing_min_h / 2. print("min housing_h: %", housing_min_h) if axis_h == 0: # minimum values housing_h = housing_min_h axis_h = axis_min_h elif axis_h >= axis_min_h: # the lower part will have longer height: axis_h # the upper part will be the minimum: axis_min_h housing_h = axis_h + axis_min_h axis_h = axis_h else: # the argument has an axis_h lower than the minimum possible logger.debug("axis_h %s cannot be smaller than %s", str(axis_h), str(axis_min_h)) housing_h = housing_min_h axis_h = axis_min_h # Atributes self.L = housing_l self.W = housing_w self.H = housing_h self.axis_h = axis_h self.boltcen_axis_dist = boltcen_axis_dist self.boltcen_perp_dist = boltcen_perp_dist self.n1_slide_axis = n1_slide_axis self.n1_bot_axis = n1_bot_axis self.n1_perp = n1_perp #To make the boxes, we take the reference on midcenter=1 and # axis_center = 0. Point 2 on the drawing if mid_center == 0: # get the vector to the center: fc_tomidcenter = DraftVecUtils.scale(n1_slide_axis, boltcen_axis_dist) else: fc_tomidcenter = V0 if axis_center == 1: fc_tobottom = DraftVecUtils.scale(n1_bot_axis,axis_h) fc_toaxis = V0 else: fc_tobottom = V0 fc_toaxis = DraftVecUtils.scale(n1_bot_axis,-axis_h) if bolt_center == 1: fc_toaxis_perp = DraftVecUtils.scale(n1_perp, boltcen_perp_dist) else: fc_toaxis_perp = V0 botcenter_pos = pos + fc_tomidcenter + fc_tobottom + fc_toaxis_perp # point 1 on the drawing axiscenter_pos = pos + fc_tomidcenter + fc_toaxis + fc_toaxis_perp # center on the top topcenter_pos = botcenter_pos + DraftVecUtils.scale(n1_bot_axis_neg, housing_h) shp_housing = fcfun.shp_box_dir(box_w = housing_w, box_d = housing_l, #dir of n1_slide_axis box_h = housing_h, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = botcenter_pos) # fillet, small shp_block = fcfun.shp_filletchamfer_dir(shp_housing, fc_axis=fc_bot_axis, radius=2) # the rod hole shp_rod = fcfun.shp_cylcenxtr(r = rod_r + kparts.ROD_SPACE_MIN, h = housing_l, normal = n1_slide_axis, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) # the linear bearing hole shp_lbear = fcfun.shp_cylcenxtr(r = bearing_r_tol, h = bearing_l_tol, normal = n1_slide_axis, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) shp_rodlbear = shp_rod.fuse(shp_lbear) # 4 bolts bolt_holes = [] for vec_axis in [DraftVecUtils.scale(n1_slide_axis,boltcen_axis_dist), DraftVecUtils.scale(n1_slide_axis,-boltcen_axis_dist)]: for vec_perp in [DraftVecUtils.scale(n1_perp, boltcen_perp_dist), DraftVecUtils.scale(n1_perp, -boltcen_perp_dist)]: pos_i = topcenter_pos + vec_axis + vec_perp # the nut hole will be on the bottom side, shp_bolt = fcfun.shp_bolt_dir ( r_shank = BOLT_SHANK_R_TOL, l_bolt = housing_h, r_head = BOLT_HEAD_R_TOL, l_head = BOLT_HEAD_L, hex_head = 0, xtr_head=1, xtr_shank=1, support=1, fc_normal = n1_bot_axis, fc_verx1=V0, pos = pos_i) bolt_holes.append(shp_bolt) shp_holes = shp_rodlbear.multiFuse(bolt_holes) shp_lbear_housing = shp_block.cut(shp_holes) doc.recompute() # making 2 parts, intersection with 2 boxes: shp_box_top = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_l + 2, box_h = housing_h - axis_h + 1, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = axiscenter_pos) shp_lbear_housing_top = shp_lbear_housing.common(shp_box_top) shp_lbear_housing_top = shp_lbear_housing_top.removeSplitter() fco_lbear_top = doc.addObject("Part::Feature", name + '_top') fco_lbear_top.Shape = shp_lbear_housing_top shp_box_bot = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_l + 2, # larger, just in case box_h = axis_h + 1, fc_axis_h = n1_bot_axis, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = axiscenter_pos) shp_lbear_housing_bot = shp_lbear_housing.common(shp_box_bot) shp_lbear_housing_bot = shp_lbear_housing_bot.removeSplitter() fco_lbear_bot = doc.addObject("Part::Feature", name + '_bot') fco_lbear_bot.Shape = shp_lbear_housing_bot self.fco_top = fco_lbear_top self.fco_bot = fco_lbear_bot def BasePlace (self, position = (0,0,0)): self.base_place = position vpos = FreeCAD.Vector(position) self.fco_top.Placement.Base = vpos self.fco_bot.Placement.Base = vpos def color (self, color = (1,1,1)): self.fco_top.ViewObject.ShapeColor = color self.fco_bot.ViewObject.ShapeColor = color def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name stlPath = filepath + stl_dir stlFileName_top = stlPath + name + "_top" + ".stl" stlFileName_bot = stlPath + name + "_bot" + ".stl" # exportStl not working well with FreeCAD 0.17 #self.fco_top.Shape.exportStl(stlFileName_top) #self.fco_bot.Shape.exportStl(stlFileName_bot) # this would work: #Mesh.export([self.fco_top], stlFileName_top) #Mesh.export([self.fco_bot], stlFileName_bot) mesh_shp_top = MeshPart.meshFromShape(self.fco_top.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp_top.write(stlFileName_top) del mesh_shp_top mesh_shp_bot = MeshPart.meshFromShape(self.fco_bot.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp_bot.write(stlFileName_bot) del mesh_shp_bot
#AAAAAAA #doc = FreeCAD.newDocument() #ThinLinBearHouse (kcomp.LMEUU[10]) #ThinLinBearHouse (kcomp.LMEUU[10], mid_center=1) #ThinLinBearHouse (kcomp.LMEUU[10], bolts_side=0, mid_center=1) #ThinLinBearHouse (kcomp.LMEUU[10], axis_h = 10, bolts_side=0, mid_center=1) #ThinLinBearHouse (kcomp.LMEUU[10], axis_h = 15, bolts_side=0, mid_center=1) #ThinLinBearHouse (kcomp.LMEUU[12], axis_h = 0, bolts_side=0, mid_center=1) #ThinLinBearHouse (kcomp.LMELUU[12], axis_h = 0, bolts_side=0, mid_center=1) #ThinLinBearHouse (kcomp.LMELUU[12], axis_h = 0, bolts_side=1, mid_center=1) #ThinLinBearHouse (kcomp.LMEUU[12], # fc_slide_axis = VY, # fc_bot_axis = VZN, # fc_perp_axis = VX, # axis_h = 0, bolts_side=0, mid_center=1, bolt_center = 1) #ThinLinBearHouse (kcomp.LMELUU[12], # fc_slide_axis = VY, # fc_bot_axis = VZN, # fc_perp_axis = VXN, # axis_h = 0, bolts_side=0, mid_center=1, bolt_center = 1) #ThinLinBearHouse (kcomp.LMELUU[12], # fc_slide_axis = VX, # fc_bot_axis = VZN, # fc_perp_axis = VYN, # axis_h = 0, bolts_side=1, # axis_center=0, mid_center=0, bolt_center = 1) # ----------- Linear bearing housing
[docs]class LinBearHouse (object): """ Makes a housing for a linear bearing takes the dimensions from a dictionary, like the one defined in kcomp.py it has to parts, the lower and the upper part :: _____________ ______________ |:: ___ ::| |.::........::.| |:: / \ ::| Upper part | :: :: | |---|-----|---|------ | :: :: | |:: \___/ ::| Lower part |.::........::.| |::_________::| |_::________::_| _____________ | 0 : : 0 | | : : | | : : | | : : | | : : | |_0_:_____:_0_| ________________ 1: axis_center=1 | : :........: : | mid_center =1 |.: : : :.| 2: axis_center=0 |.:4: 1 --------->: fc_slide_axis mid_center =1 | : :........:.: | 3: axis_center=0 | : : : : | mid_center =0 |_:3:___2____:_:_| 4: axis_center=1 mid_center =0 """ MTOL = kparts.MTOL MLTOL = kparts.MLTOL TOL_BEARING_L = kparts.TOL_BEARING_L # Radius to fillet the sides FILLT_R = kparts.FILLT_R def __init__(self, d_lbearhousing, fc_slide_axis = VX, fc_bot_axis =VZN, axis_center = 1, mid_center = 1, pos = V0, name = 'linbearhouse' ): housing_l = d_lbearhousing['L'] housing_w = d_lbearhousing['W'] housing_h = d_lbearhousing['H'] self.L = housing_l self.W = housing_w self.H = housing_h self.axis_h = d_lbearhousing['axis_h'] self.bolt_sep_l = d_lbearhousing['bolt_sep_l'] self.bolt_sep_w = d_lbearhousing['bolt_sep_w'] self.bolt_d = d_lbearhousing['bolt_d'] axis_h = self.axis_h self.name = name # normalize, just in case they are not n1_slide_axis = DraftVecUtils.scaleTo(fc_slide_axis,1) n1_bot_axis = DraftVecUtils.scaleTo(fc_bot_axis,1) n1_bot_axis_neg = DraftVecUtils.neg(n1_bot_axis) # vector perpendicular to the others n1_perp = n1_slide_axis.cross(n1_bot_axis) # get the linear bearing dictionary d_lbear = d_lbearhousing['lbear'] self.rod_r = d_lbear['Di']/2. rod_r = self.rod_r self.bear_r = d_lbear['Di'] bolt_d = d_lbearhousing['bolt_d'] doc = FreeCAD.ActiveDocument # bolt dimensions: MTOL = self.MTOL MLTOL = self.MLTOL BOLT_HEAD_R = kcomp.D912_HEAD_D[bolt_d] / 2.0 BOLT_HEAD_L = kcomp.D912_HEAD_L[bolt_d] + MTOL BOLT_HEAD_R_TOL = BOLT_HEAD_R + MTOL/2.0 BOLT_SHANK_R_TOL = bolt_d / 2.0 + MTOL/2.0 # bearing dimensions: bearing_l = d_lbear['L'] bearing_l_tol = bearing_l + self.TOL_BEARING_L bearing_d = d_lbear['De'] bearing_d_tol = bearing_d + 2.0 * self.MLTOL bearing_r = bearing_d / 2.0 bearing_r_tol = bearing_r + self.MLTOL cenbolt_dist_l = d_lbearhousing['bolt_sep_l']/2. cenbolt_dist_w = d_lbearhousing['bolt_sep_w']/2. #To make the boxes, we take the reference on midcenter=1 and # axis_center = 0. Point 2 on the drawing if mid_center == 0: # get the vector to the center: fc_tomidcenter = DraftVecUtils.scale(n1_slide_axis,cenbolt_dist_l) else: fc_tomidcenter = V0 if axis_center == 1: fc_tobottom = DraftVecUtils.scale(n1_bot_axis,axis_h) fc_toaxis = V0 else: fc_tobottom = V0 fc_toaxis = DraftVecUtils.scale(n1_bot_axis,-axis_h) # point 2 on the drawing botcenter_pos = pos + fc_tomidcenter + fc_tobottom # point 1 on the drawing axiscenter_pos = pos + fc_tomidcenter + fc_toaxis # center on top topcenter_pos = botcenter_pos + DraftVecUtils.scale(n1_bot_axis_neg, housing_h) shp_housing = fcfun.shp_box_dir(box_w = housing_w, box_d = housing_l, #dir of n1_slide_axis box_h = housing_h, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = botcenter_pos) # fillet the base: shp_housing_fllt = fcfun.shp_filletchamfer_dir(shp_housing, fc_axis=fc_bot_axis, radius=2) # the rod hole shp_rod = fcfun.shp_cylcenxtr(r = rod_r + kparts.ROD_SPACE_MIN, h = housing_l, normal = n1_slide_axis, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) # the linear bearing hole shp_lbear = fcfun.shp_cylcenxtr(r = bearing_r_tol, h = bearing_l_tol, normal = n1_slide_axis, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) shp_rodlbear = shp_rod.fuse(shp_lbear) # 4 bolts to join the upper and lower parts # distance of the bolts to the center, on n1_slide_axis dir bolt_holes = [] for vec_axis in [DraftVecUtils.scale(n1_slide_axis,cenbolt_dist_l), DraftVecUtils.scale(n1_slide_axis,-cenbolt_dist_l)]: for vec_perp in [DraftVecUtils.scale(n1_perp, cenbolt_dist_w), DraftVecUtils.scale(n1_perp, -cenbolt_dist_w)]: pos_i = topcenter_pos + vec_axis + vec_perp # the nut hole will be on the bottom side, shp_bolt = fcfun.shp_bolt_dir ( r_shank = BOLT_SHANK_R_TOL, l_bolt = housing_h, r_head = BOLT_HEAD_R_TOL, l_head = BOLT_HEAD_L, hex_head = 0, xtr_head=1, xtr_shank=1, support=1, fc_normal = n1_bot_axis, fc_verx1=V0, pos = pos_i) bolt_holes.append(shp_bolt) shp_holes = shp_rodlbear.multiFuse(bolt_holes) shp_lbear_housing = shp_housing_fllt.cut(shp_holes) #Part.show(shp_lbear_housing) doc.recompute() # making 2 parts, intersection with 2 boxes: shp_box_top = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_l + 2, box_h = housing_h - axis_h + 2, fc_axis_h = n1_bot_axis_neg, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = axiscenter_pos) shp_lbear_housing_top = shp_lbear_housing.common(shp_box_top) shp_lbear_housing_top = shp_lbear_housing_top.removeSplitter() fco_lbear_top = doc.addObject("Part::Feature", name + '_top') fco_lbear_top.Shape = shp_lbear_housing_top shp_box_bot = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_l + 2, # larger, just in case box_h = axis_h + 2, fc_axis_h = n1_bot_axis, fc_axis_d = n1_slide_axis, cw= 1, cd=1, ch=0, pos = axiscenter_pos) shp_lbear_housing_bot = shp_lbear_housing.common(shp_box_bot) shp_lbear_housing_bot = shp_lbear_housing_bot.removeSplitter() fco_lbear_bot = doc.addObject("Part::Feature", name + '_bot') fco_lbear_bot.Shape = shp_lbear_housing_bot self.fco_top = fco_lbear_top self.fco_bot = fco_lbear_bot doc.recompute() def color (self, color = (1,1,1)): self.fco_top.ViewObject.ShapeColor = color self.fco_bot.ViewObject.ShapeColor = color def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name #stlPath = filepath + "/freecad/stl/" stlPath = filepath + stl_dir stlFileName_top = stlPath + name + "_top" + ".stl" stlFileName_bot = stlPath + name + "_bot" + ".stl" # exportStl not working well with FreeCAD 0.17 #self.fco_top.Shape.exportStl(stlFileName_top) # this would be valid #Mesh.export([self.fco_top], stlFileName_top) mesh_shp_top = MeshPart.meshFromShape(self.fco_top.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp_top.write(stlFileName_top) del mesh_shp_top mesh_shp_bot = MeshPart.meshFromShape(self.fco_bot.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp_bot.write(stlFileName_bot) del mesh_shp_bot
#doc = FreeCAD.newDocument() #lin12 = LinBearHouse (kcomp.SCUU[12]) #LinBearHouse (kcomp.SCUU_Pr[10]) # ----------- thin linear bearing housing with asymmetrical distance # between the bolts
[docs]class ThinLinBearHouseAsim (object): """ There are +-------------+---------------------------+-----------------------+ |3 axis: | 3 planes (normal to axis) | 3 distances to plane | +=============+===========================+=======================+ | fc_fro_ax | fro: front | D: dep: depth | +-------------+---------------------------+-----------------------+ | fc_bot_ax | hor: horizontal) | H: hei: height | +-------------+---------------------------+-----------------------+ | fc_sid_ax | lat: lateral (medial) | W: wid: width | +-------------+---------------------------+-----------------------+ The planes are on the center of the slidding rod (height and width), and on the middle of the piece (width) The 3 axis are perpendicular, but the cross product of 2 vectors may result on the other vector or its negative. fc_fro_ax points to the front of the figure, but it is symmetrical so it can point to the back fc_bot_ax points to the bottom of the figure (not symmetrical) fc_sid_ax points to the side of the figure. Not symmetrical if bolt2cen_wid_n or bolt2cen_wid_p are not zero Makes a housing for a linear bearing, but it is very thin and intented to be attached to 2 rail it has to parts, the lower and the upper part :: ________ ______________ | ::...::| | ::........:: | | :: ::| Upper part |.:: ::.| |-::( )::|------ Horizontal plane |.:: ::.| --> fc_fro_ax | ::...::| Lower part | ::........:: | |_::___::| |_::________::_| : : _________ v | 0: :0 | fc_bot_axis | : : | | : : | | : : |--------> fc_sid_ax | : : | | :.....: | |__0:_:0__| ________ ______________ | ::...::| | ::........:: | | :: ::| Upper part |.:: ::.| |-::( )::|------> fc_sid_ax |.:: *refcen_hei = 1 | ::...::| Lower part | ::........:: | |_::___::| |_::___*____::_| | | refcen_hei = 0 | | V V centered in any of these axes refcen_hei: reference centered on the height =1: the horizontal plane (height) is on the axis of the rod =0: the horizontal plane is at the bottom refcen_dep: reference centered on the depth =1: the frontal plane (depth) is on the middle of the piece =0: the frontal plane is at the bolts refcen_wid=1: reference centered on the width the lateral plane (width) is on the medial axis, dividing the piece on the right and left =0: the lateral plane is at the bolts ______________ 1: refcen_hei=1 | ::........:: | fro_center =1 |.:: ::.| 2: refcen_hei=0 |.:4 1 --> fc_fro_ax fro_center =1 | ::........:: | 3: refcen_hei=0 | :: :: | fro_center =0 |_:3___2____::_| 4: refcen_hei=1 And 8 more posibilities: 5: refcen_wid = 0 6: refcen_wid = 1 _________ | 5:6: | | : : | | : : | | : : |--------> fc_sid_ax | : : | | :.....: | |__0:_:0__| Parameters ---------- d_lbear : dictionary Dictionary with the dimensions of the linear bearing fc_fro_ax : FreeCAD.Vector Direction of the slide fc_bot_ax : FreeCAD.Vector Direction of the bottom fc_sid_ax : FreeCAD.Vector Direction of the other perpendicular direction. Not useful unless refcen_wid == 0 if = V0 it doesn't matter axis_h : float Distance from the bottom to the rod axis * 0: take the minimum distance * X: (any value) take that value, if it is smaller than the minimum it will raise an error and would not take that value refcen_hei : int See picture, indicates the reference point refcen_dep : int See picture, indicates the reference point refcen_wid : int See picture, indicates the reference point, if it is on the bolt or on the axis pos : FreeCAD.Vector Position of the reference point, Attributes ---------- nfro_ax : FreeCAD.Vector normalized fc_fro_ax nbot_ax : FreeCAD.Vector normalized fc_bot_ax nsid_ax : FreeCAD.Vector axis_h : float bolt2cen_dep : float bolt2cen_wid_n : float bolt2cen_wid_p : float bolt2bolt_wid : bolt2cen_wid_n + bolt2cen_wid_p Dimensions: * D : float housing_d * W : float housing_w * H : float housing_h FreeCAD objects: * fco_top : Top part of the linear bearing housing * fco_bot : Bottom part of the linear bearing housing :: ________ ______________ | ::...::| | ::........:: | | :: ::| |.:: ::.| |-::( )::|---: |.:: ::.| --> nfro_ax | ::...::| +axis_h | ::........:: | |_::___::| : | :: :: | |_::___::|...: |_::________::_| : v _________ nbot_ax | 0: :0 | | : : | | : : |........ --> nsid_ax | : : | : | :.....: | + boltcen_dep |__0:_:0__|---: : : : : : : :.:.: : + bolt2cen_wid_p: distance form the bolt to the center : on the width dimension. The bolt on the positive side + bolt2cen_wid_n: distance form the bolt to the center : on the width dimension. The bolt on the negative side : + if refcen_wid=0 the reference will be on the bolt2cen_wid_n ...... D ....... : : ________.... :______________: | ::...::| : | ::........:: | | :: ::| : |.:: ::.| |-::( )::| : |.:: ::.| --> nfro_ax | ::...::| + H | ::........:: | |_::___::|...: |_::________::_| : : :........: + W bolts_side = 0 bolts_side = 1 _________ | 0: :0 | ___________ | : : | | 0: :0 | | : : | | : : | | : : | | : : | | :.....: | |_0:_____:0_| |__0:_:0__| """ MIN_SEP_WALL = 3. # min separation of a wall MIN2_SEP_WALL = 2. # min separation of a wall OUT_SEP_H = kparts.OUT_SEP_H # minimun separation of the linear bearing MTOL = kparts.MTOL MLTOL = kparts.MLTOL TOL_BEARING_L = kparts.TOL_BEARING_L # Radius to fillet the sides FILLT_R = kparts.FILLT_R def __init__(self, d_lbear, fc_fro_ax = VX, fc_bot_ax =VZN, fc_sid_ax = V0, axis_h = 0, bolts_side = 1, refcen_hei = 1, refcen_dep = 1, refcen_wid = 1, bolt2cen_wid_n = 0, bolt2cen_wid_p = 0, pos = V0, name = 'thinlinbearhouse_asim' ): self.name = name self.base_place = (0,0,0) # normalize, just in case nfro_ax = DraftVecUtils.scaleTo(fc_fro_ax,1) nbot_ax = DraftVecUtils.scaleTo(fc_bot_ax,1) nbot_ax_n = DraftVecUtils.neg(nbot_ax) # vector perpendicular to the others v_cross = nfro_ax.cross(nbot_ax) if fc_sid_ax == V0: nsid_ax = v_cross else: nsid_ax = DraftVecUtils.scaleTo(fc_sid_ax,1) if not fcfun.fc_isparal (v_cross,nsid_ax): logger.debug("fc_sid_ax not perpendicular") nsid_ax = v_cross self.rod_r = d_lbear['Di']/2. rod_r = self.rod_r self.bear_r = d_lbear['Di'] if rod_r >= 6: BOLT_D = 4 else: BOLT_D = 3 # M3 bolts doc = FreeCAD.ActiveDocument MIN_SEP_WALL = self.MIN_SEP_WALL MIN2_SEP_WALL = self.MIN2_SEP_WALL OUT_SEP_H = self.OUT_SEP_H # bolt dimensions: MTOL = self.MTOL MLTOL = self.MLTOL BOLT_HEAD_R = kcomp.D912_HEAD_D[BOLT_D] / 2.0 BOLT_HEAD_L = kcomp.D912_HEAD_L[BOLT_D] + MTOL BOLT_HEAD_R_TOL = BOLT_HEAD_R + MTOL/2.0 BOLT_SHANK_R_TOL = BOLT_D / 2.0 + MTOL/2.0 # bearing dimensions: bearing_l = d_lbear['L'] bearing_l_tol = bearing_l + self.TOL_BEARING_L bearing_d = d_lbear['De'] bearing_d_tol = bearing_d + 2.0 * self.MLTOL bearing_r = bearing_d / 2.0 bearing_r_tol = bearing_r + self.MLTOL # dimensions of the housing: # length on the direction of the sliding rod bolt2wall = fcfun.get_bolt_end_sep(BOLT_D, hasnut=0) #housing_d = bearing_l_tol + 2 * (2*BOLT_HEAD_R_TOL + 2* MIN_SEP_WALL) if bolts_side == 1: # bolts on the side of the linear bearing # bolt2cen_wid: distance from the center (axis) to the bolt center bolt2cen_wid = fcfun.get_bolt_bearing_sep (BOLT_D, hasnut=0, lbearing_r = bearing_r) else: # bolts after the linear bearing (front axis) # it will be longer (on D), and shorter (on W) bolt2cen_wid = fcfun.get_bolt_bearing_sep (BOLT_D, hasnut=0, lbearing_r = rod_r ) #lbearing_r = rod_r + kparts.ROD_SPACE_MIN) # check if it is going to be wider if bolt2cen_wid_n > 0: if bolt2cen_wid_n < bolt2cen_wid: logger.debug("bolt2cen_wid_n smaller than minimum") bolt2cen_wid_n = bolt2cen_wid else: bolt2cen_wid_n = bolt2cen_wid_n else: bolt2cen_wid_n = bolt2cen_wid if bolt2cen_wid_p > 0: if bolt2cen_wid_p < bolt2cen_wid: logger.debug("bolt2cen_wid_p smaller than minimum") bolt2cen_wid_p = bolt2cen_wid else: bolt2cen_wid_p = bolt2cen_wid_p else: bolt2cen_wid_p = bolt2cen_wid if bolts_side == 1: # it will be shorter (on D), and wider (on W) housing_d = bearing_l + 2 * MIN_SEP_WALL housing_w = 2 * bolt2wall + bolt2cen_wid_n + bolt2cen_wid_p else: housing_d = bearing_l + 4*bolt2wall #bolt_r is included in bolt2wall housing_w = max ((bearing_d + 2* MIN_SEP_WALL), 2 * bolt2wall + bolt2cen_wid_n + bolt2cen_wid_p) print("housing_d: %", housing_d) print("housing_w: %", housing_w) # bolt distance # distance of the bolts to the center, on nfro_ax dir bolt2cen_dep = housing_d/2. - bolt2wall # minimum height of the housing housing_min_h = bearing_d + 2 * OUT_SEP_H axis_min_h = housing_min_h / 2. print("min housing_h: %", housing_min_h) if axis_h == 0: # minimum values housing_h = housing_min_h axis_h = axis_min_h elif axis_h >= axis_min_h: # the lower part will have longer height: axis_h # the upper part will be the minimum: axis_min_h housing_h = axis_h + axis_min_h axis_h = axis_h else: # the argument has an axis_h lower than the minimum possible logger.debug("axis_h %s cannot be smaller than %s", str(axis_h), str(axis_min_h)) housing_h = housing_min_h axis_h = axis_min_h # Atributes self.D = housing_d self.W = housing_w self.H = housing_h self.axis_h = axis_h self.bolt2cen_dep = bolt2cen_dep self.bolt2cen_wid_n = bolt2cen_wid_n self.bolt2cen_wid_p = bolt2cen_wid_p self.bolt2bolt_wid = bolt2cen_wid_p + bolt2cen_wid_n self.nfro_ax = nfro_ax self.nbot_ax = nbot_ax self.nsid_ax = nsid_ax #To make the boxes, we take the reference on midcenter=1 and # refcen_hei = 0. Point 2 on the drawing if refcen_dep == 0: #the center is not on frontal plane # get the vector from the reference center to the center: fc_ref2cen_dep = DraftVecUtils.scale(nfro_ax, bolt2cen_dep) else: fc_ref2cen_dep = V0 if refcen_hei == 1: fc_ref2bot_hei = DraftVecUtils.scale(nbot_ax,axis_h) fc_ref2cen_hei = V0 else: fc_ref2bot_hei = V0 fc_ref2cen_hei = DraftVecUtils.scale(nbot_ax,-axis_h) if refcen_wid == 0: fc_ref2cen_wid = DraftVecUtils.scale(nsid_ax, bolt2cen_wid_n) # since it is not symmetrical the side n and the side p, we # another center for the housing, not for the rod fc_ref2houscen_wid = DraftVecUtils.scale(nsid_ax, (bolt2cen_wid_n + bolt2cen_wid_p)/2.) else: fc_ref2cen_wid = V0 # since it is not symmetrical the side n and the side p, we # another center for the housing, not for the rod fc_ref2houscen_wid = DraftVecUtils.scale(nsid_ax, (bolt2cen_wid_p - bolt2cen_wid_n)/2.) botcenter_pos = pos + fc_ref2cen_dep + fc_ref2bot_hei + fc_ref2cen_wid bothouscenter_pos = ( pos + fc_ref2cen_dep + fc_ref2bot_hei + fc_ref2houscen_wid) # point 1 on the drawing axiscenter_pos = pos + fc_ref2cen_dep + fc_ref2cen_hei + fc_ref2cen_wid axishouscenter_pos = ( pos + fc_ref2cen_dep + fc_ref2cen_hei + fc_ref2houscen_wid ) # center on the top topcenter_pos = botcenter_pos + DraftVecUtils.scale(nbot_ax_n, housing_h) shp_housing = fcfun.shp_box_dir(box_w = housing_w, box_d = housing_d, #dir of nfro_ax box_h = housing_h, fc_axis_h = nbot_ax_n, fc_axis_d = nfro_ax, cw= 1, cd=1, ch=0, pos = bothouscenter_pos) # fillet, small shp_block = fcfun.shp_filletchamfer_dir(shp_housing, fc_axis=fc_bot_ax, radius=2) # the rod hole shp_rod = fcfun.shp_cylcenxtr(r = rod_r + kparts.ROD_SPACE_MIN, h = housing_d, normal = nfro_ax, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) # the linear bearing hole shp_lbear = fcfun.shp_cylcenxtr(r = bearing_r_tol, h = bearing_l_tol, normal = nfro_ax, ch = 1, xtr_top = 1, xtr_bot=1, pos = axiscenter_pos) shp_rodlbear = shp_rod.fuse(shp_lbear) # 4 bolts bolt_holes = [] for vec_axis in [DraftVecUtils.scale(nfro_ax,bolt2cen_dep), DraftVecUtils.scale(nfro_ax,-bolt2cen_dep)]: for vec_perp in [DraftVecUtils.scale(nsid_ax, bolt2cen_wid_p), DraftVecUtils.scale(nsid_ax, -bolt2cen_wid_n)]: pos_i = topcenter_pos + vec_axis + vec_perp # the nut hole will be on the bottom side, shp_bolt = fcfun.shp_bolt_dir ( r_shank = BOLT_SHANK_R_TOL, l_bolt = housing_h, r_head = BOLT_HEAD_R_TOL, l_head = BOLT_HEAD_L, hex_head = 0, xtr_head=1, xtr_shank=1, support=1, fc_normal = nbot_ax, fc_verx1=V0, pos = pos_i) bolt_holes.append(shp_bolt) shp_holes = shp_rodlbear.multiFuse(bolt_holes) shp_lbear_housing = shp_block.cut(shp_holes) doc.recompute() # making 2 parts, intersection with 2 boxes: shp_box_top = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_d + 2, box_h = housing_h - axis_h + 1, fc_axis_h = nbot_ax_n, fc_axis_d = nfro_ax, cw= 1, cd=1, ch=0, pos = axishouscenter_pos) shp_lbear_housing_top = shp_lbear_housing.common(shp_box_top) shp_lbear_housing_top = shp_lbear_housing_top.removeSplitter() fco_lbear_top = doc.addObject("Part::Feature", name + '_top') fco_lbear_top.Shape = shp_lbear_housing_top shp_box_bot = fcfun.shp_box_dir( box_w = housing_w + 2, box_d = housing_d + 2, # larger, just in case box_h = axis_h + 1, fc_axis_h = nbot_ax, fc_axis_d = nfro_ax, cw= 1, cd=1, ch=0, pos = axishouscenter_pos) shp_lbear_housing_bot = shp_lbear_housing.common(shp_box_bot) shp_lbear_housing_bot = shp_lbear_housing_bot.removeSplitter() fco_lbear_bot = doc.addObject("Part::Feature", name + '_bot') fco_lbear_bot.Shape = shp_lbear_housing_bot self.fco_top = fco_lbear_top self.fco_bot = fco_lbear_bot def BasePlace (self, position = (0,0,0)): self.base_place = position vpos = FreeCAD.Vector(position) self.fco_top.Placement.Base = vpos self.fco_bot.Placement.Base = vpos def color (self, color = (1,1,1)): self.fco_top.ViewObject.ShapeColor = color self.fco_bot.ViewObject.ShapeColor = color def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name stlPath = filepath + stl_dir stlFileName_top = stlPath + name + "_top" + ".stl" stlFileName_bot = stlPath + name + "_bot" + ".stl" # exportStl not working well with FreeCAD 0.17 #self.fco_top.Shape.exportStl(stlFileName_top) #self.fco_bot.Shape.exportStl(stlFileName_bot) mesh_shp_top = MeshPart.meshFromShape(self.fco_top.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp_top.write(stlFileName_top) del mesh_shp_top mesh_shp_bot = MeshPart.meshFromShape(self.fco_bot.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp_bot.write(stlFileName_bot) del mesh_shp_bot
#doc = FreeCAD.newDocument() #ThinLinBearHouseAsim (kcomp.LMELUU[12], # fc_fro_ax = VX, # fc_bot_ax = VZN, # fc_sid_ax = VYN, # axis_h = 0, bolts_side=0, # refcen_hei=1, refcen_dep=1, refcen_wid = 1, # bolt2cen_wid_n = 0, # bolt2cen_wid_p = 25) # ----------- NemaMotorHolder
[docs]class NemaMotorHolder (object): """ Creates a holder for a Nema motor :: __________________ || || || O __ O || || / \ || || | 1 | || || \ / || || O __ O || ||________________|| ..... ||_______2________|| ..... wall_thick motor_xtr_space_d : : ________3_________ 3_:__:____________ .... | :: : : :: | | : : | + motor_thick |__::__:_1__:__::__| 2......:..1..:....|....:..........> fc_axis_n || || | : / || || || || | : / || || || || | : / || || || || | : / || || || || | : / ||________________|| |_: / :: : : + reinf_thick :....tot_d........: fc_axis_h : ________:_________ .................................. | :: : : :: | : |__::__:_1__:__::__|.................... : || ||....+ motor_min_h : : || || || || : +tot_h || || || || + motor_max_h : || || || || : : || || || ||...................: : ||________________||..................................: : : : : : : : : : :............: : : bolt_wall_sep : : : : : :.....tot_w........: :: motor_xtr_space 1: ref_axis = 1 & ref_bolt = 0 2: ref_axis = 0 & ref_bolt = 0 --3: ref_axis = 0 & ref_bolt = 0 Parameters ---------- nema_size : int Size of the motor (NEMA) wall_thick : float Thickness of the side where the holder will be screwed to motor_thick : float Thickness of the top side where the motor will be screwed to reinf_thick : float Thickness of the reinforcement walls motor_min_h : float Distance of from the inner top side to the top hole of the bolts to attach the holder (see drawing) motor_max_h : float Distance of from the inner top side to the bottom hole of the bolts to attach the holder rail : int * 2: the rail goes all the way to the end, not closed * 1: the holes for the bolts are not holes, there are 2 rails, from motor_min_h to motor_max_h * 0: just 2 pairs of holes. One pair at defined by motor_min_h and the other defined by motor_max_h motor_xtr_space : float Extra separation between the motor and the sides motor_xtr_space_d : float Extra separation between the motor and the wall side (where the bolts) it didn't exist before, so for compatibility * -1: same has motor_xtr_space (compatibility), considering bolt head length * 0: no separation * >0: exact separation bolt_wall_d : int/float Metric of the bolts to attach the holder bolt_wall_sep : float Separation between the 2 bolt holes (or rails). Optional. chmf_r : float Radius of the chamfer, whenever chamfer is done fc_axis_h : FreeCAD Vector Axis along the axis of the motor fc_axis_n : FreeCAD Vector Axis normal to surface where the holder will be attached to ref_axis : int * 1: the zero of the vertical axis (axis_h) is on the motor axis * 0: the zero of the vertical axis (axis_h) is at the wall pos : FreeCAD.Vector Position of the holder (considering ref_axis) wfco : int * 1: creates a FreeCAD object * 0: only creates a shape name : string Name of the FreeCAD object """ def __init__ (self, nema_size = 17, wall_thick = 4., motor_thick = 4., reinf_thick = 4., motor_min_h =10., motor_max_h =20., rail = 1, # if there is a rail or not at the profile side motor_xtr_space = 2., # counting on one side motor_xtr_space_d = -1, # same as motor_xtr_space bolt_wall_d = 4., # Metric of the wall bolts bolt_wall_sep = 30., # optional chmf_r = 1., fc_axis_h = VZ, fc_axis_n = VX, #fc_axis_p = VY, ref_axis = 1, #ref_bolt = 0, pos = V0, wfco = 1, name = 'nema_holder'): doc = FreeCAD.ActiveDocument # normalize de axis axis_h = DraftVecUtils.scaleTo(fc_axis_h,1) axis_n = DraftVecUtils.scaleTo(fc_axis_n,1) axis_p = axis_h.cross(axis_n) #perpendicular axis_n_n = axis_n.negative() axis_h_n = axis_h.negative() self.axis_h = axis_h self.axis_n = axis_n self.axis_p = axis_p # best axis to print: self.axis_print = axis_h_n self.pos = pos self.name = name motor_w = kcomp.NEMA_W[nema_size] motor_bolt_sep = kcomp.NEMA_BOLT_SEP[nema_size] motor_bolt_d = kcomp.NEMA_BOLT_D[nema_size] boltwallshank_r_tol = kcomp.D912[bolt_wall_d]['shank_r_tol'] boltwallhead_l = kcomp.D912[bolt_wall_d]['head_l'] boltwallhead_r = kcomp.D912[bolt_wall_d]['head_r'] washer_thick = kcomp.WASH_D125_T[bolt_wall_d] # calculation of the bolt wall separation # if larger is not needed max_bolt_wall_sep = motor_w - 2 * boltwallhead_r motor_box_w = motor_w if bolt_wall_sep == 0: bolt_wall_sep = max_bolt_wall_sep elif bolt_wall_sep > max_bolt_wall_sep: logger.debug('bolt wall separtion larger: ' + str(bolt_wall_sep)) logger.debug('making the box width larger') motor_box_w = bolt_wall_sep + 2 * boltwallhead_r logger.debug('taking large value: ' + str(bolt_wall_sep)) elif bolt_wall_sep < 4 * boltwallhead_r: logger.debug('bolt wall separtion too short: ' + str(bolt_wall_sep)) bolt_wall_sep = max_bolt_wall_sep logger.debug('taking large value: ' + str(bolt_wall_sep)) # else: the given separation is good # making the big box that will contain everything and will be cut if rail == 2: tot_h = motor_thick + motor_max_h else: tot_h = motor_thick + motor_max_h + 2 * bolt_wall_d tot_w = 2* reinf_thick + motor_box_w + 2 * motor_xtr_space if motor_xtr_space_d == -1: # same as motor_xtr_space motor_xtr_space_d = motor_xtr_space + boltwallhead_l + washer_thick tot_d = wall_thick + motor_w + motor_xtr_space_d # getting the offset of the reference # distance of the motor axis to de wall motax2wall_dist = wall_thick + motor_w/2. + motor_xtr_space_d self.motax2wall_dist = motax2wall_dist if ref_axis == 1: ref2motax = V0 #point 1 ref2motaxwall = DraftVecUtils.scale(axis_n_n, motax2wall_dist) else: ref2motax = DraftVecUtils.scale(axis_n, motax2wall_dist) ref2motaxwall = V0 # point 2 motax_pos = pos + ref2motax motaxwall_pos = pos + ref2motaxwall # point centered on the symmetrical plane, on top of axis_h and # on the wall (point 3) ref2topwallcent = ( ref2motaxwall + DraftVecUtils.scale(axis_h, motor_thick)) topwallcent_pos = pos + ref2topwallcent # atributes with dimensions, distances and positions self.tot_h = tot_h self.tot_w = tot_w self.tot_d = tot_d self.ref2motax = ref2motax self.ref2motaxwall = ref2motaxwall self.ref2topwallcent = ref2topwallcent self.motax_pos = motax_pos self.motaxwall_pos = motaxwall_pos self.topwallcent_pos = topwallcent_pos # make the whole box, extra height and depth to cut all the way # back and down: shp_box = fcfun.shp_box_dir (box_w = tot_w, box_d = tot_d, box_h = tot_h, fc_axis_h = axis_h_n, fc_axis_d = axis_n, cw=1, cd=0, ch=0, pos = topwallcent_pos) # little chamfer at the corners, if fillet there are some problems shp_box = fcfun.shp_filletchamfer_dir(shp_box, axis_h, fillet=0, radius = chmf_r) doc.recompute() shp_box = shp_box.removeSplitter() # chamfer of the box to make a 'triangular' reinforcement chmf_reinf_r = min(tot_d- wall_thick, tot_h-motor_thick) # look for the point: chmf_pos = ( topwallcent_pos + DraftVecUtils.scale(axis_h_n, tot_h) + DraftVecUtils.scale(axis_n, tot_d)) shp_box = fcfun.shp_filletchamfer_dirpt(shp_box, axis_p, fc_pt =chmf_pos, fillet=0, radius = chmf_reinf_r) doc.recompute() # holes: holes = [] motaxinwall_pos = (motaxwall_pos + DraftVecUtils.scale(axis_n, wall_thick)) # the space for the motor shp_motor = fcfun.shp_box_dir ( box_w = motor_box_w + 2 * motor_xtr_space, box_d = tot_d + chmf_r, box_h = tot_h, fc_axis_h = axis_h_n, fc_axis_d = axis_n, cw=1, cd=0, ch=0, pos = motaxinwall_pos) shp_motor = fcfun.shp_filletchamfer_dir(shp_motor, fc_axis=axis_h, fillet=0, radius=chmf_r) doc.recompute() holes.append(shp_motor) # central circle of the motor shp_hole = fcfun.shp_cylcenxtr(r=(motor_bolt_sep - motor_bolt_d)/2., h = motor_thick, normal = axis_h, ch = 0, xtr_top = 1, xtr_bot = 1, pos = motax_pos) holes.append(shp_hole) # motor bolt holes for add_n in (DraftVecUtils.scale(axis_n, motor_bolt_sep/2.), DraftVecUtils.scale(axis_n,-motor_bolt_sep/2.)): for add_p in (DraftVecUtils.scale(axis_p, motor_bolt_sep/2.), DraftVecUtils.scale(axis_p,-motor_bolt_sep/2.)): hole_pos = motax_pos + add_n + add_p shp_hole = fcfun.shp_cylcenxtr( r = motor_bolt_d/2.+TOL, h = motor_thick, normal = axis_h, ch = 0, xtr_top = 1, xtr_bot = 1, pos = hole_pos) holes.append(shp_hole) # rail holes. To mount the motor holder to a profile or whatever for add_p in (DraftVecUtils.scale(axis_p, bolt_wall_sep/2.), DraftVecUtils.scale(axis_p,-bolt_wall_sep/2.)): # hole for the rails hole_pos = (motaxwall_pos + add_p + DraftVecUtils.scale(axis_h_n, motor_min_h)) if rail > 0: shp_hole = fcfun.shp_box_dir_xtr( box_w = boltwallshank_r_tol * 2., box_d = wall_thick, box_h = motor_max_h - motor_min_h, fc_axis_h = axis_h_n, fc_axis_d = axis_n, cw=1, cd=0, ch=0, xtr_d =1, xtr_nd=1, #to cut pos = hole_pos) holes.append(shp_hole) # hole for the ending of the rails (semicircles) for add_h in (DraftVecUtils.scale(axis_h_n, motor_min_h), DraftVecUtils.scale(axis_h_n, motor_max_h)): hole_pos = motaxwall_pos + add_h + add_p shp_hole = fcfun.shp_cylcenxtr( r = boltwallshank_r_tol, h = wall_thick, normal = axis_n, ch = 0, xtr_top = 1, xtr_bot = 1, pos = hole_pos) holes.append(shp_hole) shp_holes = fcfun.fuseshplist(holes) shp_motorholder = shp_box.cut(shp_holes) self.shp = shp_motorholder if wfco == 1: # a freeCAD object is created fco_motorholder = doc.addObject("Part::Feature", name ) fco_motorholder.Shape = shp_motorholder self.fco = fco_motorholder def color (self, color = (1,1,1)): if self.wfco == 1: self.fco.ViewObject.ShapeColor = color else: logger.debug("Object with no fco") # exports the shape to STL format def export_stl (self, name = ""): # ------------------------------------------ # check how to do this axis_up = self.axis_print rotation = DraftVecUtils.getRotation(axis_up, VZ) if (DraftVecUtils.equals(axis_up, VZN)): #we have to flip it, but rotation doesnt get it done: rotation = FreeCAD.Rotation(VX,180) shp = self.shp #shp.Placement.Rotation = rotation #Part.show(shp) shp.Placement.Base = self.topwallcent_pos.negative() #Part.show(shp) shp.Placement.Rotation = rotation #Part.show(shp) if not name: name = self.name stlPath = filepath + "/stl/" stlFileName = stlPath + name + ".stl" #print (" %s", stlFileName) # exportStl is not working well with FreeCAD 0.17 #self.shp.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.shp, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp
#doc = FreeCAD.newDocument() #h_nema = NemaMotorHolder ( # nema_size = 17, # wall_thick = 4., # motor_thick = 4., # reinf_thick = 3., # motor_min_h =8., # motor_max_h = 35., # motor_xtr_space = 2., # counting on one side # motor_xtr_space_d = -1, # bolt_wall_d = 4., # chmf_r = 0.2, # #bolt_wall_sep = 40., # optional # rail = 1, # fc_axis_h = VZN,#FreeCAD.Vector(1,1,0), # fc_axis_n = VX, #FreeCAD.Vector(1,-1,0), # #fc_axis_p = VY, # ref_axis = 1, # #ref_bolt = 0, # pos = V0, # FreeCAD.Vector(3,2,5), # wfco = 1, # name = 'nema17_holder_rail35_8') #doc = FreeCAD.newDocument() #h_nema = NemaMotorHolder ( # nema_size = 17, # wall_thick = 5., # motor_thick = 4., # reinf_thick = 4., # motor_min_h =8., # motor_max_h = 33., # rail = 0, # motor_xtr_space = 2., # counting on one side # bolt_wall_d = 3., # chmf_r = 1., # fc_axis_h = VZN,#FreeCAD.Vector(1,1,0), # fc_axis_n = VX, #FreeCAD.Vector(1,-1,0), # #fc_axis_p = VY, # ref_axis = 1, # #ref_bolt = 0, # pos = V0, # FreeCAD.Vector(3,2,5), # wfco = 1, # name = 'nema_holder') # a porras: #doc = FreeCAD.newDocument() #h_nema = NemaMotorHolder ( # nema_size = 17, # wall_thick = 5., # motor_thick = 3., # reinf_thick = 4., # motor_min_h =8., # motor_max_h = 43., # rail = 1, # motor_xtr_space = 2., # counting on one side # bolt_wall_d = 3., # chmf_r = 1., # fc_axis_h = VZN,#FreeCAD.Vector(1,1,0), # fc_axis_n = VX, #FreeCAD.Vector(1,-1,0), # #fc_axis_p = VY, # ref_axis = 1, # #ref_bolt = 0, # pos = V0, # FreeCAD.Vector(3,2,5), # wfco = 1, # name = 'nema_holder_52h') # ----------- ShpNemaMotorHolder class ShpNemaMotorHolder (shp_clss.Obj3D): """ Creates a holder for a Nema motor. Similar to NemaMotorHolder but creating the classes defined for shapes and parts. See shp_clss and fc_clss :: axis_d : : ________:_________ || || || O __ O || || / \ || || | | || || \ / || || O __ O || ||________________|| ..... ||________________|| ..... wall_thick.....> axis_w motor_xtr_space motor_xtr_space :: :: :: _::____________::_ ___::____________ ..............> axis_d | :: : : :: | | : : | + motorside_thick |__::__:____:__::__| 0.1....:..3..:....5....: || || | : / || || || || | : / || || || || | : / || || || || | : / || || || || | : / ||________________|| |_: / :: : : : + reinf_thick :....tot_d........: : : v v axis_h axis_h axis_d : ________5_________ || || || O 4_ O || || / \ || || | 3 | || || \ / || || O 2_ O || ||_______1________|| ..... ||_______o____::__|| ..... wall_thick.....> axis_w 0 1 2 3 (axis_w) ________o_________ ....................................> axis_w | :: : : :: | : |__::__:_1__:__::__|.................... : || ||....+ motor_min_h : : || || 2 || || : +tot_h || || || || + motor_max_h : || || || || : : || || 3 || ||...................: : ||_______4________||..................................: : : : : : : : v : : : : axis_h : : : : : : : :..........: : : bolt_wall_sep : : : : : :.....tot_w........: pos_o (origin) is at pos_d=0, pos_w=0, pos_h=0, it's marked with o Parameters: ----------- nema_size : int Size of the motor (NEMA) wall_thick: float Thickness of the side where the holder will be screwed to motorside_thick: float Thickness of the top side where the motor will be screwed to reinf_thick: float Thickness of the reinforcement walls motor_min_h: float Distance of from the inner top side to the top hole of the bolts to attach the holder (see drawing) motor_max_h: float Distance of from the inner top side to the bottom hole of the bolts to attach the holder rail: int 1: the holes for the bolts are not holes, there are 2 rails, from motor_min_h to motor_max_h 0: just 2 pairs of holes. One pair at defined by motor_min_h and the other defined by motor_max_h motor_xtr_space: float Extra separation between the motor and the wall side and also between the motor and each of the sides bolt_wall_d: int/float Metric of the bolts to attach the holder bolt_wall_sep: float Separation between the 2 bolt holes (or rails). Optional. chmf_r: float Radius of the chamfer, whenever chamfer is done axis_h: FreeCAD Vector Axis along the axis of the motor axis_d: FreeCAD Vector Axis normal to surface where the holder will be attached to axis_w: FreeCAD Vector Axis perpendicular to axis_h and axis_d, symmetrical (not necessary) pos_d : int Location of pos along axis_d (0,1,2,3,4,5) 0: at the beginning, touching the wall where it is attached 1: at the inner side of the side where it will be screwed 2: bolts holes closed to the wall to attach the motor 3: at the motor axis 4: bolts holes away from to the wall to attach the motor 5: at the end of the piece pos_w : int Location of pos along axis_w (0,1,2,3). Symmetrical 0: at the center of symmetry 1: at the center of the rails (or holes) to attach the holder 2: at the center of the holes to attach the motor 3: at the end of the piece pos_h : int Location of pos along axis_h (0,1,2,3) 0: at the top (on the side of the motor axis) 1: inside the motor wall 2: Top end of the rail 3: Bottom end of the rail 4: Bottom end of the piece pos : FreeCAD.Vector Position of the piece """ def __init__ (self, nema_size = 17, wall_thick = 4., motorside_thick = 4., reinf_thick = 4., motor_min_h =10., motor_max_h =20., rail = 1, # if there is a rail or not at the profile side motor_xtr_space = 2., # counting on one side bolt_wall_d = 4., # Metric of the wall bolts bolt_wall_sep = 0, # optional chmf_r = 1., axis_h = VZ, axis_d = VX, axis_w = None, pos_h = 1, # 1: inner wall of the motor side pos_d = 3, # 3: motor axis pos_w = 0, # 0: center of symmetry pos = V0): if axis_w is None or axis_w == V0: axis_w = axis_h.cross(axis_d) shp_clss.Obj3D.__init__(self, axis_d, axis_w, axis_h) # save the arguments as attributes: frame = inspect.currentframe() args, _, _, values = inspect.getargvalues(frame) for i in args: if not hasattr(self,i): setattr(self, i, values[i]) # normal axes to print without support self.prnt_ax = self.axis_h self.motor_w = kcomp.NEMA_W[nema_size] self.motor_bolt_sep = kcomp.NEMA_BOLT_SEP[nema_size] self.motor_bolt_d = kcomp.NEMA_BOLT_D[nema_size] self.boltwallshank_r_tol = kcomp.D912[bolt_wall_d]['shank_r_tol'] self.boltwallhead_l = kcomp.D912[bolt_wall_d]['head_l'] self.boltwallhead_r = kcomp.D912[bolt_wall_d]['head_r'] self.washer_thick = kcomp.WASH_D125_T[bolt_wall_d] # calculation of the bolt wall separation self.max_bolt_wall_sep = self.motor_w - 2 * self.boltwallhead_r if bolt_wall_sep == 0: self.bolt_wall_sep = self.max_bolt_wall_sep elif bolt_wall_sep > self.max_bolt_wall_sep: logger.debug('bolt wall separtion too large: ' + str(bolt_wall_sep)) self.bolt_wall_sep = self.max_bolt_wall_sep logger.debug('taking larges value: ' + str(self.bolt_wall_sep)) elif bolt_wall_sep < 4 * self.boltwallhead_r: logger.debug('bolt wall separtion too short: ' + str(bolt_wall_sep)) self.bolt_wall_sep = self.self.max_bolt_wall_sep logger.debug('taking larges value: ' + str(self.bolt_wall_sep)) # else: the given separation is good # distance from the motor to the inner wall (in axis_d) self.motor_inwall_space = ( motor_xtr_space + self.boltwallhead_l + self.washer_thick) # making the big box that will contain everything and will be cut self.tot_h = motorside_thick + motor_max_h + 2 * bolt_wall_d self.tot_w = 2* reinf_thick + self.motor_w + 2 * motor_xtr_space self.tot_d = ( wall_thick + self.motor_w + self.motor_inwall_space) # distance from the motor axis to the wall (in axis_d) self.motax2wall = wall_thick + self.motor_inwall_space + self.motor_w/2. # definition of which axis is symmetrical self.h0_cen = 0 self.d0_cen = 0 self.w0_cen = 1 # symmetrical # vectors from the origin to the points along axis_h: self.h_o[0] = V0 self.h_o[1] = self.vec_h(motorside_thick) self.h_o[2] = self.vec_h(motorside_thick + motor_min_h) self.h_o[3] = self.vec_h(motorside_thick + motor_max_h) self.h_o[4] = self.vec_h(self.tot_h) # position along axis_d self.d_o[0] = V0 self.d_o[1] = self.vec_d(wall_thick) # inner wall # distance to the inner bolts of the motor self.d_o[2] = self.vec_d(self.motax2wall - self.motor_bolt_sep/2.) self.d_o[3] = self.vec_d(self.motax2wall) # motor axis self.d_o[4] = self.vec_d(self.motax2wall + self.motor_bolt_sep/2.) self.d_o[5] = self.vec_d(self.tot_d) # vectors from the origin to the points along axis_w: # these are negative because actually the pos_w indicates a negative # position along axis_w (this happens when it is symmetrical) self.w_o[0] = V0 self.w_o[1] = self.vec_w(-self.bolt_wall_sep/2.) self.w_o[2] = self.vec_w(-self.motor_bolt_sep/2.) self.w_o[3] = self.vec_w(-self.tot_w/2.) # calculates the position of the origin, and keeps it in attribute pos_o self.set_pos_o() # make the whole box, extra height and depth to cut all the way # back and down: shp_box = fcfun.shp_box_dir (box_w = self.tot_w, box_d = self.tot_d, box_h = self.tot_h, fc_axis_h = self.axis_h, fc_axis_d = self.axis_d, cw=1, cd=0, ch=0, pos = self.pos_o) # little chamfer at the corners, if fillet there are some problems shp_box = fcfun.shp_filletchamfer_dir(shp_box, self.axis_h, fillet=0, radius = chmf_r) shp_box = shp_box.removeSplitter() # chamfer of the box to make a 'triangular' reinforcement chmf_reinf_r = min(self.tot_d- wall_thick, self.tot_h-motorside_thick) # chamfer at the lower point (h=4), and the other end of d (d=5) shp_box = fcfun.shp_filletchamfer_dirpt(shp_box, self.axis_w, fc_pt =self.get_pos_dwh(5,0,4), fillet=0, radius = chmf_reinf_r) shp_box = shp_box.removeSplitter() # holes: holes = [] # the space for the motor shp_motor = fcfun.shp_box_dir ( box_w = self.motor_w + 2 * motor_xtr_space, box_d = self.tot_d + chmf_r, box_h = self.tot_h, fc_axis_h = self.axis_h, fc_axis_d = self.axis_d, cw=1, cd=0, ch=0, # at the inner walls pos = self.get_pos_dwh(1,0,1)) shp_motor = fcfun.shp_filletchamfer_dir(shp_motor, fc_axis=self.axis_h, fillet=0, radius=chmf_r) holes.append(shp_motor) # central circle of the motor shp_hole = fcfun.shp_cylcenxtr( r=(self.motor_bolt_sep - self.motor_bolt_d)/2., h = motorside_thick, normal = self.axis_h, ch = 0, xtr_top = 1, xtr_bot = 1, # position of the motor axis, at the top pos = self.get_pos_d(3)) holes.append(shp_hole) # motor bolt holes for pt_d in (2,4): # points of the motor holes along axis d for pt_w in (-2,2): # points of the motor holes along axis_w shp_hole = fcfun.shp_cylcenxtr( r = self.motor_bolt_d/2.+TOL, h = motorside_thick, normal = self.axis_h, ch = 0, xtr_top = 1, xtr_bot = 1, pos = self.get_pos_dwh(pt_d,pt_w,0)) holes.append(shp_hole) # rail holes. To mount the motor holder to a profile or whatever for pt_w in (-1,1): # points of the holes to attach the holder # hole for the rails if rail == 1: shp_hole = fcfun.shp_box_dir_xtr( box_w = self.boltwallshank_r_tol * 2., box_d = wall_thick, box_h = motor_max_h - motor_min_h, fc_axis_h = self.axis_h, fc_axis_d = self.axis_d, cw=1, cd=0, ch=0, xtr_d =1, xtr_nd=1, #to cut # h:2 the position on top of the rail pos = self.get_pos_dwh(0,pt_w,2)) holes.append(shp_hole) # hole for the ending of the rails (4 semicircles) for pt_h in (2,3) : # both ends of the rail (along axis_h) shp_hole = fcfun.shp_cylcenxtr( r = self.boltwallshank_r_tol, h = wall_thick, normal = self.axis_d, ch = 0, xtr_top = 1, xtr_bot = 1, pos = self.get_pos_dwh(0,pt_w,pt_h)) holes.append(shp_hole) shp_holes = fcfun.fuseshplist(holes) shp_motorholder = shp_box.cut(shp_holes) shp_bracket =shp_motorholder.removeSplitter() self.shp = shp_motorholder #doc = FreeCAD.newDocument() #shpob_nema = ShpNemaMotorHolder ( # nema_size = 17, # wall_thick = 6., # motorside_thick = 6., # reinf_thick = 1., # motor_min_h =10., # motor_max_h =50., # rail = 1, # if there is a rail or not at the profile side # motor_xtr_space = 3., # counting on one side # bolt_wall_d = 4., # Metric of the wall bolts # #bolt_wall_sep = 30., # optional # chmf_r = 1., # axis_h = VZ, # axis_d = VX, # axis_w = None, # pos_h = 1, # 1: inner wall of the motor side # pos_d = 3, # 3: motor axis # pos_w = 0, # 0: center of symmetry # pos = V0) #Part.show(shpob_nema.shp) class PartNemaMotorHolder(fc_clss.SinglePart, ShpNemaMotorHolder): """ Integration of a ShpNemaMotorHolder object into PartNemaMotorHolder object, so it is a FreeCAD object that can be visualized in FreeCAD """ def __init__ (self, nema_size = 17, wall_thick = 4., motorside_thick = 4., reinf_thick = 4., motor_min_h =10., motor_max_h =20., rail = 1, # if there is a rail or not at the profile side motor_xtr_space = 2., # counting on one side bolt_wall_d = 4., # Metric of the wall bolts bolt_wall_sep = 0, # optional chmf_r = 1., axis_h = VZ, axis_d = VX, axis_w = None, pos_h = 1, # 1: inner wall of the motor side pos_d = 3, # 3: motor axis pos_w = 0, # 0: center of symmetry pos = V0, model_type = 3, #to be printed name = ''): default_name = 'nema' + str(nema_size) + '_motorholder' self.set_name (name, default_name, change = 0) # First the shape is created ShpNemaMotorHolder.__init__(self, nema_size = nema_size, wall_thick = wall_thick, motorside_thick = motorside_thick, reinf_thick = reinf_thick, motor_min_h = motor_min_h, motor_max_h = motor_max_h, rail = rail, motor_xtr_space = motor_xtr_space, bolt_wall_d = bolt_wall_d, bolt_wall_sep = bolt_wall_sep, chmf_r = chmf_r, axis_h = axis_h, axis_d = axis_d, axis_w = axis_w, pos_h = pos_h, pos_d = pos_d, pos_w = pos_w, pos = pos) #then the part: fc_clss.SinglePart.__init__(self) # save the arguments that haven't been assigned as attributes frame = inspect.currentframe() args, _, _, values = inspect.getargvalues(frame) for i in args: if not hasattr(self,i): setattr(self, i, values[i]) #doc = FreeCAD.newDocument() #part_nemahold = PartNemaMotorHolder ( # nema_size = 23, # wall_thick = 4., # motorside_thick = 4., # reinf_thick = 4., # motor_min_h =10., # motor_max_h =20., # rail = 1, # if there is a rail or not at the profile side # motor_xtr_space = 2., # counting on one side # bolt_wall_d = 4., # Metric of the wall bolts # #bolt_wall_sep = 30., # optional # chmf_r = 1., # axis_h = VZ, # axis_d = VX, # axis_w = None, # pos_h = 1, # 1: inner wall of the motor side # pos_d = 3, # 3: motor axis # pos_w = 0, # 0: center of symmetry # pos = V0) # ----------- ShpNemaMotorHolderVer # TODO #class ShpNemaMotorHolderVer (shp_clss.Obj3D): """ Creates a VERTICAL holder for a Nema motor. :: axis_h : : 0 1 ________:_________ _........> axis_d | | | | | O __ O | | | | / \ | | | | | | \ / | | O __ O | | | ..... | || || || | | || || || | | || || || | | || || || | | || || || | | || || || | | ________________ | ..... > axis_w 0: just 2 pairs of holes. One pair at defined by motor_min_h and the other defined by motor_max_h Parameters ---------- motor_xtr_space: float Extra separation between the motor and the wall side and also between the motor and each of the sides bolt_wall_d: int/float Metric of the bolts to attach the holder bolt_wall_sep: float Separation between the 2 bolt holes (or rails). Optional. chmf_r: float Radius of the chamfer, whenever chamfer is done axis_h: FreeCAD Vector Axis along the axis of the motor axis_d: FreeCAD Vector Axis normal to surface where the holder will be attached to axis_w: FreeCAD Vector Axis perpendicular to axis_h and axis_d, symmetrical (not necessary) pos_d : int Location of pos along axis_d (0,1,2,3,4,5) 0: at the beginning, touching the wall where it is attached 1: at the inner side of the side where it will be screwed 2: bolts holes closed to the wall to attach the motor 3: at the motor axis 4: bolts holes away from to the wall to attach the motor 5: at the end of the piece pos_w : int Location of pos along axis_w (0,1,2,3). Symmetrical 0: at the center of symmetry 1: at the center of the rails (or holes) to attach the holder 2: at the center of the holes to attach the motor 3: at the end of the piece pos_h : int Location of pos along axis_h (0,1,2,3) 0: at the top (on the side of the motor axis) 1: inside the motor wall 2: Top end of the rail 3: Bottom end of the rail 4: Bottom end of the piece pos : FreeCAD.Vector Position of the piece def __init__ (self, nema_size = 17, wall_thick = 4., motor_min_h =10., motor_max_h =20., rail = 1, # if there is a rail or not at the profile side axis_h = VZ, axis_d = VX, axis_w = None, pos_h = 0, # 1: inner wall of the motor side pos_d = 0, # 3: motor axis pos_w = 0, # 0: center of symmetry pos = V0): """ class Plate3CageCubes (object): """ Creates a plate to join 3 Cage Cubes fc_top_ax fc_fro_ax : / _______________________:_____/__________.............. | O O : O / O |--top_h/2 + top_h |.......... ____ .....:..... ..........|..:.........: |o ___ o: |SQR | :o _:_ /o: :o ___ o| | / \ : |____| : / :.\..:.:. /...\..|..... fc_sid_ax | \___/ : : \___/ : : \___/ | |o_______o:________:o_______o:_:o_______o| : : :....: :. .: + sqr_w + hole_d fc_fro_ax : ___________ _____:_____ __________ |o ___ o| |o _:_ /o| |o ___ o| --> cage cubes | / \ | | / : \ | | / \ | | \___/ | | \_:_/ | | \___/ | |o_______o|________|____:___ |_|o_______o|........... fc_sid_ax | : : : : : : | + thick |__:___:______________:___:_______:___:__|..: : : : :.... cube_dist_n..:...........: + cube_dist_p Thruholes of the bolts are not drawn The position of the plate: pos, is referenced to the center of the hole of the middle plate. There are 3 axes: - fc_fro_ax: FreeCAD.Vector pointing to the direction of the cage cubes, and it is on the surface touching the cubes - fc_top_ax: FreeCAD.Vector pointing to the top, where there is an extra length (top_h) to hold an aluminum profile - fc_sid_ax: FreeCAD.Vector pointing to the side p (positive) ________________________________________ | O O O O | |.......... ........... ..........| |o ___ o: :o ___ o: :o ___ o| | / \ : : / \ : : / \ | | \___/ : : \___/ : : \___/ | |o_______o:________:_________:_:o_______o| : : : :.... cube_dist_n..: : Arguments: d_cagecube: dictionary with the dimensions of the cage cube thick: thickness of the plate, in mm cube_dist_n: distance from center to center of the middle cage cube to the cube in opposite direction (negative) of fc_sid_ax cube_dist_p: distance from center to center of the middle cage cube to the cube in the same direction (positive) of fc_sid_ax top_h: length of the extra part on top of the plate to hold a aluminum profile or whatever cube_face: indicates which face of the cube is facing the plate. There are 3 possible faces (defined in kparts.py): THRUHOLE (1) : the big hole is a thruhole without threads THRURODS (2) : the face has 4 thruholes for the rods RODSCREWS(3): the face has 4 tapped holes for screwing the end of the rods hole_d: diameter of the central thruhole facing the plate. 0: take the value of the cagecube hole X: take this value, since there may be something attached, such as a tubelens, which may have a ring that makes necesary to have larger diameter hole -1: no hole boltatt_n: number of bolt holes on the extra top side boltatt_d: diameter of the bolt holes on the top side sqr_h: height of the square hole done if there is space between cubes if 0: no rectangle. The rectangle only will be on the larger space between cubes sqr_w: width of the square(rectangle) hole done if there is space between cubes. It is made in line with the top of the cubes centered on the width space if 0: takes all the space of the space fc_fro_ax: FreeCAD.Vector pointing to the direction of the cage cubes, and it is on the surface touching the cubes fc_top_ax: FreeCAD.Vector pointing to the top, where there is an extra length (top_h) to hold an aluminum profile fc_sid_ax: FreeCAD.Vector pointing to the side p (positive) fillet_r: radius of the fillet of the corners, if 0, no fillet holes_tol : Add tolerance for the holes, it seems that even when milled it is needed moreboltholes : if more bolt holes are made to attach things pos: FreeCAD.Vector with the position of the reference. Center of the hole of the middle plate, on the face touching the cagecube name: str with the name of the FreeCAD.Object """ ROD_SCREWS = kcomp_optic.ROD_SCREWS THRU_RODS = kcomp_optic.THRU_RODS THRU_HOLE = kcomp_optic.THRU_HOLE def __init__(self, d_cagecube, thick, cube_dist_n, cube_dist_p, top_h = 10, #which side of the cube faces the plate cube_face = kcomp_optic.ROD_SCREWS, hole_d = 0, boltatt_n = 6, boltatt_d = 3, sqr_h = 0, sqr_w = 0, fc_fro_ax = VX, fc_top_ax = VZ, fc_sid_ax = VY, fillet_r = 1., holes_tol = 0, moreboltholes = 0, pos = V0, name = 'Plate3CageCubes' ): self.d_cagecube = d_cagecube self.name = name cage_w = d_cagecube['L'] #get normalized vectors nfro_ax = DraftVecUtils.scaleTo(fc_fro_ax,1) nfro_ax_n = nfro_ax.negative() ntop_ax = DraftVecUtils.scaleTo(fc_top_ax,1) nsid_ax = DraftVecUtils.scaleTo(fc_sid_ax,1) # calculate the plate dimensions # and its center # ________________________________________............. # | O O O O | + top_h : # |.......... ........... ..........|..: : # |o ___ o: :o _ _ o: :o ___ o| : + plate_h # | / \ : : / : \ : : / \ | + cage_w : # | \___/ : : \___/ : : \___/ | : : # |o_______o:________:o_______o:_:o_______o|..:........: # : : : : : # : :.... cube_dist_n..:...........: : # : +cube_dist_p : # :......plate_w...........................: plate_w = cube_dist_n + cube_dist_p + cage_w plate_h = cage_w + top_h # the center of the plate on the fc_top_ax and tc_sid_ax vectors platecen_pos = ( pos + DraftVecUtils.scale(ntop_ax,top_h/2.) + DraftVecUtils.scale(nsid_ax,(cube_dist_p-cube_dist_n)/2.)) shp_box = fcfun.shp_box_dir (box_w = plate_w, box_d = plate_h, box_h = thick, fc_axis_h = nfro_ax_n, fc_axis_d = ntop_ax, cw=1, cd=1, ch=0, pos = platecen_pos) if fillet_r > 0: # fillet the four corners shp_box = fcfun.shp_filletchamfer_dir(shp_box, fc_axis = fc_fro_ax, fillet = 1, radius = fillet_r) # diameter of the holes of the cubes: if cube_face == self.ROD_SCREWS: cube_hole_d = d_cagecube['thru_thread_d'] + holes_tol bolt_d = d_cagecube['rod_thread_d'] + holes_tol elif cube_face == self.THRU_RODS: cube_hole_d = d_cagecube['thru_thread_d'] + holes_tol bolt_d = d_cagecube['thru_rod_d'] + holes_tol elif cube_face == self.THRU_HOLE: cube_hole_d = d_cagecube['thru_hole_d'] + holes_tol bolt_d = d_cagecube['rod_thread_d'] + holes_tol else: logger.debug("cube_face not supported %s", cube_face) cube_hole_d = d_cagecube['thru_thread_d'] + holes_tol bolt_d = d_cagecube['rod_thread_d'] + holes_tol bolt_r = bolt_d/2. # position of the cage on the positive and negative sides: pos_cage_p = pos + DraftVecUtils.scale(nsid_ax,cube_dist_p) pos_cage_n = pos + DraftVecUtils.scale(nsid_ax,-cube_dist_n) holes_list = [] if hole_d >= 0: #if <0: no hole if hole_d == 0: hole_d = cube_hole_d # check if the diameter is larger than the cage diameter elif hole_d < cube_hole_d: logger.debug("hole_d smaller than cube hole"); logger.debug("taking the minimum %s", cube_hole_d) hole_d = cube_hole_d else: hole_d = hole_d hole_r = hole_d/2. # central big hole (it is on pos) shp_bighole_cen = fcfun.shp_cylcenxtr (r= hole_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos) shp_bighole_p = fcfun.shp_cylcenxtr (r= hole_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_cage_p) shp_bighole_n = fcfun.shp_cylcenxtr (r= hole_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_cage_n) # add the large holes to the list holes_list.extend([shp_bighole_cen, shp_bighole_p, shp_bighole_n]) ################ cagebolt_sep = d_cagecube['thru_rod_sep'] cagebolt2cen = cagebolt_sep /2. bolt_pos_top_p = DraftVecUtils.scale(ntop_ax, cagebolt2cen) bolt_pos_top_n = DraftVecUtils.scale(ntop_ax, -cagebolt2cen) bolt_pos_sid_p = DraftVecUtils.scale(nsid_ax, cagebolt2cen) bolt_pos_sid_n = DraftVecUtils.scale(nsid_ax, -cagebolt2cen) for pos_i in [pos, pos_cage_p, pos_cage_n]: for top_add in [bolt_pos_top_p, bolt_pos_top_n]: for sid_add in [bolt_pos_sid_p, bolt_pos_sid_n]: pos_boltcage = pos_i + top_add + sid_add shp_boltcage = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_boltcage) holes_list.append(shp_boltcage) # bolts to attach the aluminum profile: if boltatt_n < 2: boltatt_n = 2 # the first and the last bolt will be at the same fc_sid_ax as the # cage bols. # the distance between the first and the last is: boltatt_dist = cube_dist_n + cube_dist_p + cagebolt_sep boltatt_sep = boltatt_dist / (boltatt_n - 1) vec_boltatt_add = DraftVecUtils.scale(nsid_ax, boltatt_sep) #The first bolt will be: boltatt_pos = ( pos_cage_n + DraftVecUtils.scale(nsid_ax, -cagebolt2cen) + DraftVecUtils.scale(ntop_ax, cage_w/2. + top_h/2.)) boltatt_r = boltatt_d/2. for it_boltatt in range(boltatt_n): shp_boltatt = fcfun.shp_cylcenxtr (r= boltatt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = boltatt_pos) boltatt_pos = boltatt_pos + vec_boltatt_add holes_list.append(shp_boltatt) if cube_dist_n > cube_dist_p : # large space central vector larg_sp_c_vec = DraftVecUtils.scale(nsid_ax,-cube_dist_n/2.) shor_sp_c_vec = DraftVecUtils.scale(nsid_ax,cube_dist_p/2.) # width of the large space larg_sp_w = cube_dist_n - cage_w shor_sp_w = cube_dist_p - cage_w else: larg_sp_c_vec = DraftVecUtils.scale(nsid_ax,cube_dist_p/2.) shor_sp_c_vec = DraftVecUtils.scale(nsid_ax,-cube_dist_n/2.) # width of the large space larg_sp_w = cube_dist_p - cage_w shor_sp_w = cube_dist_n - cage_w # square (rectangle holes): # a rectangle on the larger distance between the cubes if sqr_h > 0: # ________________________________________ # | O O O O | # |.......... _____ ........| # |o ___ o: |_:_| larg_sp_c_pos ___ o| # | / \ : :<--------: \ : : / \ | # | \___/ : : \___/ : : \___/ | # |o_______o:________:o_______o:_:o_______o| # vector of the distance from the center to the square pos_sqr = (pos + larg_sp_c_vec + DraftVecUtils.scale(ntop_ax,cage_w/2. - sqr_h/2.)) if sqr_w == 0: # square width will be the total distance sqr_w = larg_sp_w # since in dont have shp_box_dir_extr, I put extra depth # double thick because we need extra and I havent brought it back # then a little more to cut the other # 1 mm tolerance. 0.5 on each side shp_sqr = fcfun.shp_box_dir (box_w = sqr_w + 1., # 1mm tolerance box_d = 2.1 * thick, box_h = sqr_h + 1., fc_axis_h = ntop_ax, fc_axis_d = nfro_ax_n, cw=1, cd=1, ch=1, pos= pos_sqr) holes_list.append(shp_sqr) # more bolt holes ( holes): if moreboltholes == 1: # ________________________________________ # | O O O O | # |........................................| # |o ___ o: : :o ___ o| # | / \ : :<--------: \ : : / \ | # | \___/ : O O : \___/ : : \___/ | # |o_______o:________:o_______o:_:o_______o| # holes on the shorter side pos_bolt = pos + bolt_pos_top_n + shor_sp_c_vec shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) pos_bolt = ( pos + bolt_pos_top_n + shor_sp_c_vec + DraftVecUtils.scale(ntop_ax,20)) shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) # holes on the larger side pos_bolt = pos + bolt_pos_top_n + larg_sp_c_vec shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) pos_bolt = ( pos + bolt_pos_top_n + larg_sp_c_vec + DraftVecUtils.scale(ntop_ax,20)) shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) # holes on the larger side pos_bolt = (pos + bolt_pos_top_n + larg_sp_c_vec + DraftVecUtils.scale(nsid_ax,20)) shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) pos_bolt = ( pos + bolt_pos_top_n + larg_sp_c_vec + DraftVecUtils.scale(nsid_ax,20) + DraftVecUtils.scale(ntop_ax,20)) shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) # holes on the larger side pos_bolt = (pos + bolt_pos_top_n + larg_sp_c_vec + DraftVecUtils.scale(nsid_ax,-15)) shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) pos_bolt = ( pos + bolt_pos_top_n + larg_sp_c_vec + DraftVecUtils.scale(nsid_ax,-15) + DraftVecUtils.scale(ntop_ax,20)) shp_bolt = fcfun.shp_cylcenxtr (r= bolt_r, h = thick, normal = nfro_ax_n, ch=0, xtr_top=1, xtr_bot=1, pos = pos_bolt) holes_list.append(shp_bolt) shp_holes = fcfun.fuseshplist(holes_list) shp_plate = shp_box.cut(shp_holes) doc = FreeCAD.ActiveDocument fco_plate = doc.addObject("Part::Feature", name) fco_plate.Shape = shp_plate self.fco = fco_plate def color (self, color = (1,1,1)): self.fco.ViewObject.ShapeColor = color # exports the shape to STL format def export_stl (self, name = ""): if not name: name = self.name #stlPath = filepath + "/freecad/stl/" stlPath = filepath + stl_dir stlFileName = stlPath + name + ".stl" #print (stlFileName) # exportStl is not working well with FreeCAD 0.17 #self.fco.Shape.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.fco.Shape, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp #doc = FreeCAD.newDocument() #Plate3CageCubes(d_cagecube = kcomp_optic.CAGE_CUBE_60, # thick = 5, # cube_dist_n = 120, # cube_dist_p = 80, # top_h = 10, # cube_face = 'rodscrews',#which side of the cube faces the plate # hole_d = 0, # boltatt_n = 6, # boltatt_d = 3+TOL, # fc_fro_ax = VX, # fc_top_ax = VZ, # fc_sid_ax = VY, # pos = V0, # name = 'Plate3CageCubes') class hallestop_holder (object): def __init__(self, stp_w = 21., stp_h = 31., base_thick = 4., sup_thick = 4., bolt_base_d = 3, #metric of the bolt bolt_sup_d = 3, #metric of the bolt bolt_sup_sep = 17., alu_rail_l = 5, stp_rail_l = 5, xtr_bolt_head = 3, xtr_bolt_head_d = 0, reinforce = 1, base_min_dist = 1, fc_perp_ax = VZ, fc_lin_ax = VX, pos = V0, wfco=1, name = 'holder'): doc = FreeCAD.ActiveDocument self.name = name # bolt lin dimensions boltli_dict = kcomp.D912[bolt_base_d] boltlihead_r = boltli_dict['head_r'] boltlihead_r_tol = boltli_dict['head_r_tol'] boltlishank_r_tol = boltli_dict['shank_r_tol'] boltlihead_l = boltli_dict['head_l'] if bolt_sup_d == 0: bolt_sup_d = bolt_lin_d boltpe_dict = kcomp.D912[bolt_sup_d] boltpehead_r = boltpe_dict['head_r'] boltpehead_r_tol = boltpe_dict['head_r_tol'] boltpeshank_r_tol = boltpe_dict['shank_r_tol'] boltpehead_l = boltpe_dict['head_l'] boltmaxhead_r = max(boltlihead_r, boltpehead_r) boltmaxhead_r_tol = max(boltlihead_r_tol, boltpehead_r_tol) # normalize axis, just in case: axis_perp = DraftVecUtils.scaleTo(fc_perp_ax,1) axis_lin = DraftVecUtils.scaleTo(fc_lin_ax,1) axis_perp_neg = axis_perp.negative() axis_lin_neg = axis_lin.negative() axis_wid = axis_perp.cross(axis_lin) #Calculate the length of the sup_l # sup_thick :boltpehead_l # : : : boltlihead_r # ....:__: : : # : | |_ : # sup_h + | |_| _:_ # : | |__|___|___ # :...|_____________| # :.......: # bolt1li_dist = sup_thick+boltpehead_l+boltlihead_r # : : : # 2 x boltlihead_r # :.............: # + sup_l if base_min_dist == 0: bolt1li_dist = ( sup_thick + boltpehead_l + boltlihead_r_tol + xtr_bolt_head ) sup_l = bolt1li_dist + 2 * boltlihead_r + alu_rail_l else: bolt1li_dist = ( sup_thick + boltlihead_r_tol + xtr_bolt_head +kcomp.TOL) sup_l = bolt1li_dist + 0.8*boltlihead_r + alu_rail_l tot_w = max(stp_w + 2 * boltpehead_r, 8 * boltlihead_r) + 2 * reinforce # ....:__: : : _________ # : | |_ : || || # su_h + | |_| _:_ || O || # : | |__|___|___ ||_______|| # :...|_____________| |___:_:___|......axis_wid # :.............: :.........: # + sup_l + tot_w sup_h = 2*boltpehead_r + base_thick + stp_rail_l shp_box = fcfun.shp_box_dir (box_w = tot_w, box_d = sup_l, box_h = sup_h, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = pos) chmf_out_r = min(sup_l-sup_thick, sup_h-base_thick) chmf_out_pos = ( pos + DraftVecUtils.scaleTo(axis_lin, sup_l) + DraftVecUtils.scaleTo(axis_perp, sup_h)) shp_box = fcfun.shp_filletchamfer_dirpt(shp_box, fc_axis = axis_wid, fc_pt = chmf_out_pos, fillet = 0, radius = chmf_out_r) # inside_w # ...+... # ....:__: : : :_______: # : | |_ : || || # sup_h + | |_| _:_ || O || # : | |__|___|___ ||_______|| # :...|_____________| |___:_:___| # :.............: :.........: # + sup_l + tot_w # cut the box inside # Inside width # add one, to have it a minimum of one mm if (reinforce > 0 and (tot_w > 2*(boltmaxhead_r + kcomp.TOL) + 1 )): inside_w = tot_w - 2 * reinforce #print ("inside width " + str(inside_w)) else: #no space for reinforcement, or reinforcement 0 inside_w = tot_w + 2 # +2 to make the cut # chamfer of the inside box chmf_in_r = boltpehead_r logger.debug ("chamfer radius" + str(chmf_in_r)) # inside box: insbox_pos = ( pos + DraftVecUtils.scale(axis_lin,sup_thick) + DraftVecUtils.scale(axis_perp,base_thick)) shp_insbox = fcfun.shp_box_dir (box_w = inside_w, box_d = sup_l, box_h = sup_h, fc_axis_h = axis_perp, fc_axis_d = axis_lin, cw = 1, cd = 0, ch = 0, pos = insbox_pos) if chmf_in_r > 0 : shp_insbox = fcfun.shp_filletchamfer_dirpt(shp_insbox, fc_axis = axis_wid, fc_pt = insbox_pos, fillet = 0, radius = chmf_in_r) #Part.show(shp_insbox) shp_box = shp_box.cut(shp_insbox) #pos_boltpe = pos + DraftVecUtils.scale(axis_perp,sup_h/2.) #shp_boltpe= fcfun.shp_cylcenxtr(r=boltshank_r_tol, # h=brack_thick, # normal = axis_lin, # ch = 0, xtr_top = 1, xtr_bot=1, # pos = pos_boltpe) boltholes = [] for pos_wi in [ DraftVecUtils.scale(axis_wid,-bolt_sup_sep/2.), DraftVecUtils.scale(axis_wid,bolt_sup_sep/2.)]: pos_boltpe = (pos + DraftVecUtils.scale(axis_perp, base_thick +(sup_h-base_thick)/2.) + DraftVecUtils.scale(axis_lin,sup_thick+boltpehead_l) + pos_wi) shp_boltpe = fcfun.shp_2stadium_dir( length = stp_rail_l, r_s = boltpeshank_r_tol, #r_l = boltpehead_r_tol + xtr_bolt_head_d/2., r_l = boltpehead_r + xtr_bolt_head_d/2., h_tot = sup_thick + boltpehead_l, h_rl = boltpehead_l, fc_axis_h = axis_lin_neg, fc_axis_l = axis_perp, ref_l = 1, #ref on the circle center rl_h0 = 1, #bolt head is on pos xtr_h = 1, xtr_nh = 1, pos = pos_boltpe) boltholes.append(shp_boltpe) pos_boltli = pos + DraftVecUtils.scale(axis_lin,bolt1li_dist) #pos_wi_sca = tot_w/2. -2*boltlihead_r - reinforce pos_wi_sca = bolt_sup_sep/2. for pos_wi in [ DraftVecUtils.scale(axis_wid,-pos_wi_sca), DraftVecUtils.scale(axis_wid,pos_wi_sca)]: # 2 Stadium to cut the chamfer if it is too big pos_boltli_top = (pos_boltli + DraftVecUtils.scale(axis_perp, sup_h) + pos_wi) shp_railli = fcfun.shp_2stadium_dir (length = alu_rail_l, r_s = boltlishank_r_tol, r_l = boltlihead_r_tol + kcomp.TOL/2., #extra TOL h_tot = sup_h, h_rl = sup_h-base_thick, fc_axis_h = axis_perp_neg, fc_axis_l = axis_lin, ref_l = 2, #ref on the circle center rl_h0 = 1, #bolt head is on pos xtr_h = 1, xtr_nh = 1, pos = pos_boltli_top) boltholes.append(shp_railli) shp_boltfuse = fcfun.fuseshplist(boltholes) shp_bracket = shp_box.cut(shp_boltfuse) doc.recompute() shp_bracket =shp_bracket.removeSplitter() doc.recompute() self.shp = shp_bracket self.wfco = wfco if wfco == 1: # a freeCAD object is created fco_bracket = doc.addObject("Part::Feature", name ) fco_bracket.Shape = shp_bracket self.fco = fco_bracket def color (self, color = (1,1,1)): if self.wfco == 1: self.fco.ViewObject.ShapeColor = color else: logger.debug("Bracket object with no fco") # exports the shape into stl format def export_stl (self, name = ""): #filepath = os.getcwd() if not name: name = self.name stlPath = filepath + "/stl/" stlFileName = stlPath + name + ".stl" # exportStl is not working well with FreeCAD 0.17 #self.shp.exportStl(stlFileName) mesh_shp = MeshPart.meshFromShape(self.shp, LinearDeflection=kparts.LIN_DEFL, AngularDeflection=kparts.ANG_DEFL) mesh_shp.write(stlFileName) del mesh_shp #doc = FreeCAD.newDocument() #hs = hallestop_holder ( # stp_w = 21., # stp_h = 31., # base_thick = 4., # sup_thick = 5., # bolt_base_d = 3, #metric of the bolt # bolt_sup_d = 3, #metric of the bolt # bolt_sup_sep = 17., # alu_rail_l = 10, # stp_rail_l = 20, # xtr_bolt_head = 0, # xtr_bolt_head_d = 0, # base_min_dist = 1, # reinforce = 4, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'holder') #hs = hallestop_holder ( # stp_w = 21., # stp_h = 31., # base_thick = 3., # sup_thick = 3., # bolt_base_d = 3, #metric of the bolt # bolt_sup_d = 3, #metric of the bolt # bolt_sup_sep = 17., # alu_rail_l = 7, # stp_rail_l = 5, # xtr_bolt_head = 0, # xtr_bolt_head_d = 0, # base_min_dist = 1, # reinforce = 2, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'holder') #hs = hallestop_holder ( # stp_w = 21., # stp_h = 31., # base_thick = 3., # sup_thick = 3., # bolt_base_d = 3, #metric of the bolt # bolt_sup_d = 3, #metric of the bolt # bolt_sup_sep = 17., # alu_rail_l = 10, # stp_rail_l = 10, # xtr_bolt_head = 0, # xtr_bolt_head_d = 0, # base_min_dist = 1, # reinforce = 4, # fc_perp_ax = VZ, # fc_lin_ax = VX, # pos = V0, # wfco=1, # name = 'holder') # for the optical sensor CNY70 and TR class sensor_holder (object): def __init__(self, sensor_support_length = 10., sensor_pin_sep = 2.54, sensor_pin_pos_h = 3, sensor_pin_pos_w = 2, sensor_pin_r_tol = 1.05, sensor_pin_rows = 6, sensor_pin_cols = 6, #sensor_clip_pos_h = 2.45, #position from center #sensor_clip_h_tol = 1.28, #sensor_clip_w_tol = 1., base_height = 37., # height of the cd case base_width = 20., # width of the cd case flap_depth = 8., flap_thick = 2., base_thick = 2., #la altura basesensor_thick = 9., #la altura de la parte de los sensores pos = V0, axis_h = VZ, axis_d = VX, axis_w = VY, wfco=1, name = 'holder'): axis_h = DraftVecUtils.scaleTo(axis_h,1) axis_d = DraftVecUtils.scaleTo(axis_d,1) axis_w = DraftVecUtils.scaleTo(axis_w,1) axis_h_n = DraftVecUtils.scaleTo(axis_h,-1) axis_d_n = DraftVecUtils.scaleTo(axis_d,-1) axis_w_n = DraftVecUtils.scaleTo(axis_w,-1) TOL = 0.4 base_h = base_height + TOL; shp_list = [] shp_base = fcfun.shp_box_dir_xtr(box_w=base_width, box_d=base_thick, box_h=base_h, fc_axis_h=axis_h, fc_axis_d=axis_d, fc_axis_w=axis_w_n, cw=0,cd=0,ch=0, xtr_h=1, xtr_nh=1,pos=V0) shp_list.append(shp_base) sup_sensor_w = (sensor_pin_cols ) * sensor_pin_sep + sensor_pin_pos_w sup_sensor_h = (sensor_pin_rows ) * sensor_pin_sep + sensor_pin_pos_h pos_sup_sensor = ( V0 + DraftVecUtils.scale(axis_d_n, basesensor_thick-base_thick)) shp_sup_sensor = fcfun.shp_box_dir_xtr( box_w=sup_sensor_w, box_d=basesensor_thick, box_h=sup_sensor_h, fc_axis_h=axis_h, fc_axis_d=axis_d, fc_axis_w=axis_w, cw=0,cd=0,ch=0, xtr_h=0, xtr_nw=1,pos=pos_sup_sensor) shp_list.append(shp_sup_sensor) shp_top_flap = fcfun.shp_box_dir_xtr( box_w=base_width, box_d=flap_depth, box_h=flap_thick, fc_axis_h=axis_h, fc_axis_d=axis_d_n, fc_axis_w=axis_w_n, cw=0,cd=0,ch=0, xtr_h=0, xtr_nd=base_thick, pos=FreeCAD.Vector(0,0,base_h)) shp_list.append(shp_top_flap) shp_bot_flap = fcfun.shp_box_dir_xtr( box_w=base_width, box_d=flap_depth, box_h=flap_thick, fc_axis_h=axis_h_n, fc_axis_d=axis_d_n, fc_axis_w=axis_w_n, cw=0,cd=0,ch=0, xtr_h=0, xtr_nd=base_thick, pos=V0) shp_list.append(shp_bot_flap) pos_hole_w = sensor_pin_pos_w holes_list =[] for w_i in range (sensor_pin_cols): pos_hole_h = sensor_pin_pos_h for h_i in range (sensor_pin_rows): pos_pin = (pos_sup_sensor + DraftVecUtils.scale(axis_w, pos_hole_w) + DraftVecUtils.scale(axis_h, pos_hole_h)) shp_pin_hole = fcfun.shp_cylcenxtr(r=sensor_pin_r_tol, h = basesensor_thick, normal = axis_d, ch=0, xtr_top = 1,xtr_bot=1, pos = pos_pin) pos_hole_h = pos_hole_h + sensor_pin_sep holes_list.append(shp_pin_hole) pos_hole_w = pos_hole_w + sensor_pin_sep shp_holes = fcfun.fuseshplist(holes_list) shp_solid = fcfun.fuseshplist(shp_list) shp_final = shp_solid.cut(shp_holes) shp_final = shp_final.removeSplitter() fco_sensor_holder = FreeCAD.ActiveDocument.addObject("Part::Feature", name ) fco_sensor_holder.Shape = shp_final #sensor_holder()