3Dプリンタ作例/LEGO互換部品

(160d) 更新


3Dプリンタ作例

LEGO の互換パーツを作りたい

格安3Dプリンターとしては非常に高い精度を要求されることになるため、いろいろと工夫が必要だった。

試作品1

上面にサポートを付けるわけにいかないので、内部にサポートを付けた。

真ん中の中空円柱が底面が小さくて浮いてしまうため1層のラフトを付けたのだけれど、 ベッドの高さ調整が悪かったのかどうか、あまりきれいにできなかった。

さらに、寸法通りにいかないところがあるので微調整が必要みたい。

gcode0.png model1.png WIN_20211206_10_34_56_Pro.jpg

四角い部分、15.80 mm の設計が、X 方向は 15.90 mm, Y 方向は 15.65 mm となっていた。 Y 方向のバックラッシュが少し大きくなってきているのかもしれない、とも思ったのだけれど、 いろいろよく測ってみると太っているのはカドの部分だけで、中央部分を測ると X 方向 15.69 mm Y 方向 15.61 mm で、そこまで大きな違いはなかった。

伝説の「リニアアドバンス」の設定で解決できるという、カドの部分でフィラメントが過剰に 押し出されてしまう影響を受けているのかもしれない。

丸く突き出た頭の部分は X 方向も Y 方向も 4.70 mm だった。 設計値は 4.90 mm なので 0.2 mm も細くなってしまっている。

四角部分の高さは 9.65 mm を指定したところ、中央で 9.7 mm カドで 9.86 mm になっていた。 ここはあまり効かないので、まあこのくらいでも。

内部の円柱外径は 6.50 mm 指定のところ 6.45 mm だった。

実際のはめ合いは上も下もかなり緩いので、要改善点として重要そうなのは、

  • 頭の直径を 0.2 mm 増やす
  • 内部円柱の外径を 0.1 mm 増やす
  • 底面をきれいに印刷できるよう温度と距離を調節しよう

としてみよう。

試作品2

  • 頭の直径を 0.2 mm 増やす
  • 内部円柱の外径を 0.1 mm 増やす

をしたところ、

頭が大きくなりすぎた。0.1 mm 減らそう。このくらいになってくると Y 軸のバックラッシュが気になるかも。 0.1 mm くらい、ソフト的な処理で対応する?

円柱外径はかなり良くなったけどまだ足りない。内径がぜんぜん足りず、中に頭が入らない。 円柱内径も増やそうか?

四角の四隅が少し下に飛び出すためかみ合わせが悪くなって困る。

このあたりは寸法で調整もできなくはないのだけれど、本来はやはりリニアアドバンスなどで対応するべきなんだよなあ。。。 ファームウェアの書き換えも含めて、もう少し本腰を入れて調べてみようかしら。

こういうのは OpenSCAD が良いみたい

OpenSCAD でしっかりプログラムしておくと、パラメータとして与えた任意のサイズのブロックを自動的に生成できた。

backside1.png backside2.png backside3.png lego4x10x0.png

WIN_20211221_08_41_55_Pro.jpg WIN_20211221_08_40_13_Pro.jpg WIN_20211221_08_42_44_Pro.jpg

また以下の工夫で十分に実用になる精度で出力できた。

  • モデル
    • 外寸は正規品に合わせて 8 mm の倍数から少々のクリアランス分を引いてある(width_delta)
    • 1列の時と2列以上の時とを if で分けて、内部に円筒を生成するか、棒を生成するかを自動的に切り替えた
    • 2列以上の時にはブリッジが長くなりすぎないように4辺から、および円筒から、サポートを伸ばした
    • 縦になる四辺の周囲が膨らんでしまう現象は、これらの辺を面取りすることで防げた(wall_bevel)
    • 同様に、下面の四隅のカドが膨らんでしまう現象も、このカドの部分を面取りすることで防げた(bottom_bevel)
    • 上部の円柱外径や、下部の円筒台形、下部の棒の外径、箱の内寸は実測を元に設計値へ補正を加えた値を指定した
      • この部分は「ズル」なのだけれど、どうしても必要だった
  • スライス
    • 側面の凹凸を十分に小さくするため 0.1 mm で積層
    • 高さを正確に合わせるために2層のラフトを敷いてその上に生成
      • インターフェースレイヤーを2層としたため実際には密に埋めた2層のレイヤー上に生成したことになる
    • サポートとオブジェクトの距離は 0.15 mm
      • 底面積が小さいのでこのくらい小さくしてもはがせる
  • バックラッシュ補正
    • 機械的にベルトの張りを調整してできるかぎりバックラッシュを小さくした
    • 0.1 mm 以下のバックラッシュをソフト的に補正した

