chiark / gitweb /
sewing-table: FrontCurve: adjust from print
[reprap-play.git] / filamentspool.scad
1 // -*- C -*-
2
3 // filamentspool.scad
4 // 3D design for filament spools to hold coils as supplied by Faberdashery
5 //
6
7 //
8 // Copyright 2012,2013,2016 Ian Jackson
9 //
10 // This work is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // This work is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this work.  If not, see <http://www.gnu.org/licenses/>
22 //
23
24 //
25 // Each spool is a hub with 3 or 4 arms.  Each arm has a cup for
26 // holding the filament.  The effective diameter can be adjusted by
27 // setting the cup into a different seat in the arm.  The cups are
28 // held on with simple clips, so the filement coil can easily be
29 // removed and replaced.
30 //
31 // This file (and its includes) can generate:
32 //
33 // ===== Heavy duty 4-armed spool for 3mm x 100m coil =====
34 //
35 // A heavy duty 4-armed spool suitable for holding a 100m
36 // Faberdashery coil on the spool arm of a Lulzbot TAZ-5.
37 //
38 //     Set
39 //           fdia=2.85
40 //           lightduty=false
41 //     And print following parts
42 //            Hub
43 //            ArmEnd x 4
44 //            FilamentCup x 4  (or FilamentCupPair x 2)
45 //            CupSecuringClip x 4
46 //
47 //     You will also need  4 x M4 machine screws and nuts.
48 //
49 //     This is the default.
50 //
51 // ===== Light duty 3-armed spool for 3mm x <=30m coil =====
52 //
53 // A light duty 3-armed spool suitable for up to around 30m
54 // of Faberdashery 2.85mm PLA.
55 //
56 //     Set
57 //           fdia=2.85
58 //           lightduty=true
59 //     (or look in filamentspool-lt.scad).
60 //
61 //     And print following parts
62 //           Hub
63 //           ArmEnd x 3
64 //           FilamentCup x 3  (or FilamentCup + FilamentCupPair)
65 //           CupSecuringClip x 3
66 //           TowerDoveClipPin x 6
67 //
68 //     When assembling, insert one TowerDoveClipPin from each side,
69 //     joining each ArmEnd to the Hub with two TowerDoveClipPins.
70 //     Modest force with pliers is good to seat them properly.
71 //
72 //     (note that the light duty and heavy duty CupSecuringClips
73 //      are slightly different)
74 //
75 // ===== Notes regarding both the above spools =====
76 //
77 // When mounting either spool on the TAZ-5 spool arm, put the `pointy'
78 // end of the hub towards the printer - ie, put put the spool on
79 // `backwards'.  This ensures that the spool's arms will clear the
80 // printer framework.
81 //
82 // For the above, I generally used the Cura `Standard' PLA profile.
83 //
84 // ===== TAZ-5 feed tube adjustment kit =====
85 //
86 // With a TAZ-5 I recommend using this kit to improve the feed
87 // reliability:
88 //
89 //       Set
90 //           fdia=2.85
91 //     And print following parts
92 //           FilamentGuideSpacer (ideally, at `high detail')
93 //           FilamentGuideArmPrint (optional; `high detail' or `standard')
94 //
95 //     And possibly also
96 //           t-nut_jig_0.2.stl
97 //     from Aleph Objects - look here:
98 //           http://download.lulzbot.com/TAZ/accessories/tool_heads/version_2/Dual_Extruder_v2/production_parts/stl/
99 //
100 // The spacer clips onto the filament guide tube holder arm, on the
101 // inside, with the pointy flanged end towards the filament guide
102 // tube.  It stops the filament guide tube angle (and so the
103 // filament's natural pickup location) changing as the print head moves.
104 //
105 // The FilamentGuideArm[Print] is a replacement for the arm supplied
106 // with your TAZ-5.  It's longer, so that the filament pickup point is
107 // closer to the middle of the coil.  Use the t-nut_jig to stop the
108 // T-nuts in the aluminium channel from annoyingly sliding down to the
109 // bottom while you swap out the arm.
110 //
111 // (Faberdashery coils, and therefore both the above spools, have a
112 // larger diameter than the flat-walled spools often supplied by other
113 // vendors.  And the spools above have individual arms rather than a
114 // continuous disc.  If the filament `unhooks' from the arm, it can
115 // pull taught around the hub and stop feeding properly.)
116 //
117 // ===== Spool storage arm, for mounting on walls =====
118 //
119 // A storage arm suitable for screwing to walls, bookshelves,
120 // etc. (requires non-countersunk M4 screws); will hold two heavy duty
121 // spools each with a 100m coil.
122 //
123 //     Set
124 //           fdia=2.85
125 //           lightduty=false
126 //     And print one of these, according to taste
127 //            StorageArmLeft
128 //            StorageArmRight
129 //
130 //     NB that the `light duty' version of this is shorter and
131 //     will only take two `light duty' spools.
132 //
133 // A longer arm for three spools is also available:
134 //     Set
135 //           fdia=2.85
136 //           lightduty=false
137 //           storarm_spools=3
138 //     (or look in filamentspool-storarm3.scad).
139 //
140 //     And print one of these, according to taste
141 //            StorageArmLeft
142 //            StorageArmRight
143 //
144 // For all of these, I used the Cura `High detail' PLA profile because
145 // I wanted it pretty, but the `Standard' profile should do fine.
146 //
147 // ===== Spools for 1.75mm filament =====
148 //
149 // Spool (in many parts) for handing 1.75mm filament, printable
150 // on, and with parts for mounting on, a Reprappro Huxley.
151
152
153 fdia=2.85; // or 1.75
154 lightduty=false; // or true
155
156
157 slop=0.5;
158 bigslop=slop*2;
159
160 function selsz(sm,lt,lg) = fdia < 2 ? sm : lightduty ? lt : lg;
161 function usedove() = selsz(true,true,false);
162
163 num_arms = selsz(3,3,4);
164
165 channelslop=selsz(slop,0.75,slop);
166
167 exteffrad = 70;
168 hubeffrad = selsz(30, 82, 40);
169 hubbigrad = selsz(20, 38, 38);
170 hublwidth = selsz(3, 2.5, 3.0);
171 hubstemwidth = 2;
172 hublthick = 10;
173 hubaxlerad = selsz(5, 28/2, 28/2);
174 totalheightfromtower = 240;
175 axletowerfudgebend = 0;
176 axleaxlefudgebend = 3;
177 axlepadlen = 1.0;
178
179 armend_length = 120;
180
181 prongthick=selsz(5,4,5);
182 prongwidth=selsz(5,4,5);
183 prongribwidth=3;
184 prongribheight=selsz(0,0,4);
185 ratchetstep=15;
186 ratchettooth=3;
187 ratchettoothheight=5;
188 ratchettoothsmoothr=1;
189 ratchettoothslope=0.75;
190 overlap=0.5;
191 cupwidth=selsz(40,25,50);
192 cupheight=selsz(75,35,75);
193
194 cupstrong_dx=selsz(0,0,-10);
195
196 propxshift = -6;
197
198 doveclipheight = 10;
199
200 teethh=3;
201 teethgapx=4+fdia;
202
203 prongstalkxwidth=3;
204
205 stalklength=selsz(35,25,55);
206 overclipcupgap=5;
207 overclipdepth=15;
208 overcliproundr=2.0;
209 overclipthick=1.0;
210 overclipcupnextgap=selsz(20,15,20);
211
212 hubaxlelen = selsz(25, 62.5, 77.5);
213 echo(hubaxlelen);
214
215 overclipsmaller=-2.5;
216 overclipbigger=0.0;
217
218 wingspoke=2.5;
219 wingsize=6;
220 wingthick=3;
221
222 armendwallthick=selsz(2.5, 1.8, 2.5);
223 armendbasethick=selsz(1.2, 1.2, 1.2);
224
225 numbers_relief = 0.7;
226 numbers_tick_len = 8;
227 numbers_tick_width = 0.75;
228 numbers_tick_linespc = 1.0;
229 numbers_height_allow = 8;
230
231 axlehorizoffset = 12.5;
232 axlevertheight = 100;
233 towercliph = 16;
234 towerclipcount = 3;
235 towerpillarw = 5;
236
237 axlepinrad = 2;
238 axlepintabrad = 5;
239
240 washerthick = 1.2;
241 washerthinthick = 0.8;
242 washerverythinthick = 0.4;
243 washerrad = hubaxlerad + 7.5;
244 frictionwasherarmwidth = 3;
245 frictionwasherextrapush = 1.0;
246
247 ratchetpawl=ratchetstep-ratchettooth-bigslop*2;
248
249 nondove_armhole_x = 32;
250 nondove_armhole_hole = 4 + 0.8;
251 nondove_armhole_support = 7;
252 nondove_armhole_wall = 3.2;
253 nondove_armhole_slop = 0.5;
254 nondove_armhole_slop_x = 0.5;
255
256 nondove_armbase = nondove_armhole_x + nondove_armhole_hole/2 +
257   nondove_armhole_support;
258 echo(nondove_armbase);
259
260 include <doveclip.scad>
261 include <cliphook.scad>
262 include <filamentteeth.scad>
263 include <axlepin.scad>
264 include <commitid.scad>
265
266 hub_clip_baseextend = (hubeffrad - DoveClip_depth()
267                        - hubbigrad + hublwidth);
268
269 real_exteffrad = selsz(exteffrad + hub_clip_baseextend,
270                        hubeffrad + DoveClip_depth(),
271                        hubeffrad + nondove_armbase);
272
273 channelwidth = prongthick + channelslop;
274 channeldepth = prongwidth + ratchettoothheight;
275 totalwidth = armendwallthick*2 + channelwidth;
276 totalheight = channeldepth + armendbasethick;
277 stalkwidth = prongwidth + prongstalkxwidth;
278
279 tau = PI*2;
280
281 module ArmEnd(length=armend_length){ ////toplevel
282   if (usedove()) {
283     translate([ratchettoothsmoothr, channelwidth/2, -armendbasethick]) {
284       rotate([0,0,-90])
285         DoveClipPairBase(h=doveclipheight);
286     }
287   } else {
288     difference(){
289       translate([1, -armendwallthick, -armendbasethick])
290         mirror([1,0,0])
291         cube([nondove_armbase+1, totalwidth, totalheight]);
292       translate([-nondove_armbase + nondove_armhole_x,
293                  -armendwallthick + totalwidth/2,
294                  -armendbasethick -1])
295         cylinder(r= nondove_armhole_hole/2, h=totalheight+2, $fn=10);
296       translate([-nondove_armbase, -armendwallthick, -armendbasethick])
297         rotate([90,0,0])
298         Commitid_BestCount([nondove_armbase, totalwidth]);
299     }
300   }
301
302   difference(){
303     union(){
304       difference(){
305         translate([0, -armendwallthick, -armendbasethick])
306           cube([length, totalwidth, totalheight]);
307         translate([-1, 0, 0])
308           cube([length+1 - ratchettooth, channelwidth, channeldepth+1]);
309         translate([-1, 0, ratchettoothheight])
310           cube([length+2, channelwidth, channeldepth+1]);
311       }
312       for (dx = [0 : ratchetstep : length - ratchetstep]) translate([dx,0,0]) {
313         translate([ratchettoothsmoothr+0.5, armendwallthick/2, 0]) minkowski(){
314           rotate([90,0,0])
315             cylinder($fn=20, r=ratchettoothsmoothr, h=armendwallthick);
316           multmatrix([  [       1, 0, ratchettoothslope, 0      ],
317                             [   0,      1,      0,      0       ],
318                             [   0,      0,      1,      0       ],
319                             [   0,      0,      0,      1       ]])
320             cube([ratchettooth - ratchettoothsmoothr*2,
321                   channelwidth, ratchettoothheight - ratchettoothsmoothr]);
322         }
323       }
324     }
325
326     for (otherside=[0,1]) {
327       for (circum = [300:100:1500]) {
328         assign(rad = circum / tau)
329           assign(fn = str("filamentspool-number-n",circum,".dxf"))
330           assign(rotateoffset = [0, totalwidth/2, 0])
331           assign(xlen = rad - real_exteffrad) {
332           if (xlen >= numbers_tick_width/2
333               + (otherside ? numbers_height_allow : 0) &&
334               xlen <= length - (otherside ? 0 : numbers_height_allow))
335             translate([xlen, -armendwallthick,
336                        -armendbasethick + (totalheight - numbers_tick_len)/2])
337             translate(rotateoffset)
338             rotate([0,0, otherside*180])
339             translate(-rotateoffset){
340               translate([-numbers_tick_width/2, -1, 0])
341                 cube([numbers_tick_width, numbers_relief+1, numbers_tick_len]);
342               translate([numbers_tick_width/2 + numbers_tick_linespc,
343                          1,
344                          numbers_tick_len])
345                 rotate([90,0,0])
346                 rotate([0,0,-90])
347                 linear_extrude(height= numbers_relief+1)
348                 //    scale(templatescale)
349                 import(file=fn, convexity=100);
350             }
351         }
352       }
353     }
354
355     if (usedove()){
356       translate([0, -armendwallthick, -armendbasethick])
357         Commitid_BestCount_M([length/3, totalwidth]);
358     }
359   }
360 }
361
362 module FilamentCupHandle(){
363   pawlusewidth = ratchetpawl-ratchettoothsmoothr*2;
364   mirror([0,1,0]) {
365     cube([stalklength, stalkwidth, prongthick]);
366     translate([stalklength, stalkwidth/2, 0])
367       cylinder(r=stalkwidth/2, h=prongthick, $fn=20);
368     translate([ratchettoothsmoothr, stalkwidth, 0]) {
369       minkowski(){
370         cylinder($fn=20,r=ratchettoothsmoothr, h=1);
371         multmatrix([    [       1, -ratchettoothslope, 0, 0     ],
372                         [       0,      1,      0,      0       ],
373                         [       0,      0,      1,      0       ],
374                         [       0,      0,      0,      1       ]])
375           cube([pawlusewidth,
376                 ratchettoothheight - ratchettoothsmoothr,
377                 prongthick - 1]);
378       }
379     }
380   }
381 }
382
383 module FilamentCupCup(){
384   for (my=[0,1]) mirror([0,my,0]) {
385     translate([0, cupwidth/2, 0])
386       cube([cupheight + prongwidth, prongwidth, prongthick]);
387   }
388 }
389
390 module FilamentCupPositive() {
391   FilamentCupHandle();
392
393   gapy = prongwidth;
394   dy = cupwidth/2 + gapy + overclipcupgap;
395   baselen = dy+cupwidth/2;
396
397   translate([0, dy, 0])
398     FilamentCupCup();
399   cube([prongwidth, baselen+1, prongthick]);
400
401   translate([cupstrong_dx, prongwidth, 0]) {
402     cube([prongwidth, baselen-prongwidth, prongthick]);
403     for (y = [0, .33, .67, 1])
404       translate([0, (baselen - prongwidth) * y, 0])
405         cube([-cupstrong_dx + 1, prongwidth, prongthick]);
406   }
407   if (cupstrong_dx != 0) {
408     rotate([0,0,45])
409       translate([-prongwidth*.55, -prongwidth*2.1, 0])
410       cube([prongwidth*(2.65), prongwidth*4.2, prongthick]);
411   }
412
413   translate([0, -0.2, 0])
414     cube([prongribwidth, baselen, prongthick + prongribheight]);
415
416   if (prongribheight > 0) {
417     translate([-prongwidth, baselen, 0])
418       cube([cupheight/2, prongwidth + prongribheight, prongribwidth]);
419   }
420
421   midrad = cupwidth/2 + prongwidth/2;
422
423   propshift = stalklength - overclipdepth - prongthick + propxshift;
424   proptaken = propshift;
425   echo(midrad, propshift, proptaken);
426
427   translate([propshift, -1, 0]) {
428     // something is wrong with the y calculation
429     cube([prongwidth,
430           gapy+2,
431           prongthick]);
432   }
433   for (y = [overclipcupgap, overclipcupgap+overclipcupnextgap]) {
434     translate([cupstrong_dx, y + prongwidth, 0])
435       rotate([0,0, 102 + fdia])
436       FilamentTeeth(fdia=fdia, h=teethh);
437   }
438   for (x = [-0.3, -1.3]) {
439     translate([cupheight + overclipcupnextgap*x, baselen + prongwidth, 0])
440       rotate([0,0, 12 + fdia])
441       FilamentTeeth(fdia=fdia, h=teethh);
442   }      
443 }
444
445 module FilamentCup() { ////toplevel
446   difference(){
447     FilamentCupPositive();
448     translate([0, -stalkwidth, 0])
449       Commitid_BestCount_M([stalklength - stalkwidth, stalkwidth]);
450   }
451 }
452
453 module CupSecuringClipSolid(w,d,h1,h2){
454   rotate([0,-90,0]) translate([0,-h1/2,-w/2]) linear_extrude(height=w) {
455     polygon(points=[[0,0], [d,0], [d,h2], [0,h1]]);
456   }
457 }
458
459 module CupSecuringClipSolidSmooth(xrad=0, xdepth=0){
460   hbase = totalheight + prongstalkxwidth - overcliproundr*2;
461   minkowski(){
462     CupSecuringClipSolid(w=totalwidth,
463                          d=overclipdepth + xdepth,
464                          h1=hbase - overclipsmaller,
465                          h2=hbase + overclipbigger);
466     cylinder($fn=20, h=0.01, r=overcliproundr+xrad);
467   }
468 }
469
470 module CupSecuringClip(){ ////toplevel
471   wingswidth = wingspoke*2 + overclipthick*2 + overcliproundr*2 + totalwidth;
472   difference(){
473     union(){
474       CupSecuringClipSolidSmooth(xrad=overclipthick, xdepth=0);
475       translate([-wingswidth/2, -wingsize/2, 0])
476         cube([wingswidth, wingsize, wingthick]);
477       translate([-wingsize/2, -wingswidth/2, 0])
478         cube([wingsize, wingswidth, wingthick]);
479     }
480     translate([0,0,-0.1])
481       CupSecuringClipSolidSmooth(xrad=0, xdepth=0.2);
482   }
483 }
484
485 module ArmDoveClipPin(){ ////toplevel
486   DoveClipPin(h=doveclipheight);
487 }
488
489 module TowerDoveClipPin(){ ////toplevel
490   DoveClipPin(h=towercliph/2);
491 }
492
493 module Hub(){ ////toplevel
494   axlerad = hubaxlerad + slop;
495   xmin = axlerad+hublwidth/2;
496   xmax = hubbigrad-hublwidth/2;
497   hole = hubeffrad - hubbigrad - DoveClip_depth() - hublwidth*2;
498   holewidth = DoveClipPairSane_width() - hubstemwidth*2;
499   nondove_allwidth = nondove_armhole_wall*2 + totalwidth;
500   difference(){
501     union(){
502       difference(){
503         cylinder($fn=60, h=hublthick, r=hubbigrad);
504         translate([0,0,-1])
505           cylinder($fn=30, h=hublthick+2, r=(hubbigrad-hublwidth));
506       }
507       cylinder(h=hubaxlelen, r=axlerad+hublwidth);
508       for (ang=[0 : 360/num_arms : 359])
509         rotate([0,0,ang]) {
510           if (usedove()){
511             difference() {
512               translate([hubeffrad,0,0])
513                 DoveClipPairSane(h=doveclipheight,
514                                  baseextend = hub_clip_baseextend);
515               if (hole>hublwidth && holewidth > 2) {
516                 translate([hubbigrad + hublwidth, -holewidth/2, -1])
517                   cube([hole, holewidth, hublthick+2]);
518               }
519             }
520           } else {
521             difference(){
522               translate([0,
523                          -nondove_allwidth/2,
524                          0])
525                 cube([hubeffrad + nondove_armhole_x
526                       + nondove_armhole_hole/2 + nondove_armhole_support,
527                       nondove_allwidth,
528                       nondove_armhole_wall + totalheight]);
529               translate([hubeffrad - nondove_armhole_slop_x,
530                          -nondove_allwidth/2
531                          + nondove_armhole_wall - nondove_armhole_slop,
532                          nondove_armhole_wall])
533                 cube([nondove_armhole_x + 50,
534                       totalwidth + nondove_armhole_slop*2,
535                       totalheight + 1]);
536               translate([hubeffrad + nondove_armhole_x, 0, -20])
537                 cylinder(r= nondove_armhole_hole/2, h=50, $fn=10);
538             }
539           }
540         }
541       for (ang = [0 : 180/num_arms : 359])
542         rotate([0,0,ang]) rotate([90,0,0]) {
543           translate([0,0,-hublwidth/2])
544             linear_extrude(height=hublwidth)
545             polygon([[xmin,0.05], [xmax,0.05],
546                      [xmax,hublthick-0.2], [xmin, hubaxlelen-0.2]]);
547         }
548     }
549     translate([0,0,-1]) cylinder($fn=60, h=hubaxlelen+2, r=axlerad);
550
551     rotate([0,0, selsz(0,0,45)])
552       translate([axlerad+hublwidth,
553                  -hublwidth/2,
554                  0])
555       rotate([90,0,0])
556       Commitid_BestCount([(hubbigrad-hublwidth) - (axlerad+hublwidth),
557                           hublthick +
558                           hublwidth/2 * hubaxlelen/(hubbigrad-axlerad),
559                           ]);
560   }
561 }
562
563 module ArmExtender(){ ////toplevel
564   DoveClipExtender(length=exteffrad-hubeffrad,
565                    ha=doveclipheight,
566                    hb=doveclipheight);
567 }
568
569 module FsAxlePin(){ ////toplevel
570   AxlePin(hubaxlerad, washerrad*2, axlepinrad, axlepintabrad, slop);
571 }
572
573 module Axle(){ ////toplevel
574   pillarswidth = DoveClipPairSane_width(towerclipcount);
575
576   rotate([0,0, -( axleaxlefudgebend + atan(slop/hubaxlelen) ) ])
577   translate([-axlehorizoffset, -axlevertheight, 0]) {
578     rotate([0,0,-axletowerfudgebend])
579     rotate([0,0,-90])
580       DoveClipPairSane(h=towercliph, count=towerclipcount, baseextend=3);
581     translate([0, DoveClip_depth(), 0])
582     rotate([0,0,90])
583       ExtenderPillars(axlevertheight - DoveClip_depth(),
584                       pillarswidth, towercliph,
585                       pillarw=towerpillarw);
586   }
587
588   axleclearlen = hubaxlelen + slop*4 + washerthick*2 + axlepadlen;
589   axlerad = hubaxlerad-slop;
590   bump = axlerad * 0.2;
591   shift = axlerad-bump;
592   joinbelowallow = 3;
593
594   intersection(){
595     translate([0, 0, shift]) {
596       difference() {
597         union(){
598           translate([-1, 0, 0])
599             rotate([0,90,0])
600             cylinder($fn=60,
601                      r = axlerad,
602                      h = 1 + axleclearlen + axlepinrad*2 + 2);
603           mirror([1,0,0]) rotate([0,90,0])
604             cylinder(r = axlerad*1.75, h = 3);
605           intersection(){
606             mirror([1,0,0])
607               translate([axlehorizoffset - pillarswidth/2, 0, 0])
608               rotate([0,90,0])
609               cylinder($fn=60,
610                        r = towercliph - shift,
611                        h = pillarswidth);
612             translate([-50, -joinbelowallow, -50])
613               cube([100, joinbelowallow+50, 100]);
614           }
615         }
616         rotate([90,0,0])
617         translate([axleclearlen + axlepinrad/2, 0, -25])
618           cylinder(r = axlepinrad + slop, h=50);
619       }
620     }
621     translate([-50,-50,0]) cube([100,100,100]);
622   }
623 }
624
625 module washer(thick){
626   Washer(hubaxlerad, washerrad, thick, slop);
627 }
628
629 module AxleWasher(){ ////toplevel
630   washer(thick=washerthick);
631 }
632
633 module AxleThinWasher(){ ////toplevel
634   washer(thick=washerthinthick);
635 }
636
637 module AxleVeryThinWasher(){ ////toplevel
638   washer(thick=washerverythinthick);
639 }
640
641 module AxleFrictionWasher(){ ////toplevel
642   difference(){
643     cylinder(h=washerthick, r=washerrad);
644     translate([0,0,-1]) cylinder(h=washerthick+2, r=hubaxlerad+slop);
645   }
646   frarmr = hubbigrad;
647   frarmw = frictionwasherarmwidth;
648   frarmpawlr = hublwidth;
649   frarmpawlpush = slop*4 + frictionwasherextrapush;
650   for (ang=[0,180]) rotate([0,0,ang]) {
651     translate([washerrad-1, -frarmw/2, 0])
652       cube([frarmr - washerrad + 1, frarmw, washerthick]);
653     intersection(){
654       translate([frarmr - frarmpawlr, -50, 0])
655         cube([frarmpawlr, 100, 50]);
656       rotate([0,90,0])
657         cylinder(h = 50, r = frarmpawlpush, $fn=36);
658     }
659   }
660 }
661
662 module TowerExtender(){ ////toplevel
663   l = totalheightfromtower - axlevertheight;
664   echo("TowerExtender",l);
665   DoveClipExtender(length = l,
666                    ha = towercliph, hb = towercliph,
667                    counta = towerclipcount, countb = towerclipcount,
668                    pillarw = towerpillarw);
669 }
670
671 module FilamentCupPair(){ ////toplevel
672   FilamentCup();
673   translate([cupheight + prongthick*3,
674              cupwidth/2*1.7,
675              0])
676     rotate([0,0,180]) FilamentCup();
677 }
678
679 //----- storarm -----
680
681 storarm_hooklen = 8;
682 storarm_hookheight = 5;
683 storarm_thick = 10;
684 storarm_axleslop = 4;
685
686 storarm_base_w = 30;
687 storarm_base_h = 100;
688 storarm_base_d = 15;
689 storarm_base_mind = 2;
690
691 storarm_cope_hubaxle_mk1 = true;
692
693 storarm_screw_hole = 4;
694 storarm_screw_hole_slop = 0.5;
695 storarm_besides_hole = 4;
696
697 storarm_under_hole = 5;
698 storarm_screw_hole_head = 8.8;
699 storarm_screw_hole_head_slop = 1.5;
700
701 // calculated
702
703 storarm_spools = 2;
704
705 storarm_axlerad = hubaxlerad - storarm_axleslop;
706 storarm_mainlen = hubaxlelen*storarm_spools
707   + storarm_axleslop*(storarm_spools-1)
708   + (storarm_cope_hubaxle_mk1 ? 10 : 0);
709 storarm_totlen = storarm_mainlen + storarm_hooklen;
710
711 storarm_taller = storarm_axleslop * (storarm_spools-2);
712
713 storarm_mid_off_y = storarm_axlerad;
714
715 storarm_base_off_y = storarm_mid_off_y + storarm_base_h/2;
716
717 module StorageArmDiagPartSide(xmin, xmax){
718   xsz = xmax-xmin;
719   yuse = storarm_thick/2;
720
721   intersection(){
722     translate([xmin-1, -storarm_axlerad, storarm_thick/2])
723       rotate([0,90,0])
724       cylinder(r=storarm_axlerad, h=xsz+2, $fn=60);
725     translate([xmin, -yuse, 0])
726       cube([xsz, yuse, storarm_thick]);
727   }
728 }
729
730 module StorageArmDiagPart(xmin, xmax, adjbot, shear){
731   hull(){
732     StorageArmDiagPartSide(xmin,xmax);
733
734     multmatrix([[1,0,0,0],
735                 [shear,1,0,0],
736                 [0,0,1,0],
737                 [0,0,0,1]])
738       translate([0, -storarm_axlerad*2 + adjbot, 0])
739       mirror([0,1,0])
740       StorageArmDiagPartSide(xmin,xmax);
741   }
742 }
743
744 module StorageArmBaseTemplate(){
745   square([storarm_base_w, storarm_base_h]);
746 }
747
748 module StorageArmAtMountingHoles(){
749   bes = storarm_besides_hole + storarm_screw_hole;
750
751   x0 = bes;
752   x1 = storarm_base_w-bes;
753   y1 = storarm_base_h - bes;
754   y0 = bes;
755
756   for (pos=[ [x0, y1],
757              [x1, y1],
758              [x1, y0] ]) {
759     rotate([0,90,0])
760       translate([pos[0] - storarm_base_w,
761                  pos[1] - storarm_base_off_y, -storarm_base_d])
762       children();
763   }
764 }
765
766 module StorageArmRight(){ ////toplevel
767   shear = storarm_hookheight / (storarm_mainlen/2);
768   shear2 = shear + storarm_taller / (storarm_mainlen/2);
769   base_xyz = [-storarm_base_d, -storarm_base_off_y, storarm_base_w];
770
771   StorageArmDiagPart(-1, storarm_mainlen/2+1,
772                      -storarm_taller, shear2);
773   StorageArmDiagPart(storarm_mainlen/2-1, storarm_mainlen+1,
774                      storarm_hookheight/2, shear/2);
775
776   translate([0, storarm_hookheight, 0])
777     StorageArmDiagPart(storarm_mainlen, storarm_totlen,
778                        -storarm_hookheight/2, shear/2);
779
780   difference(){
781     union(){
782       hull(){
783         translate(base_xyz)
784           rotate([0,90,0])
785           linear_extrude(height=storarm_base_mind)
786           StorageArmBaseTemplate();
787         StorageArmDiagPart(-1, 0, -storarm_taller, shear);
788       }
789       StorageArmAtMountingHoles(){
790         cylinder(r= storarm_screw_hole_head/2,
791                  h=10);
792       }
793     }
794     StorageArmAtMountingHoles(){
795       translate([0,0,-1])
796         cylinder(r= (storarm_screw_hole + storarm_screw_hole_slop)/2 ,
797                  h=20);
798       translate([0,0,storarm_under_hole])
799         cylinder(r= (storarm_screw_hole_head + storarm_screw_hole_head_slop)/2,
800                  h=20);
801     }
802     translate(base_xyz + [0, storarm_base_h/4, -storarm_base_w/4])
803       rotate([0,90,0])
804       Commitid_BestCount([storarm_base_w/2, storarm_base_h/2]);
805   }
806 }
807
808 module StorageArmLeft(){ ////toplevel
809   mirror([1,0,0]) StorageArmRight();
810 }
811
812 module StorArmHoleTest(){ ////toplevel
813   sz = storarm_screw_hole_head + storarm_besides_hole*2;
814   intersection(){
815     StorageArmRight();
816     translate([-50, -storarm_base_off_y, -1])
817       cube([100, sz, sz+1]);
818   }
819 }
820
821
822 //----- filament guide spacer -----
823
824 guide_armdia = 15.0;
825 guide_armwidth = 10.2;
826 guide_armcorelen = 25.0;
827 guide_clipcirclethick = 10.0;
828
829 guidefilclip_outerdia = 22.8;
830
831 guidespacer_armslop = 0.75;
832 guidespacer_armlenslop = 1.05;
833
834 guidespacer_prongprotrude = 4;
835 guidespacer_thick = 1.6;
836
837 // calculated
838
839 guidespacer_armdia = guide_armdia + guidespacer_armslop;
840 guidespacer_armwidth = guide_armwidth + guidespacer_armslop;
841 guidespacer_len = guide_armcorelen - guide_clipcirclethick
842   + guidespacer_armlenslop;
843
844 guidespacer_wingheight = (guidefilclip_outerdia - guidespacer_armdia)/2;
845
846 module FilamentGuideArmTemplate(extra=0){
847   intersection(){
848     circle(r= (guidespacer_armdia/2) + extra);
849     square(center=true, [guidespacer_armwidth+extra*2,
850                          guidespacer_armdia + extra*2 + 10]);
851   }
852 }
853
854 module FilamentGuideSpacerInnerTemplate(){
855   FilamentGuideArmTemplate();
856   translate([0, -guidespacer_armdia/2])
857     square(center=true, [guidespacer_armwidth - guidespacer_prongprotrude,
858                          guidespacer_armdia]);
859 }
860
861 module FilamentGuideSpacer(){ ////toplevel
862   difference(){
863     union(){
864       linear_extrude(height= guidespacer_len)
865         FilamentGuideArmTemplate(extra= guidespacer_thick);
866       for (angle=[26, 60]) {
867         for (m=[0,1]) {
868           mirror([m,0,0]) {
869             rotate([0,0,angle]) {
870               hull(){
871                 for (t=[[0, guidespacer_wingheight],
872                         [guidespacer_len-1, -guidespacer_wingheight]])
873                   translate([0,0, t[0] + 0.5])
874                     cube([guidespacer_thick, guidespacer_armdia + t[1]*2,
875                       1],
876                          center=true);
877               }
878             }
879           }
880         }
881       }
882     }
883     translate([0,0,-1])
884       linear_extrude(height= guidespacer_len+5)
885       FilamentGuideSpacerInnerTemplate();
886   }
887 }
888
889
890 //----- replacement filament guide arm for TAZ-5 -----
891
892 guidearm_armslop = 0.25;
893 guidearm_armlenslop = 0.25;
894
895 guidearm_hookprotr = 3;
896 guidearm_hookprotrflat = 1;
897 guidearm_hookslope = 0.3;
898
899 guidearm_totallen = 60;
900
901 guidearm_screwplatesz = 12;
902 guidearm_screwplateth = 4;
903 guidearm_screwplatewd = 15;
904 guidearm_screwhole = 5 + 0.5;
905
906 guidearm_bendlen = 40;
907 guidearm_bendslot = 4.5;
908
909 guidearm_stopthick = 4;
910 guidearm_protrslop = 1.0;
911
912 // calculated
913
914 guidearm_armdia = guide_armdia - guidearm_armslop;
915 guidearm_armwidth = guide_armwidth - guidearm_armslop;
916 guidearm_armcorelen = guide_armcorelen + guidearm_armlenslop;
917
918 guidearm_base_z0 = -(guidearm_totallen - guidearm_armcorelen);
919
920 guidearm_realbendlen = min(guidearm_bendlen,
921                            guidearm_totallen - guidearm_screwplateth - 0.1);
922 guidearm_slopelen = guidearm_hookprotr/guidearm_hookslope;
923
924 module FilamentGuideArmStop(h){
925   for (ts=[-1,+1]) {
926     translate([ts * guidearm_hookprotr, 0,0])
927       cylinder(r=guidearm_armdia/2, h, $fn=80);
928   }
929 }
930
931 module FilamentGuideArmShaftPositive(){
932   r = guidearm_armdia/2;
933
934   translate([0,0, guidearm_base_z0+1])
935     cylinder(r=r, h= guidearm_totallen, $fn=80);
936   translate([0,0, guidearm_armcorelen]){
937     hull(){
938       FilamentGuideArmStop(guidearm_hookprotrflat);
939       translate([0,0, guidearm_slopelen])
940         cylinder(r=r, h=guidearm_hookprotrflat, $fn=80);
941     }
942   }
943   mirror([0,0,1])
944     FilamentGuideArmStop(guidearm_stopthick);
945 }
946
947 module FilamentGuideArmBase(){
948   translate([0,
949              (guidearm_screwplatewd - guidearm_armwidth)/2,
950              guidearm_base_z0]){
951     difference(){
952       translate([0,0, guidearm_screwplateth/2])
953         cube(center=true,
954              [guidearm_armdia + guidearm_screwplatesz*2,
955               guidearm_screwplatewd,
956               guidearm_screwplateth]);
957       for (ts=[-1,+1]) {
958         translate([ts * (guidearm_armdia/2 + guidearm_screwplatesz/2),
959                    0,
960                    -20])
961           cylinder(r= guidearm_screwhole/2, h=40, $fn=20);
962       }
963     }
964   }
965 }
966
967 module FilamentGuideArm(){ ///toplevel
968   intersection(){
969     difference(){
970       FilamentGuideArmShaftPositive();
971       translate([-guidearm_bendslot/2,
972                  -50,
973                  -guidearm_realbendlen + guidearm_armcorelen])
974         cube([guidearm_bendslot,
975               100,
976               guidearm_realbendlen + 100]);
977       hull(){
978         for (zx=[ [ 0, guidearm_bendslot ],
979                   [ guidearm_armcorelen + guidearm_slopelen,
980                     guidearm_hookprotr*2 + guidearm_protrslop ]
981                   ]) {
982           translate([-zx[1]/2, -50, zx[0]])
983           cube([zx[1], 100, 1]);
984         }
985       }
986     }
987     cube(center=true,
988          [guidearm_armdia*2,
989           guidearm_armwidth,
990           guidearm_totallen*3]);
991   }
992   FilamentGuideArmBase();
993 }
994
995 module FilamentGuideArmPrint(){ ////toplevel
996   rotate([90,0,0])
997     FilamentGuideArm();
998 }
999
1000 module Demo(){ ////toplevel
1001   translate([-real_exteffrad,-20,0]) Hub();
1002   ArmEnd();
1003   translate([ratchettooth*2, 30, 0]) FilamentCup();
1004   if (selsz(true,false,false)) {
1005     translate([-exteffrad + hubeffrad - hub_clip_baseextend, -10, 0])
1006       ArmExtender();
1007   }
1008 }
1009
1010 //ArmEnd();
1011 //FilamentCup();
1012 //FilamentCupPair();
1013 //CupSecuringClip();
1014 //Hub();
1015 //ArmExtender();
1016 //Axle();
1017 //AxleWasher();
1018 //AxlePin();
1019 //AxleFrictionWasher();
1020 //StorageArmLeft();
1021 //StorArmHoleTest();
1022 //FilamentGuideSpacer();
1023 //FilamentGuideArm();
1024 //FilamentGuideArmPrint();
1025 //Demo();