OpenSCAD でキーキャップをデザインしてみた

つくりたいもの

前回、キーキャップをレジンで複製する方法を記事にしました。

今回は複製ではなく、自分の好みの形のキーキャップをデザインしてみます。

自分でキーキャップをデザインしたい理由ですが、こういう Artisan キーキャップをつくりたいというのが大きいです。

レジンで上の画像のようなキーキャップをつくるには、パックマンや鯉を封入するためのスペースがなければいけません。この図のようなイメージです。

こういう原型が必要なのですが、普通に買えるキーキャップにはこういう形のものはなかなかないので自分でつくってみようと思います。

せっかくつくるならXDAのようなかわいい形のキーキャップにしたいので、XDAよりも背を高くしつつころんとした形のキーキャップを目指してみようと思います。

OpenSCAD

キーキャップのモデリングには OpenSCAD を使いました。

OpenSCAD は、3Dモデリングをするためのプログラミング言語です。

引用元:OpenSCAD github

一般のプログラミング言語のように変数を使えるので、主要なパラメータを変数にしておいて後から変更可能にできます。 たとえばキーの高さや幅などのパラメータを変数にしておけば軸のスケールは変えずに高さや幅だけを変更したりすることが簡単にできます。

また、今回つくるキーキャップでは側面の丸みにこだわりたいのですが、OpenSCAD では数式で表現したカーブに沿って面を作ることなどもできるのでその点でも便利です。

OpenSCADでキーキャップをモデリングする方法については@zk_phiさんが記事にされています。

qiita.com

キーキャップをモデリングする方法が順を追って書かれていて大変勉強になりました。OpenSCADの文法の解説を交えながら基本的なキーキャップの形の作り方、キートップの凹みの作り方や、モデリング後にDMM.makeに発注するときの注意点まで丁寧にかかれているので、これからキーキャップをデザインしようと思っている人はまずはこちらの記事を読むのがおすすめです。

OpenSCADでできることを一通り勉強したい場合にはドットインストールに入門講座もあるので、しゅっと入門してしまいましょう。 

ドットインストール OpenSCAD 入門

書いてみた

ここからはOpenSCADのコードを交えて、どういう手順でモデリングしたかを紹介していきます。

この記事ではOpenSCADの文法の解説はしないのですが、OpenSCAD 使うとこういうことができるんだなーというイメージを持っていただければ幸いです。

Charry MX 軸

軸は円筒をベースにして十字部分を抜くことでつくります。

f:id:beikome:20190602004016p:plain

SCADのコードは以下のようになります。

module cherry_stem(stem_height) {
    // 軸の外径と十字の大きさを指定
    stem_outer_size = 5.5;
    stem_cross_length = 4.0;
    stem_cross_h = 1.25;
    stem_cross_v = 1.10;

    // 円筒と十字の差をとる
    difference() {
        // 円筒
        cylinder(d = stem_outer_size, h = stem_height);

        // 立方体を2つ組み合わせた十字形
        translate([- stem_cross_h / 2, - stem_cross_length / 2, 0]) {
            cube([stem_cross_h, stem_cross_length, stem_height]);
        }
        translate([- stem_cross_length / 2, - stem_cross_v / 2, 0]) {
            cube([stem_cross_length, stem_cross_v, stem_height]);
        }
    }
}

丸っこい形

土台

まずはシンプルな土台をつくってみます。

f:id:beikome:20190602005542p:plain

底面と天面を薄い立方体でつくり、その凸包をとりました。

key_bottom_size = 18;
key_top_size = 14;
key_top_height = 14;

 // hull() は3次元のオブジェクトの凸包を取るコマンド
 hull() {
     // キーキャップの底面
     translate([0, 0, 0]) {
         cube([key_bottom_size, key_bottom_size, 0.01], center=true);
     }
    // キーキャップの天面
     translate([0, 0, key_top_height]) {
         cube([key_top_size, key_top_size, 0.01], center=true);
     }
 }

まだカクカクです。

側面の丸み

丸っこい形にするために、底面から天面にかけてゆるやかにカーブを描くようにつなげたいと思います。

側面のカーブが円弧の一部になるように設計します。こういうイメージです。

天面の辺の長さを t 、底面の辺の長さを b , 高さを h とおき、円の半径 r と天面に対応する角度 {\theta}_{max} を求めます。

r \sin ( {\theta}_{max} ) = h
r \cos ( {\theta}_{max} ) = r - ( \dfrac {b} {2} - \dfrac {t} {2} )

が成り立ちます。