本来であれば、カドが膨らむ現象はリニアアドバンスの設定で解決すべきなのですが、 今のところはファームウェアに手を加えていないのでそのような設定ができず 小手先で対応するしかありませんでした。 一方、どうしてもこれが問題になる場合に面取りで解決できることが分かったのは収穫でした。

円筒や円柱の外径が設計値と大きくずれるのは熱膨張の影響なのか何なのか、 トライアンドエラーで補正値を求めなければならないのは嫌な感じ。 0.1 mm 程度の精度を求めようとすると仕方がないのものなのかどうか。

lego_block.scad

LANG:scad
// 鏡像を複製する
module sym_m(d=[1,0,0], p=[0,0,0]) {
  children();

  translate(p)
  mirror(d)
  translate(-p)
  children();
}

// 直交する鏡2枚分の鏡像を複製する
module sym_2m() {
  children();
  mirror([0,1,0]) children();
  mirror([1,0,0]) {
    children();
    mirror([0,1,0]) children();
  }
}

// 回転対称で複製する
module sym_c(n, axis=[0,0,1]) {
  for(r=[1:n])
    rotate(r*axis*360/n)
    children();
}

// 単純なレゴブロックを作る
// 面積 n x m 高さ l
// シートを作るには l = 1/3 にする
module lego_block(n=2,m=2,l=1,
  width_delta=0.08,
  width_unit=8,
  wall_thick=1.55,
  wall_bevel = 0.4,
  corner_bevel = 0.8,
  height_unit=9.6,
  ceil_thick=1,
  prot_diameter=4.9 + 0.1,
  prot_height=1.7,
  prot_bevel = 0.15,
  bottom_d1 = 6.5,
  bottom_d2 = 4.9,
  bottom_d3 = 3.1 + 0.18,
  epsilon = 0.01,
  fn = 80,
  bottom_lp = 0.42,
  bottom_bevel = 0.2
) {
  // n < m のときは n と m とを切り替え n > m で生成してから転置する
  if(n < m) {
    mirror([-1,1,0])
    lego_block(n=m, m=n, l=l,
      width_delta=width_delta,
      width_unit=width_unit,
      wall_thick=wall_thick,
      wall_bevel = wall_bevel,
      height_unit=height_unit,
      ceil_thick=ceil_thick,
      prot_diameter=prot_diameter,
      prot_height=prot_height,
      prot_bevel = prot_bevel,
      bottom_d1 = bottom_d1,
      bottom_d2 = bottom_d2,
      epsilon = epsilon,
      fn = fn,
      bottom_lp = bottom_lp,
      bottom_bevel = bottom_bevel
    );
  } else {

    // 以降は必ず n > m になっているはず
    translate([
      width_unit*n/2,
      width_unit*m/2, 0]) {

      // 四角い枠
      difference(){
        // 外枠の直方体
        translate([0, 0, -l*height_unit]/2)
        cube([
          width_unit*n - width_delta,
          width_unit*m - width_delta,
          l*height_unit],
          center=true
        );
        
        // 裏側の抜き
        translate([0, 0, -l*height_unit-ceil_thick]/2)
        cube([
          width_unit*n - wall_thick*2,
          width_unit*m - wall_thick*2,
          l*height_unit],
          center=true
        );
        
        // 面取り
        sym_2m() {
          // 縦の辺の面取り
          translate([
            width_unit*n - width_delta,
            width_unit*m - width_delta,
            -l*height_unit]/2)
          rotate([0, 0, 45])
          cube([wall_bevel,wall_bevel,l*height_unit+0.1],
            center=true);

          // 下面の角の面取り
          translate([
            width_unit*n/2 - width_delta,
            width_unit*m/2 - width_delta,
            -l*height_unit])
          rotate([0,0,1]*45)
          rotate(atan(2/sqrt(2))*[0, 1, 0])
          cube([1,2,2]*corner_bevel,
            center=true);
        }
      }
    }
    
    // 上部に出っ張る円柱
    for(i=[0:n-1]) {
      for(j=[0:m-1])
        translate([
          width_unit*(i+1/2), 
          width_unit*(j+1/2), 0])
        intersection() {
          // 上の円柱
          cylinder(
            prot_height, 
            d=prot_diameter, 
            $fn=fn);

          // 面取り
          cylinder(
            prot_height, 
            r1=prot_diameter-prot_bevel, 
            r2=prot_diameter/2-prot_bevel,
            $fn=fn);
        }
    }

    // m >= 2 では内部に筒を持つ
    if(m >= 2) {
      // サポートが外枠からはみ出さないように制限
      intersection(){ 
        translate([
          width_unit*n/2,
          width_unit*m/2,
          0]) 
        translate([0, 0, -l*height_unit]/2)
        cube([
          width_unit*n - width_delta,
          width_unit*m - width_delta,
          l*height_unit],
          center=true
        );

        union () {
          // 円筒の生成
          for(i=[1:n-1])
            for(j=[1:m-1]) {
              difference() {
                union() {
                  // 下向きの円筒の外周
                  translate([
                    width_unit*i, 
                    width_unit*j, 
                    -l*height_unit])
                  cylinder(
                    l*height_unit, 
                    d=bottom_d1, 
                    $fn=fn);

                  // 円筒から伸びるサポート
                  translate([
                    width_unit*i, 
                    width_unit*j, 
                    0])
                  sym_c(4)
                  translate([(bottom_d1+bottom_d2)/4,0,0])
                  rotate([0,45,0])
                  cube([bottom_lp,0.2,bottom_lp]*width_unit,center = true);
                }

                // 円筒の内側をくり抜く
                translate([
                  width_unit*i, 
                  width_unit*j, 
                  -l*height_unit])
                translate([0,0,-0.1])
                cylinder(
                  l*height_unit+0.2, 
                  d=bottom_d2, 
                  $fn=fn);
              }

            }
          
          // 壁から伸びるサポート
          sym_m([0,1,0], [0,width_unit*m/2,0])
          for(i=[1:n-1]) {
            translate([
              width_unit*i, 
              wall_thick, 
              0])
            rotate([0,0,90])
            rotate([0,45,0])
            cube([bottom_lp,0.2,bottom_lp]*width_unit,center = true);
          }

          // 壁から伸びるサポート
          sym_m([1,0,0], [width_unit*n/2, 0,0])
          for(j=[1:m-1]) {
            translate([
              wall_thick, 
              width_unit*j, 
              0])
            rotate([0,45,0])
            cube([bottom_lp,0.2,bottom_lp]*width_unit,center = true);
          }
        }
      }
    }
    // 1列の場合には内側に棒を持つ
    if(m == 1) {
      for(i=[1:n-1])
        translate([i,1/2,0]*width_unit)
        translate([0,0,-height_unit*l]) {
        difference(){
          cylinder(height_unit*l, r=bottom_d3/2, $fn=fn);
            
          rotate_extrude($fn=80)
          polygon([
          [bottom_d3/2+epsilon-bottom_bevel,-epsilon],
          [bottom_d3/2+epsilon,+bottom_bevel-epsilon],
          [bottom_d3/2+epsilon,-epsilon]
          ]);
        }
      }
    }
  }
}

