"""Door robot arm: the turret (J1), rebuilt in Coder stage 2 after CRITIQUE_1 item 2 (and item 8: belt drive, bundle). Arm frame A at rest (metres): X forward, Y the arm's left, Z up from the turntable face; J2 at (-0.341, 0, 0.517). ref1 px -> A: X = (1000 - x) * 0.0022, Z = (1550 - y) * 0.0022. What the pictures show (ref1 x 765-1225, y 1200-1395; ref3, ref4, ref7) and how it is built here: - one long, low housing on each side, X -0.50..+0.515, Z 0.345..0.742: chamfered front top, a stepped top line with a long diagonal seam, raised lids, the J2 motor cap set into its rounded rear end. In front of the drum (X > -0.035) the housing is one block across the width (|Y| <= 0.30); behind that only the two side housings (cheeks, |Y| 0.215..0.30) stand beside the drum, so the drum's perforated side face shows behind them (ref3). - J2 motor caps: cylinder stacks standing 0.098 proud of the cheeks, faces at |Y| 0.398 (ref7: inside the carriage's width; the old pods put them at 0.543). - lower block: three stacked rounded slabs, Z 0.06..0.348, 0.60 m wide at the bottom; the middle slab sticks out at the front (the lip), a recessed slot, a raised tab and screws on the sides; the top tier stands only under the housing, never under the drum (the drum and the lower arm's root band turn there). - belt drive (item 8): the white ringed J1 motor with a dark lens stands outboard in front; a wide black belt with big lugs runs on a dark sprocket inboard of it, in two runs back into a pocket in the lower block's front. - cable bundle (item 8): a flat band of seven cables with white clips from a flat gland on the front chamfer down to the clamp over the motor. """ import math import bmesh from mathutils import Vector, Matrix from dra_lib import (Link, lathe, slab, rbox, tube, knurl, merge, xform, frame, basis, mirror_y, fillet, ccw, inset_poly, clip_half, face, W, G, S, R, O, GL, LA, TAU, decal_strip, decal_poly, path_frames, fillet3d) from dra_shapes import (rrect, stadium, xz_slab, yz_slab, xy_slab, screw, dome, hexbolt, ring, cyl, grooved_cyl, holed_plate) from dra_lib import stack as rings_stack J2 = Vector((-0.341, 0.0, 0.517)) HW = 0.292 EDGE = 0.026 # stage 3: the rounded transition from the side faces into the top, front and back # housing core side face; raised panels to 0.300 PANEL = 0.008 CHEEK_IN = 0.215 # cheeks' inner faces (the drum's side faces are at |Y| 0.200, its hubs 0.208) XB = -0.035 # the front block's back face between the cheeks Z_BOT = 0.345 # housing bottom CAP_BASE = HW + PANEL # 0.300 # side outline of the housing (X, Z, round), counter-clockwise. Stage 3 shape pass: behind the stepped top the housing # steps down and ends in an arc round the J2 cap (R_REAR about J2): its top above the cap at Z 0.70 (ref1 x_img 1155: # y_img 1234), so the drum stands 0.06 above it as in ref7 R_REAR = 0.185 def _rear_arc(): out = [] for k in range(13): a = math.radians(74 + (228 - 74) * k / 12) out.append((J2.x + R_REAR * math.cos(a), J2.z + R_REAR * math.sin(a), 0.0)) return out H_OUT = [ (0.515, 0.345, 0.010), (0.515, 0.600, 0.012), (0.452, 0.700, 0.012), (0.240, 0.700, 0.010), (0.192, 0.742, 0.010), (-0.135, 0.742, 0.030), (-0.232, 0.700, 0.020)] + _rear_arc() + [(-0.420, 0.345, 0.030)] def poly_of(outline, n=3): return ccw([p for p, _ in fillet(outline, closed=True, n=n)]) def clip(P, halfplanes): """P (CCW Vector2 list) cut by half planes ((nx, nz), d): keep n . p <= d""" for (nx, nz), d in halfplanes: if len(P) < 3: return [] P = clip_half(P, Vector((nx, nz)), d) return P def to_pts(P, r=0.0): return [(p.x, p.y, r) for p in P] def sided(L, bm, s, pid, mat, seats=()): if s < 0: mirror_y(bm) L.put(bm, mat=mat, pid=pid + ('.L' if s > 0 else '.R'), seats=seats) # ------------------------------------------------------------------ lower block def _lower_block(L): # B1 bottom slab (widest), sits on the turning race T01 (top 0.059) L.put(xy_slab(rrect(0.760, 0.600, 0.070, -0.020, 0.0), 0.060, 0.140, 0.004, 0.006), mat=W, pid='T02', seats=('T01',)) # B2 middle slab: the lip sticks out at the front; a pocket for the belt (Y 0.028..0.114) at the front b2 = [(-0.375, -0.268, 0.060), (0.400, -0.268, 0.075), (0.400, 0.028, 0.006), (0.190, 0.028, 0.008), (0.190, 0.114, 0.008), (0.400, 0.114, 0.006), (0.400, 0.268, 0.075), (-0.375, 0.268, 0.060)] L.put(xy_slab(b2, 0.144, 0.252, 0.005, 0.006), mat=W, pid='T02m', seats=('T02',)) # groove bead between B1 and B2 (dark), a little inside L.put(xy_slab(rrect(0.730, 0.560, 0.055, -0.005, 0.0), 0.139, 0.146, 0.0, 0.0), mat=G, pid='T02g', seats=('T02', 'T02m')) # B3 top tier: in front of the drum across the width (pocket for the belt), and under each cheek b3 = [(XB, -0.262, 0.020), (0.330, -0.262, 0.045), (0.330, 0.028, 0.004), (0.190, 0.028, 0.006), (0.190, 0.114, 0.006), (0.330, 0.114, 0.004), (0.330, 0.262, 0.045), (XB, 0.262, 0.020)] L.put(xy_slab(b3, 0.256, 0.348, 0.005, 0.0), mat=W, pid='T02t', seats=('T02m', 'T03', 'T03c.L', 'T03c.R')) for s in (1, -1): bm = xy_slab(rrect(0.370, 0.063, 0.020, -0.215, 0.2535), 0.256, 0.348, 0.005, 0.0) # 5 mm into the front piece sided(L, bm, s, 'T02t', W, seats=('T02m', 'T03c', 'T02t')) # pocket floor/walls are the slabs themselves; a dark back wall in the pocket L.put(rbox((0.012, 0.086, 0.196), 0.002), Matrix.Translation((0.196, 0.071, 0.248)), G, 'T02p', seats=('T02m', 'T02t', 'T02', 'T03')) # side details: recessed slot on B1, raised tab on B1, slot panel on B2, warning stripes (markings, later) for s in (1, -1): sd = '.L' if s > 0 else '.R' sp = rbox((0.150, 0.040, 0.006), 0.0015, ops=[('+z', -0.066, 0.066, -0.012, 0.012, -0.004)], rbev=0.001) L.put(sp, frame((0.205, s * 0.2985, 0.100), (0, s, 0), spin=math.pi / 2 if s > 0 else -math.pi / 2), G, 'T02c' + sd, seats=('T02',)) L.put(rbox((0.050, 0.014, 0.070), 0.004, rv=0.010, vax=1), Matrix.Translation((0.055, s * 0.302, 0.100)), W, 'T02x' + sd, seats=('T02',)) sp2 = rbox((0.17, 0.056, 0.005), 0.002, ops=[('+z', -0.077, 0.077, -0.020, 0.020, -0.0035)], rbev=0.004, rim_segs=2) L.put(sp2, frame((-0.170, s * 0.2665, 0.198), (0, s, 0)), W, 'T02f' + sd, seats=('T02m',)) # the rear corner glands where the side cable pairs end (B1's sides) L.put(rings_stack([(0.066, 0.016, 'paint_white'), (0.048, 0.030, 'rubber')], 24, base=0.004), frame((-0.280, s * 0.2985, 0.100), (0, s, 0)), None, 'T02d' + sd, seats=('T02',)) # front corner screws on B2's front corners for z in (0.170, 0.200, 0.228): L.put(screw(0.0055), frame((0.3998, s * 0.215, z), 'X'), None, 'T02e' + sd, seats=('T02m',)) # back screw strips on B1 + B2's back faces L.put(rbox((0.006, 0.0396, 0.176), 0.0015), Matrix.Translation((-0.3775, s * 0.114, 0.158)), W, 'T02a' + sd, seats=('T02', 'T02m', 'T02g')) for z in (0.095, 0.158, 0.221): L.put(screw(0.0055), frame((-0.3805, s * 0.114, z), '-X'), None, 'T02a' + sd, seats=('T02a' + sd,)) # back latch: slot plate with a bent tab over its top (ref7 middle) lp = rbox((0.110, 0.180, 0.006), 0.0015, ops=[('+z', -0.022, 0.022, -0.075, 0.075, -0.004)], rbev=0.001) L.put(lp, frame((-0.3785, 0, 0.160), '-X', spin=math.pi / 2), G, 'T02b', seats=('T02', 'T02m', 'T02g')) tab = [(-0.3865, 0, 0.215), (-0.405, 0, 0.215), (-0.405, 0, 0.258), (-0.370, 0, 0.258)] for yy in (-0.016, 0.016): L.put(tube([(x, yy, z) for x, _, z in tab], 0.0045, 10, 0.008), None, S, 'T02b', seats=('T02b', 'T02m')) # dot vent on B3's front face (beside the belt pocket) vent = holed_plate(0.090, 0.056, 0.004, 6, 4, 0.0122, 0.0032, 0.003, mat=G) L.put(vent, frame((0.3295, -0.150, 0.302), 'X', spin=math.pi / 2), None, 'T16', seats=('T02t',)) # ------------------------------------------------------------------ housing def _housing(L): P = poly_of(H_OUT) front = clip(P, [((-1, 0), -XB)]) # X >= XB rear = clip(P, [((1, 0), XB + 0.010)]) # X <= XB + 0.01 (overlaps the block 10 mm: its seat) L.put(xz_slab(to_pts(front), -HW, HW, EDGE, EDGE, n=1, steps=3), mat=W, pid='T03', seats=('T02t',)) for s in (1, -1): bm = xz_slab(to_pts(rear), CHEEK_IN, HW, 0.008, EDGE, n=1, steps=3) sided(L, bm, s, 'T03c', W, seats=('T03', 'T02t')) # raised side panels (8 mm) cut into pieces by the seams of ref1: a horizontal seam at Z 0.575, the long diagonal # down from the step, a vertical seam before the cap, one in front of the connector boss Pi = inset_poly(P, EDGE + 0.006) # the panels sit inside the rounded edges g = 0.002 d1 = Vector((0.192, 0.742)) - Vector((0.090, 0.578)) nd = Vector((d1.y, -d1.x)).normalized() # right of the diagonal (toward +X) cd = nd.dot(Vector((0.090, 0.578))) pieces = [ ("cap", clip(Pi, [((1, 0), -0.175 - g)])), ("upmid", clip(Pi, [((-1, 0), 0.175 - g), ((0, -1), -0.575 - g), ((nd.x, nd.y), cd - g)])), ("upfront", clip(Pi, [((0, -1), -0.575 - g), ((-nd.x, -nd.y), -cd - g)])), ("lowmid", clip(Pi, [((-1, 0), 0.175 - g), ((0, 1), 0.575 - g), ((1, 0), 0.330 - g)])), ("lowfront", clip(Pi, [((0, 1), 0.575 - g), ((-1, 0), -0.330 - g)])), ] for s in (1, -1): for nm, pc in pieces: if len(pc) < 3: continue bm = xz_slab(to_pts(pc), HW - 0.002, HW + PANEL, 0.0, 0.004, n=1, steps=2) sided(L, bm, s, 'T03p', W, seats=('T03', 'T03c', 'T03p')) # a skirt ledge along the housing's foot, standing out 16 mm (a stepped lower edge, ref1 and ref4) led = [(-0.395, 0.350, 0.004), (0.430, 0.350, 0.004), (0.430, 0.372, 0.006), (-0.395, 0.372, 0.006)] bm = xz_slab(led, HW - 0.010, HW + 0.016, 0.0, 0.004, n=1, steps=2) sided(L, bm, s, 'T03f', W, seats=('T03', 'T03c', 'T03p', 'T02t')) # a raised lid along each housing's top behind the step, bent round the cap's arc (ref1: the stepped top line) lid_pts = [(-0.150, 0.744, 0.0), (-0.226, 0.708, 0.0)] + [ (J2.x + (R_REAR + 0.006) * math.cos(math.radians(a)), J2.z + (R_REAR + 0.006) * math.sin(math.radians(a)), 0.0) for a in range(80, 150, 10)] lid_in = [(J2.x + (R_REAR - 0.030) * math.cos(math.radians(a)), J2.z + (R_REAR - 0.030) * math.sin(math.radians(a)), 0.0) for a in range(140, 70, -10)] + [(-0.236, 0.680, 0.0), (-0.152, 0.718, 0.0)] for s in (1, -1): bm = xz_slab(lid_pts + lid_in, CHEEK_IN + 0.030, HW - 0.016, 0.006, 0.006, n=1, steps=2) sided(L, bm, s, 'T03k', W, seats=('T03c', 'T03', 'T03p')) # lids on top: a thin lid on the front top and the raised block behind the step (ref1 x 955-1000) L.put(rbox((0.150, 0.420, 0.016), 0.004, rv=0.02, vax=2), Matrix.Translation((0.365, 0, 0.707)), W, 'T03l', seats=('T03',)) L.put(rbox((0.120, 0.300, 0.034), 0.006, rv=0.03, vax=2), Matrix.Translation((0.040, 0, 0.756)), W, 'T03l', seats=('T03',)) L.put(rings_stack([(0.055, 0.016, 'paint_white'), (0.036, 0.006, 'gunmetal')], 24, base=0.002), frame((0.330, -0.100, 0.715)), None, 'T03a', seats=('T03l',)) # J2 motor caps set into the cheeks' rear ends (ref1: white bezel, dark ring of slots, thin ORANGE ring, dark hub # with rings, hex bolt); they stand 0.098 proud (ref7) for s in (1, -1): sd = '.L' if s > 0 else '.R' Mc = frame((J2.x, s * CAP_BASE, J2.z), (0, s, 0)) cap = rings_stack([(0.280, 0.030, 'paint_white'), (0.262, 0.006, 'paint_white'), (0.226, 0.016, 'gunmetal'), (0.140, 0.010, 'gunmetal'), (0.128, 0.004, 'orange'), (0.118, 0.010, 'gunmetal'), (0.100, 0.008, 'gunmetal'), (0.084, 0.006, 'gunmetal')], 32, base=0.004) L.put(cap, Mc, None, 'T04a' + sd, seats=('T03p' + sd, 'T03c' + sd)) L.put(hexbolt(0.036, 0.016), Mc @ Matrix.Translation((0, 0, 0.090)), None, 'T04b' + sd, seats=('T04a' + sd,)) # ring of slots in the dark ring (12 short notches) for k in range(12): a = TAU * (k + 0.5) / 12 M = Mc @ Matrix.Translation((0.095 * math.cos(a), 0.095 * math.sin(a), 0.0505)) @ Matrix.Rotation(a, 4, 'Z') L.put(rbox((0.020, 0.008, 0.004), 0.001, segs=1), M, G, 'T04n' + sd, seats=('T04a' + sd,)) for k in range(8): a = TAU * (k + 0.5) / 8 L.put(screw(0.005), Mc @ Matrix.Translation((0.123 * math.cos(a), 0.123 * math.sin(a), 0.036)), None, 'T04s' + sd, seats=('T04a' + sd,)) # connector boss (left), cable port glands (both), vent slots (both) L.put(rings_stack([(0.115, 0.020, 'paint_white'), (0.090, 0.006, 'gunmetal'), (0.064, 0.018, 'gunmetal'), (0.030, 0.006, 'steel')], 28, base=0.003), frame((0.385, CAP_BASE, 0.452), 'Y'), None, 'T05', seats=('T03p.L',)) for s in (1, -1): sd = '.L' if s > 0 else '.R' L.put(rings_stack([(0.106, 0.026, 'paint_white'), (0.080, 0.006, 'paint_white'), (0.070, 0.040, 'rubber')], 24, base=0.003), frame((0.160, s * CAP_BASE, 0.445), (0, s, 0)), None, 'T06' + sd, seats=('T03p' + sd,)) sl = rbox((0.036, 0.100, 0.006), 0.0015, ops=[('+z', -0.010, 0.010, -0.040, 0.040, -0.004)], rbev=0.001) L.put(sl, frame((0.461, s * (CAP_BASE - 0.001), 0.420), (0, s, 0)), G, 'T17' + sd, seats=('T03p' + sd,)) # three screw domes along the lower panel's bottom edge for x in (-0.12, 0.05, 0.25): L.put(dome(0.008, 0.005, W), frame((x, s * CAP_BASE, 0.394), (0, s, 0)), None, 'T03s' + sd, seats=('T03p' + sd,)) # ------------------------------------------------------------------ belt drive (item 8) PC = Vector((0.671, 0.0, 0.242)) # sprocket / motor axis (Y) PH = Vector((0.300, 0.0, 0.2425)) # the hidden pulley in the lower block's pocket R_SP = 0.058 # sprocket body radius R_HP = 0.060 BELT_IN = 0.059 # belt inner radius on the sprocket (1 mm over the body) BELT_T = 0.016 LUG = 0.019 BY0, BY1 = 0.040, 0.100 # belt edges (Y) def _belt_drive(L): # inner bracket plate (Y 0.010..0.028) from the housing's front bottom down round the sprocket axle and the idler plate = [(0.455, 0.352, 0.0), (0.600, 0.352, 0.020), (0.735, 0.300, 0.040), (0.742, 0.200, 0.040), (0.690, 0.070, 0.030), (0.610, 0.060, 0.025), (0.585, 0.140, 0.020), (0.455, 0.300, 0.010)] L.put(xz_slab(plate, 0.010, 0.028, 0.003, 0.003), mat=W, pid='T11', seats=('T03', 'T03p.L')) # outer plate: the motor's flange (Y 0.108..0.120) up to the housing's front face plate2 = [(0.515, 0.352, 0.0), (0.640, 0.352, 0.020), (0.742, 0.300, 0.040), (0.760, 0.236, 0.030), (0.700, 0.172, 0.020), (0.600, 0.196, 0.020), (0.515, 0.300, 0.0)] L.put(xz_slab(plate2, 0.108, 0.120, 0.002, 0.002), mat=W, pid='T11', seats=('T03',)) L.put(xz_slab(rrect(0.220, 0.016, 0.004, 0.630, 0.360), 0.010, 0.120, 0.003, 0.003), mat=W, pid='T11', seats=('T11', 'T03')) for x, z in ((0.535, 0.335), (0.585, 0.340), (0.635, 0.346)): L.put(screw(0.0055), frame((x, 0.120, z), 'Y'), None, 'T11s', seats=('T11',)) # sprocket (dark) with flanges, and its axle through both plates prof = [(0.0, 0.032, 0, G), (0.070, 0.032, 0.001, G), (0.070, 0.036, 0.001, G), (R_SP, 0.036, 0, G), (R_SP, 0.104, 0, G), (0.070, 0.104, 0.001, G), (0.070, 0.108, 0.001, G), (0.0, 0.108, 0, G)] L.put(lathe(prof, 32, n=1), frame(PC, 'Y'), None, 'T12p', seats=('T11',)) L.put(cyl(0.012, 0.114, 12, 0.001, S, z0=0.008), frame(PC, 'Y'), S, 'T12x', seats=('T11', 'T12p', 'T12')) # the J1 motor: white ringed drum outboard of the flange plate, 5 grooves, front face with a white bezel and a # dark lens standing out (ref1 x 655-735, y 1400-1475) prof = [(0.0, 0.120, 0, W), (0.086, 0.120, 0.003, W)] y = 0.124 for k in range(5): prof += [(0.088, y, 0.0, W), (0.088, y + 0.0035, 0.0, W), (0.083, y + 0.0045, 0, W), (0.083, y + 0.0060, 0, W), (0.088, y + 0.0070, 0, W)] y += 0.0070 prof += [(0.088, 0.160, 0.004, W), (0.0, 0.160, 0, W)] L.put(lathe(prof, 40, n=1), frame(PC, 'Y'), None, 'T12', seats=('T11',)) L.put(rings_stack([(0.150, 0.008, 'paint_white'), (0.132, 0.006, 'paint_white'), (0.104, 0.006, 'gunmetal'), (0.086, 0.012, 'glass_dark'), (0.040, 0.004, 'gunmetal')], 40, base=0.002), frame((PC.x, 0.160, PC.z), 'Y'), None, 'T12b', seats=('T12',)) # hidden pulley in the pocket (dark), on an axle into the pocket's walls prof = [(0.0, 0.032, 0, G), (0.070, 0.032, 0.001, G), (0.070, 0.036, 0.001, G), (R_HP, 0.036, 0, G), (R_HP, 0.104, 0, G), (0.070, 0.104, 0.001, G), (0.070, 0.108, 0.001, G), (0.0, 0.108, 0, G)] L.put(lathe(prof, 28, n=1), frame(PH, 'Y'), None, 'T14h', seats=('T02m', 'T02t')) L.put(cyl(0.010, 0.090, 12, 0.001, S, z0=0.025), frame(PH, 'Y'), S, 'T14h', seats=('T02m', 'T02t', 'T14h')) # idler (jockey wheel) below the lower run on the inner plate, with its bolt ic = Vector((0.645, 0.0, 0.098)) L.put(lathe([(0.0, 0.028, 0, S), (0.008, 0.028, 0, S), (0.008, 0.040, 0, G), (0.030, 0.040, 0.002, G), (0.030, 0.100, 0.002, G), (0.0, 0.100, 0, G)], 24), frame(ic, 'Y'), None, 'T14', seats=('T11',)) L.put(rings_stack([(0.024, 0.006, 'steel')], 16, base=0.001), frame((ic.x, 0.100, ic.z), 'Y'), None, 'T14', seats=('T14',)) _belt(L) # (the T10 clamp moved to _cables in the fix round: it now holds the band beside the pulley) def _belt(L): """a closed belt (Y BY0..BY1) round the sprocket PC and the hidden pulley PH, flat inner face, big lugs outside""" def P2(c, r, t): return Vector((c.x + r * math.cos(t), c.y + r * math.sin(t))) r1, r2 = BELT_IN + BELT_T / 2, (R_HP + 0.001) + BELT_T / 2 C1, C2 = Vector((PC.x, PC.z)), Vector((PH.x, PH.z)) d = C2 - C1 ang = math.atan2(d.y, d.x) al = math.acos(max(-1.0, min(1.0, (r1 - r2) / d.length))) up, lo = ang - al, ang + al if math.sin(up) < math.sin(lo): up, lo = lo, up pts = [] a0, a1 = up, lo while a1 > a0: a1 -= TAU for k in range(25): pts.append(P2(C1, r1, a0 + (a1 - a0) * k / 24)) b0, b1 = lo, up while b0 < b1: b0 += TAU for k in range(17): pts.append(P2(C2, r2, b0 + (b1 - b0) * k / 16)) # resample the loop evenly (about 6 mm) loop = [] n = len(pts) for i in range(n): a, b = pts[i], pts[(i + 1) % n] m = max(1, int((b - a).length / 0.006)) for j in range(m): loop.append(a.lerp(b, j / m)) n = len(loop) h = BELT_T / 2 bm = bmesh.new() rings = [] for i in range(n): t = (loop[(i + 1) % n] - loop[i - 1]).normalized() nrm = Vector((-t.y, t.x)) # the loop runs clockwise: this points outward rings.append([bm.verts.new((loop[i].x + nrm.x * dn, yy, loop[i].y + nrm.y * dn)) for (yy, dn) in ((BY0, -h), (BY1, -h), (BY1, h), (BY0, h))]) for i in range(n): A, B = rings[i], rings[(i + 1) % n] cen = Vector(((loop[i].x + loop[(i + 1) % n].x) / 2, (BY0 + BY1) / 2, (loop[i].y + loop[(i + 1) % n].y) / 2)) for k in range(4): k2 = (k + 1) % 4 mid = (A[k].co + A[k2].co + B[k].co + B[k2].co) / 4 face(bm, [A[k], A[k2], B[k2], B[k]], R, out=mid - cen) L.put(bm, None, R, 'T13', seats=('T12p', 'T14h', 'T02p', 'T02m', 'T02t', 'T13t')) # lugs every 0.040 m: rectangular blocks 0.020 x (width - 6 mm) x 0.012 on the outer face seg = [(loop[(i + 1) % n] - loop[i]).length for i in range(n)] total = sum(seg) s = 0.02 while s < total - 0.01: acc = 0.0 for i in range(n): if acc + seg[i] >= s: f = (s - acc) / seg[i] p = loop[i].lerp(loop[(i + 1) % n], f) t = (loop[(i + 1) % n] - loop[i]).normalized() nrm = Vector((-t.y, t.x)) M = Matrix(((t.x, 0, nrm.x), (0, 1, 0), (t.y, 0, nrm.y))).to_4x4() M.translation = Vector((p.x + nrm.x * (h + LUG / 2 - 0.0005), (BY0 + BY1) / 2, p.y + nrm.y * (h + LUG / 2 - 0.0005))) L.put(rbox((0.022, BY1 - BY0 - 0.006, LUG), 0.002, segs=1), M, R, 'T13t', seats=('T13', 'T02p', 'T02m', 'T02t', 'T13t')) break acc += seg[i] s += 0.042 # ------------------------------------------------------------------ cables def _cables(L): """T08 gland on the top's front chamfer, T09 the flat band of seven cables, T09c white clips, T10 the white clamp by the belt pulley, T08g the gland it ends in. Fix round (CRITIQUE_2 should 3; ref2 x 740-860 y 1270-1440, ref4 x 260-660 y 520-960): the band leaves the collar on the top, runs forward and down the turret's end close to it, through the clamp beside the pulley (on the drive bracket's -y face) and on down behind the pulley (seen from the arm's left-front) into the lower block. It stays on the drive's -y side: >= 10 mm from the bracket, clear of the belt and the pulley. No loop out and back any more.""" YB = -0.080 # the band's middle (|y| 0.0..0.16, beside the drive) a, b = Vector((0.515, 0.600)), Vector((0.452, 0.700)) t2 = (b - a).normalized() n2 = Vector((t2.y, -t2.x)) # outward (CCW outline) gm = (a + b) / 2 nrm = Vector((n2.x, 0, n2.y)) up = Vector((t2.x, 0, t2.y)) M = basis((gm.x, YB, gm.y), nrm, up) # local z = normal, local x along the chamfer L.put(rbox((0.120, 0.215, 0.050), 0.008, rv=0.012, vax=2), M @ Matrix.Translation((0, 0, 0.018)), W, 'T08', seats=('T03', 'T03p.L', 'T03p.R', 'T03l')) L.put(rbox((0.095, 0.190, 0.016), 0.004), M @ Matrix.Translation((0, 0, 0.044)), R, 'T08r', seats=('T08',)) # the end gland on the lower block's front face (found on the face itself) hit, n = L.snap((0.9, YB, 0.198), (-1, 0, 0)) xe = hit.x if hit is not None else 0.400 Mg = basis((xe, YB, 0.198), (1, 0, 0), (0, 0, 1)) L.put(rbox((0.066, 0.200, 0.034), 0.006, rv=0.010, vax=2), Mg @ Matrix.Translation((0, 0, 0.013)), W, 'T08g', seats=('T02m', 'T02', 'T02t', 'T02g')) L.put(rbox((0.046, 0.180, 0.010), 0.003), Mg @ Matrix.Translation((0, 0, 0.031)), R, 'T08g', seats=('T08g',)) # the band's path: out of the top collar, forward and down in front of the end, through the clamp, down behind the # pulley and back into the lower block's gland p0 = Vector((gm.x, YB, gm.y)) + nrm * 0.046 path = [p0, p0 + nrm * 0.05, Vector((0.640, YB, 0.668)), Vector((0.668, YB, 0.560)), Vector((0.655, YB, 0.400)), Vector((0.632, YB, 0.268)), Vector((0.560, YB, 0.200)), Vector((xe + 0.020, YB, 0.198))] P = fillet3d(path, 0.08, 5) out = [] for i in range(len(P)): a_, b_ = P[max(i - 1, 0)], P[min(i + 1, len(P) - 1)] T = (b_ - a_).normalized() out.append((T, Vector((0, 1, 0)))) # the band's width along y: its flat side faces the front from dra_lib import tube as _tube for k in range(7): off = (k - 3) * 0.0228 pts = [p + Wd * off for p, (T, Wd) in zip(P, out)] L.put(_tube(pts, 0.0105, 8, 0.0, caps=True), None, R, 'T09', seats=('T08', 'T08r', 'T08g', 'T10', 'T09c')) lens = [0.0] for i in range(1, len(P)): lens.append(lens[-1] + (P[i] - P[i - 1]).length) def at(sv): for i in range(1, len(P)): if lens[i] >= sv: f = (sv - lens[i - 1]) / max(1e-9, lens[i] - lens[i - 1]) T, Wd = out[i] Th = T.cross(Wd).normalized() Mc = Matrix((T, Wd, Th)).transposed().to_4x4() Mc.translation = P[i - 1].lerp(P[i], f) return Mc return None # T10 the white clamp by the pulley: two halves round the band (front and back), joined at the drive bracket's # -y face by a block, two bolts and an orange tick on its front half s_cl = min(range(len(P)), key=lambda i: abs(P[i].z - 0.300)) # on the bracket plate's face Mc = at(lens[s_cl]) for side in (1, -1): L.put(rbox((0.080, 0.190, 0.016), 0.003, rv=0.0065, vax=1), Mc @ Matrix.Translation((0, -0.002, side * 0.0215)), W, 'T10', seats=('T09', 'T10', 'T11')) yb = 0.012 - YB # from the band's middle to the bracket's face (y 0.010) L.put(rbox((0.080, 0.014, 0.060), 0.003), Mc @ Matrix.Translation((0, yb - 0.005, 0.0)), W, 'T10', seats=('T10', 'T11', 'T09')) for dy in (-0.060, 0.050): L.put(hexbolt(0.018, 0.007), Mc @ Matrix.Translation((0.0, dy, 0.0295)), None, 'T10b', seats=('T10',)) L.put(rbox((0.006, 0.018, 0.0008), 0.0), Mc @ Matrix.Translation((0.026, -0.012, 0.0298)), O, 'T10t', seats=('T10',), decal=True) # white clips round the band for sv in (0.14, lens[-1] - 0.11): Mk = at(sv) if Mk is not None: L.put(rbox((0.022, 0.178, 0.032), 0.004, rv=0.008, vax=0), Mk, W, 'T09c', seats=('T09',)) def _side_cables(L): """T15: a pair of cables each side from the gland on the housing's lower panel out round and back to the gland at the lower block's rear corner (ref1, ref7)""" from dra_lib import bundle for s in (1, -1): sd = '.L' if s > 0 else '.R' path = [(0.160, s * 0.345, 0.445), (0.160, s * 0.430, 0.410), (0.110, s * 0.535, 0.300), (-0.020, s * 0.575, 0.190), (-0.165, s * 0.520, 0.120), (-0.255, s * 0.420, 0.100), (-0.280, s * 0.345, 0.100)] L.put(bundle(path, 0.0132, [(0.0, 0.028), (0.0, -0.028)], rad=0.085, segs=10), None, R, 'T15' + sd, seats=('T06' + sd, 'T02d' + sd)) for p in ((0.160, s * 0.355, 0.442), (-0.280, s * 0.338, 0.100)): pass # ------------------------------------------------------------------ markings def _markings(L): for s in (1, -1): M = L.on_surface((0.110, s * 0.6, 0.625), (0, -s, 0), up=(0, 0, 1)) if M is None: continue bm = decal_strip([(-0.020, -0.075), (0.020, -0.075), (0.020, 0.075), (-0.020, 0.075)], 0.0026) for k in range(5): y0 = -0.058 + k * 0.026 st = decal_poly([(-0.016, y0 - 0.006), (-0.016, y0 + 0.004), (0.016, y0 + 0.016), (0.016, y0 + 0.006)]) merge(bm, st) st.free() ln = decal_poly([(0.027, -0.075), (0.031, -0.075), (0.031, 0.040), (0.027, 0.040)]) merge(bm, ln) ln.free() if s < 0: xform(bm, Matrix.Scale(-1, 4, Vector((0, 1, 0)))) L.decal(bm, M, 'T07' + ('.L' if s > 0 else '.R')) M = L.on_surface((-0.330, 0.6, 0.205), (0, -1, 0), up=(0, 0, 1)) if M is not None: bm = decal_strip([(-0.030, -0.026), (0.030, -0.026), (0.030, 0.026), (-0.030, 0.026)], 0.0024) for k in range(3): y0 = -0.020 + k * 0.016 st = decal_poly([(-0.025, y0), (-0.025, y0 + 0.006), (0.025, y0 + 0.012), (0.025, y0 + 0.006)]) merge(bm, st) st.free() L.decal(bm, M, 'T07a') M = L.on_surface((0.252, 0.6, 0.095), (0, -1, 0), up=(0, 0, 1)) if M is not None: L.decal(decal_poly([(-0.0017, -0.020), (0.0017, -0.020), (0.0017, 0.020), (-0.0017, 0.020)]), M, 'D10') def build_turret(): L = Link('turret') # T01 turning race: an inner ring inside the fixed race, three stacked rings with two V grooves prof = [(0.0, 0.010, 0, G), (0.246, 0.010, 0.002, G), (0.246, 0.036, 0.001, G), (0.288, 0.038, 0.002, G), (0.288, 0.0425, 0, G), (0.2845, 0.0450, 0, G), (0.288, 0.0475, 0, G), (0.288, 0.0505, 0, G), (0.2845, 0.0530, 0, G), (0.288, 0.0555, 0, G), (0.288, 0.061, 0.001, G), (0.0, 0.061, 0, G)] L.put(lathe(prof, 48), None, None, 'T01') _lower_block(L) _housing(L) _belt_drive(L) _cables(L) _side_cables(L) _markings(L) return L