これを  r {\theta}_{max} について解いて、

 r = \dfrac {h ^ 2} {( b - t )} + \dfrac {(b - t)} {4}
 {\theta}_{max} = {\arcsin} ( \dfrac {h} {r} )

角度が  {\theta} のときの辺の長さ x は以下のように求められます。

 x = b - 2 r (1 - cos((\theta)))

急に高校数学みたいになりました。

以上の式をそのままコードにしていきます。

n = 20; // 底面から天面までの分割数

b = key_bottom_size;
t = key_top_size;
h = key_top_height;

r = h * h / (b - t) + (b - t)  / 4;
theta_max = asin(h / r);

hull() {
    // 底面から theta_max / n ずつ角度を変えて面を作成
    for (i = [0 : n]) {
        translate([0, 0, r * sin(theta_max * i / n) ]) {
            x = b - 2 * r * (1 - cos(theta_max * i / n));
            cube([x, x, 0.01], center=true);
        }
    }
}

f:id:beikome:20190602151839p:plain

辺の丸み

まだ側面の辺がカクカクしているのでこれをなめらかにしていきます。

ここまではcubeを積み重ねて形をつくっていましたが、これを角丸のものに置き換えてみます。

角丸の立方体をこのように定義しておきます。

module rounded_cube(size, r) {
    h = 0.0001;
    minkowski() {
        cube([size[0] - r * 2, size[1] - r * 2, size[2] - h], center = true);
        cylinder(r = r, h = h);
    }
}
rounded_cube([14, 14, 0.01], 3);

f:id:beikome:20190602164906p:plain

cube() をこの rounded_cube() で置き換えるとこんな感じになります。下から上にむかってだんだん丸く変化するようにしてみました。

round = 3; // 角丸の半径

hull() {
    for (i = [0 : n]) {
        translate([0, 0, r * sin(theta_max * i / n) ]) {
            x = b - 2 * r * (1 - cos(theta_max * i / n));
            rounded_cube([x, x, 0.01], round * i / n);  // cubeを置き換え 
        }
    }
}

f:id:beikome:20190602165716p:plain

だいぶ丸っこくかわいくなりました。

天面の丸み

仕上げに、天面に指をのせたときにぴったりくるようにカーブをつくります。

このあたりの操作は @zk_phiさんの記事 に詳しい解説がありますので、そちらを参照してください。

function dish_r(w, d) = (w * w + 4 * d * d) / (8 * d);

module keycap_dish(key_top_size, key_top_size, dish_depth) {
    translate([0, 0, key_top_height + dish_r(key_top_size * sqrt(2), dish_depth) - dish_depth]) {
        sphere(dish_r(key_top_size * sqrt(2), dish_depth));
    }
}

difference() {
    keycap_round_base(key_bottom_size, key_top_size, key_top_height, r);
    keycap_dish(key_top_size, key_top_height, dish_depth);
}

f:id:beikome:20190602171111p:plain

完成形

ここまでで作った外形の中をくりぬいて、軸と組み合わせて完成です。

module keycap(key_bottom_size, key_top_size, key_top_height, r = 3, dish_depth = 1) {
    key_inner_height = 5;
    thickness = 1.5;

    // 軸
    cherry_stem(key_inner_height);

    // キーキャップの中をくり抜く
    difference() {
        keycap_outer_shape(key_bottom_size, key_top_size, key_top_height, r, dish_depth);
        keycap_outer_shape(key_bottom_size - 2 * thickness, key_top_size, key_inner_height, r, 0);
    }
}

最終的な形はこうなりました。

f:id:beikome:20190603210212p:plain

f:id:beikome:20190603205952p:plain

各パラメータが変数になっているので、高さや大きさを変えるときもすぐ対応できます。

丸っこさはそのままに背だけを低くするとこんな感じになります。XDAっぽい。

f:id:beikome:20190604224921p:plain

完成形のコードとモデルはこちらに置きました。

github.com

印刷

作ったモデルを光造形3Dプリンターで印刷したものがこちらです。

印刷したままでは積層痕が目立つので磨いてみました。

f:id:beikome:20190603210915p:plain

ころんとしたキーキャップができました!

レジン複製

色付きレジンで複製してみました。

🍺大好きなので🍺のキーキャップもつくってみました。

泡が入っててもキニシナイ。🍺なので。

まとめ

OpenSCAD でキーキャップをデザインできるようになりました。

ころっとした形が実現できたし、レジンの層を厚くつくったので二色成形もできるようになり、つくれるものの幅がひろがって楽しいです。

レジンの中にものを封入するのもこれから実験していきたいと思います!