// 縦、横、高さを指定して生成する
// 高さは整数値あるいは 1/3 を指定する
lego_block(4,10,1/3);

Fusion 360 でもパラメータを使えるんですね

fusion_parameters1.png  fusion_parameters2.png

長さやコピー数をパラメータで変更することで、任意のサイズのブロックを作れそうです。

OpenSCAD から Fusion 360 へインポートするとメッシュの数が大きくなりすぎて難儀するので、 Fusion 360 だけで作れるならそれに越したことはない!

のですが・・・

Fusion 360 では IF 文などによる条件分岐ができないため、 幅や奥行きが1のときには底面に円筒ではなく円柱を作成する、 というような場合分けを自動で行うことはできません。

手動でやるには画面下部のフィーチャ履歴で「グループ化」や「フィーチャを抑制」を使って ON/OFF の切り替えをするのが良さそうです?

fusion_features.png

あと、矩形状パターンなどを使ってできた多数のボディを自動的にグループ化したり、別のボディに結合したりする機能が見つからないため、最後に1つのボディにまとめるところは手動で行う必要がありそうです?

さらに、そのようにして1つのボディにまとめたものをコピー&ペーストして別のコンポーネントとしたい場合には、張り付けた先で「DMフィーチャーに変換」しておくと、元のボディを変更したり、消したりしても影響を受けなくなるようです?

