knob.hs

A pal of mine DJs under the name Syntax Terror.

A while back, he contacted me about printing some replacement dials for his Traktor Kontrol X1 MK2, as these had apparently fallen off during transit.

He sent me a list of possible knob designs from Thingiverse.

Now, I’m broadly of the opinion that the point of having a 3d printer is that you can make custom parts. Thingiverse is great, but if you’re just going to print stuff from Thingiverse all the time, you’d be better off with an Alibaba account.

With this in mind, I thought I’d have a go at designing some custom knobs, instead.

This meant I was able to use the line “I’ve got some knobs here with your name on them”, while we were arranging postage.

While I’m relatively happy with how these came out, I regret not playing around with the bevel radius and number of cuts a little more than I did.

knob-syntax.stl

knob-terror.stl

raw haskell source

#!/usr/bin/env stack
{- stack script --resolver lts-22.6 
    --package linear
    --package waterfall-cad
    --extra-dep waterfall-cad-0.3.0.0
    --extra-dep opencascade-hs-0.3.0.0
-}

-- short-description: Tommy's Knobs

-- description: [A pal of mine](https://www.tommyp.org/) DJs under the name [Syntax Terror](https://soundcloud.com/syntax-terrorist).
-- description: 
-- description: A while back, he contacted me about printing some replacement dials for his [Traktor Kontrol X1 MK2](https://www.native-instruments.com/en/products/traktor/dj-controllers/traktor-x1/), as these had apparently fallen off during transit.
-- description: 
-- description: He sent me a list of possible knob designs from Thingiverse.
-- description: 
-- description: Now, I'm broadly of the opinion that the point of having a 3d printer is that you can make _custom parts_.
-- description: Thingiverse is great, but if you're just going to print stuff from Thingiverse all the time, you'd be better off with an Alibaba account. 
-- description: 
-- description: With this in mind, I thought I'd have a go at designing some custom knobs, instead.
-- description: 
-- description: This meant I was able to use the line "I've got some knobs here with your name on them", while we were arranging postage.
-- description: 
-- description: While I'm relatively happy with how these came out, I regret not playing around with the bevel radius and number of cuts a little more than I did.
-- image: https://doscienceto.it/blog/photos/knobs-01.jpg
-- image: https://doscienceto.it/blog/photos/traktor_kontrol.jpg

import qualified Waterfall
import Linear 

shaft :: Waterfall.Solid
shaft = 
    let r = 3 
        h = 20 
        cutOff = 2
    in (Waterfall.scale (V3 r r h) Waterfall.unitCylinder) `Waterfall.difference` 
        (Waterfall.translate (cutOff *^ unit _y) $ Waterfall.scale (V3 h h (h*3)) $ Waterfall.translate (0.5 *^ unit _y) $ Waterfall.centeredCube)

knob :: Waterfall.Shape -> Waterfall.Solid
knob t = 
    let rInner = 19/2
        h = 19
        fillet = Waterfall.roundConditionalFillet (\(V3 _ _ z, V3 _ _ z') -> if z > h/2 && z' > h/2 then Just 5 else Nothing)
        cutR = 1.75
        cutN = 8
        cuts = Waterfall.rotate (unit _z) (pi/cutN) $ mconcat $ take 10 $ iterate (Waterfall.rotate (unit _z) (2*pi/cutN)) $ Waterfall.translate (rInner *^ unit _y) $ Waterfall.scale (V3 cutR cutR (h*3)) $ Waterfall.centeredCylinder 
        plainCyl = fillet $ Waterfall.scale (V3 rInner rInner h) $ Waterfall.unitCylinder
        rOuter = 21/2
        baseH = 2
        coneS = rOuter + baseH
        coneGrad = 0.75
        baseCone = Waterfall.scale (V3 coneS coneS (coneS * coneGrad)) $ Waterfall.translate (unit _z) $ Waterfall.rotate (unit _x) pi $ Waterfall.unitCone
        base = (Waterfall.scale (V3 rOuter rOuter (h/2)) Waterfall.unitCylinder) `Waterfall.intersection` baseCone
        shaft' = Waterfall.translate ((h - 20 - 2) *^ unit _z) $ shaft

        tDepth = 0.5
        text = Waterfall.translate ((h- tDepth*9) *^ unit _z) $ Waterfall.prism (tDepth *10) t
    in  (((plainCyl `Waterfall.difference` cuts) `Waterfall.union` base) `Waterfall.difference` shaft') `Waterfall.union` text


main :: IO ()
main = do
    let stlRes = 0.05
    font <- Waterfall.fontFromSystem "monospace" Waterfall.Regular 5
    Waterfall.writeSTL stlRes "knob-syntax.stl" (knob $ Waterfall.text font "syntax")
    Waterfall.writeSTL stlRes "knob-terror.stl" (knob $ Waterfall.text font "terror")