fusion_dmfeature.png

Fusion360 で使える数式

https://forums.autodesk.com/t5/fusion-360-ri-ben-yu/yuan-zhou-lupwo-biaosu-biao-xianha/m-p/6589086#M3042 によると、同じく AutoDesk 社の Inventor の数式の書き方 PDF を参照すると、fx 機能で使える関数やその書式などが分かるそうです。

http://images.autodesk.com/apac_japan_main/files/I00-parameters_9.pdf

inventor-units.png

inventor-operators.png

inventor-functions1.png

inventor-constants.png

注意事項

  • 関数のパラメータ区切りは "," ではなく ";"
    • min(N1, N2) はエラーになります。正しくは min(N1; N2) です。

  • 単位文字の例
    • 単位は、単位の文字列の直前にある数値に対して割り当てられます。 たとえば 3/4mm は、3/(4mm) と解釈されます。

  • 構文
    • 計算式では、個々のフィールドについて、既定のドキュメントのプロパティから予想される単位と同じ単位を一貫して使用します。 たとえば、あるスケッチを押し出す場合に既定の長さの単位が mm だったとすると、Inventor で予想される押し出しの深さの単位も mm になります。
    • 単位なしの項や係数には、既定の単位が割り当てられます。 その後、代数式の演算順序と既定の単位系に従って、式が評価されます。

  • よくある構文エラー
    • 累乗では、指数が単位にも適用されるので、注意して入力する必要があります。 次のような、押し出しの深さの式を考えます (既定の単位は mm であるとします)。
      2 + 3^3
    • 押し出しの深さとは長さのことなので、編集ボックスでは、予想に基づいて長さの単位が使用されます。 計算式ボックスでは、まず、単位なしのすべての項に対して、「推論」アルゴリズムに従って単位が割り当てられます。 その結果、2mm + (3mm)^3ul は 2mm + 27mm^3 と解析されますが、これはエラーです (異なる単位同士は加算できません)。これは赤字で表示されます。
    • 2 mm + ((3 ul) ^ 3 ul ) * 1 mm と入力すれば、エラーは発生しません。

  • 単位の評価
    • 単位は、式で使用されている代数演算子よりも優先的に解析されます。 したがって、累乗演算子は、まず単位に適用されてから、隣接する数値に適用されます。 たとえば、次のようになります。
      2m^2
    • この場合は、4 平方メートルではなく、2 平方メートルと評価されます。正しい構文は、次のとおりです。
      (2m)^2 = 4m^2

  • 詳細な型指定
    • 構文的に正しい式を作成する最も効果的で正確な方法は、式中のそれぞれの数値に単位を明示的に割り当てることです。 たとえば、次のように入力するとします。
      (2 + 1 * (3^2))
    • ここでシステムが、単位が mm であると予想していると、構文エラーが発生します。より正確を期するには 2mm + 1mm * (3ul^2ul) のように入力します。
    • [回転]コマンドでは、回転角の単位は度であると予想されますが、式をラジアンの単位で入力したい場合は、次のように入力します。
      (-0.25 deg * 3.1415 rad/1 deg) + (2ul * 3.1415 ul ) * 1 rad

コメント・質問





Counter: 925 (from 2010/06/03), today: 9, yesterday: 0