2018年1月31日水曜日

(2/7)レーザーユニットのカウンターウェイトを作った

<前   次>

レジンを流すときの外枠の組み立て
仮組み

ボンドで固定
ボルト周辺のボンドの間が気になるけれど、ボルトがもったいないので・・・
また、レジンって結構ドロッとしているので大丈夫じゃね?、って感じで

レジンが固まったら外枠は破壊して外します。
ボンドはレジンを当しませんし水につけておけばはがれます。
プラスチック系の接着剤を使ってしまうと多分悲しいことになるんだと思います。

フレームの組み立て
フレームの切り出しが終わりました
瞬間接着剤で固めるために仮組み

絡まってるし
こういうの苦手だし

交互に積んでいきます。どうにかがんばる
用意していた33mmのスペーサは空間的に使えないことが分かった
しょうがないからノギスで測って厚さを調整

できました
2箇所ほど向きが間違っていたり

なんか、ラジエータみたいですな 
にしても、この0.5mmの隙間にレジンが流れ込む予定にしているのですが、本当に流れていくのだろうか。。

部品も大体そろってきました


外枠にはケムリースを塗ってレジンが固着しないようにします。
レジンは・・・、しばらく触っていないうちに荷物の奥のほうに行ってしまったので、まずは片づけか。苦手だし


<前   次>

ロジクールのカットキーが出てきた

掃除していたら出てきました。
きたない・・・



ロジクール、日本語106キーボードに準拠した片手入力キーボードを発売

・・・19年前か。

C#で、SVGファイルのXMLを操作する

SVGはXMLベースのベクターデータ用フォーマットで業界標準(?)らしい。

自分が必要なのはレーザー加工用の情報が入っている「path」って要素で、円弧などもこちらで定義している。
これの編集と追加をしたかったのだけれど、面倒そうなのでもういっそ文字列操作で済まそうかと思ったが、調べてみたら意外とすっきりXmlパーサで実装できました。変な制限がつかないで済んでえがった。

※A
まず、なんだかよく分かっていないけれど、「http://www.w3.org/2000/svg」文字列をマネージャ経由で渡す必要がある。
そして、XPathというらしいけれど「/a:svg/a:g/a:path」みたいに直接パスを指定してXmlNodeListを取得できる。(「a」は名前空間?)

※B
CloneNode(…)でコピーでき、現在位置に対してInsertBefore(…)やInsertAfter(…)で挿入できる。
現在位置もNodeで普通のリスト要素のように保持できたり。


// ログ出力クラス
private LogUtil logUtil = null;

/// 要素を解析し変換する
public System.Xml.XmlDocument ConvSvg(System.Xml.XmlDocument xmlDoc)
{
    // 引数の確認
    if (xmlDoc is null) { return null; }

    try
    {
        // -- ※A ->
        // 名前空間マネージャの生成
        System.Xml.XmlNamespaceManager nsmgr = new System.Xml.XmlNamespaceManager(xmlDoc.NameTable);
        nsmgr.AddNamespace("a", "http://www.w3.org/2000/svg");

        // 「path」の取得
        System.Xml.XmlNodeList nodeList = xmlDoc.SelectNodes("/a:svg/a:g/a:path", nsmgr);
        // <- ※A --

        // 取得の確認
        if (nodeList is null || nodeList.Count <= 0)
        {
            this.logUtil.WriteLog("パス(path) が取得できませんでした。", LogUtil.LogLevel.Error);
            this.logUtil.WriteLog(" → オブジェクト は予め パス(path) に変換する必要があります", LogUtil.LogLevel.Info);
            this.logUtil.WriteLog(" → /svg/g/path が存在するか確認してください", LogUtil.LogLevel.Info);
            return null;
        }

        // 取得したパスで回る
        foreach (System.Xml.XmlNode node in nodeList)
        {
            // 図形情報(d属性?)の取得
            string dValue = null;
            try
            {
                dValue = node.Attributes["d"].Value;
            }
            catch (Exception)
            {
                dValue = null;
            }
            if (string.IsNullOrEmpty(dValue) == true) { continue; }

            // 図形情報を確認して図形の種類を取得する
            DValueTypes dValueType = this.GetDValueType(dValue);

            // style属性(「;」「:」区切り。strokeが線色?)の取得
            string sValue = null;
            try
            {
                sValue = node.Attributes["style"].Value;
            }
            catch (Exception)
            {
                sValue = null;
            }

            // style属性を確認して処理の種類を取得する
            SValueTypes sValueType = this.GetSValueType(sValue);

            // 線色による分岐
            if (sValueType == SValueTypes.Delete)
            {
                // 削除する
                node.ParentNode.RemoveChild(node);
                continue;
            }

            // 図形種類による分岐
            string[] dValues = null;
            if (dValueType == DValueTypes.LineRelative || dValueType == DValueTypes.LineAbsolute)
            {
                dValues = this.ConvLine(dValue, dValueType, sValueType);
            }
            else if (dValueType == DValueTypes.ArcRelative || dValueType == DValueTypes.ArcAbsolute)
            {
                dValues = this.ConvArc(dValue, dValueType, sValueType);
            }
            else
            {
                this.logUtil.WriteLog("図形の種類の特定に失敗しました。", LogUtil.LogLevel.Error);
                this.logUtil.WriteLog(" → 現バージョンでは「円弧(a)」「移動(m)で定義の直線」のみ対応しています。(「直線(l)で定義の直線」は非対応)", LogUtil.LogLevel.Info);
                this.logUtil.WriteLog(" → " + dValue, LogUtil.LogLevel.Info);
                continue;
            }

            // 処理結果の確認
            if (dValues is null || dValues.Length <= 0) { continue; }

            // -- ※B ->
            // 変換結果で回る
            System.Xml.XmlNode lastNode = node;
            for (int i = 0; i < dValues.Length; i++)
            {
                if (i == 0)
                {
                    //-- 1件目の場合
                    // 置き換える
                    node.Attributes["d"].Value = dValues[i];
                    continue;
                }

                //-- 以下、2件目以降の場合

                // コピーして置き換える
                System.Xml.XmlNode newNode = node.CloneNode(true);
                newNode.Attributes["id"].Value += "_" + (i + 1).ToString().PadLeft(3, '0');
                newNode.Attributes["d"].Value = dValues[i];
                node.ParentNode.InsertBefore(newNode, lastNode);

                // 現在の位置を保存する
                lastNode = newNode;
            }
            // <- ※B --
        }
    }
    catch (Exception ex)
    {
        // ログ出力
        this.logUtil.WriteLog(LogUtil.LogLevel.Delimiter);
        this.logUtil.WriteLog(ex.ToString(), LogUtil.LogLevel.Fatal);
        this.logUtil.WriteLog(LogUtil.LogLevel.Delimiter);
        this.logUtil.WriteLog("変換処理で例外が発生しました。", LogUtil.LogLevel.Fatal);

        // 戻り値のクリア
        xmlDoc = null;
    }

    // 返す
    return xmlDoc;
}


※動作しているコードの該当箇所をそのままコピーしました

(1/7)レーザーユニットのカウンターウェイトを作った

<前   次>

SVGファイルを変換したりもして、だいぶ加工精度が上がってきました。
けど、もうちょっと。あと一息。
早送り(?)してきた直後に位置がずれているみたいです。(左の列)
(「抜け切らない」のは多分これが原因かと思われる)
誘導のために接線を追加してみたのが右の列。
ずれは無い(様に見える)。

レーザーユニット(直方体の部分)重量を計ってみたら、180g以上ありました。
材質が金属(アルミ)でサイズもあるのでそんなに重い感じはしていなかったのですが、、、缶コーヒーより少し重いあるわけです。
直方体の部分がレーザーユニット。中にレーザーLEDが入っている

 キリン ファイア 挽きたて微糖 185g1箱30本
キリン ファイア 挽きたて微糖 185g

これだけで静止していても右肩下がりになっているポイです。
さらに、レーザーユニットの上下方向の重心はローレットのところにあるのですが、自分の場合は加工対象が工作用紙なので(薄いので)、X軸の上下方向の中心から20mmほど下になった状態で行き来しています。
かなり振り回されていると想像します。

これはバランスをとるべきだろうと、カウンターウェイトを点対称の位置に設置するべきだろうと。やらねばならぬ。
と言って、カウンターウェイトを作っています。
釣り用のおもり。約180g。たぶん鉛。
くくらいやわらかく、はさみで簡単に切れる
(はさみの刃こぼれの心配もしないくらい)

サボテンダー

M4のスペーサー。高さ33mm

レジンを流すときの枠の部品

仮組み中

初めはこちら向きで流す
(肉抜きぽいところから流す)

最後はこちら向きで流す
(肉抜きぽいがない部品に差し替えて流す)

おもりをまるめて

ハブネークモドキで固定して

レジンで固める予定です。

ハブネークは、33mm / 0.5mm = 66 カットしなければなりません。あと40くらい


<前   次>

2018年1月30日火曜日

みかんの缶詰め

YouTubeでみかんの缶詰めを作る工場の動画を見て以降、缶詰めのシロップを切りウィルキンソンタンサンをかけて食べると旨い、ってなってる


THE MAKING (115)みかんの缶詰ができるまで

C#で、キックする実行モジュールのフルパスをレジストリから取得する(環境変数は登録されていない)


・処理対象のファイルの拡張子は分かっている
・実行モジュールは指定したい
・実行モジュールがどこにインストールされているか分からない
・環境変数に登録されていない

そんな状況なんですが、目的としてはDXFファイルをSVGファイルに変換したい。
その為には、Inkscapeをコマンドで呼び出し処理させる。
だけれど、拡張子「DXF」はAutocadなどに関連付いている可能性がある、と。

UACの絡みとかも有り、シンプルで確実に動く方法が意外と見つからなかった。
最終的に上手くいったコードが以下。

レジストリの構成を説明してくれている記事があったので、手順的にはその内容を使っていますが、、どこのページか分からなくなってしまいました。すまそ。

例) テキストファイル(拡張子:.txt)
「HKEY_CLASSES_ROOT\.txt」の値は「txtfile」。
引き続き「HKEY_CLASSES_ROOT\txtfile」配下のパス、
「HKEY_CLASSES_ROOT\txtfile\shell\open\command」の値は「%SystemRoot%\system32\NOTEPAD.EXE %1」
これを文字列操作して取得。

/// <summary>
/// 実行モジュールのフルパスを探す
/// </summary>
/// <param name="characteristic">見つけたいモジュールのモジュール名</param>
/// <param name="exts">関連付けられている可能性のある拡張子(複数可能)</param>
/// <returns>モジュールのフルパス</returns>
private string FindFullPath(string characteristic, string[] exts)
{
    RegistryKey regKey1 = null;
    RegistryKey regKey2 = null;
    try
    {
        for (int i = 0; i <= exts.Length; i++)
        {
            // キーのパスを指定してレジストリを開く
            regKey1 = Registry.ClassesRoot.OpenSubKey(exts[i]);
            // レジストリの値を取得
            string regValue1 = (string)regKey1.GetValue(null);
            regKey1.Close();
            // 確認
            if (string.IsNullOrEmpty(regValue1) == true) { continue; }
            // キーのパスを指定してレジストリを開く
            regKey2 = Registry.ClassesRoot.OpenSubKey(regValue1 + "\\shell\\open\\command");
            // レジストリの値を取得
            string regValue2 = (string)regKey2.GetValue(null);
            regKey2.Close();
            // 確認
            if (string.IsNullOrEmpty(regValue2) == true) { continue; }
            // 一致の確認
            int pos = regValue2.IndexOf(characteristic);
            if (pos < 0) { continue; }
            // 文字列操作して返す
            return regValue2.Substring(1, pos + characteristic.Length - 2);
        }
    }
    catch (Exception ex)
    {
        try { regKey1.Close(); } catch { }
        try { regKey2.Close(); } catch { }
    }
    return null;       // 抜けていたので追加
}

※動作しているコードを編集しました
※編集後のコンパイル/動作確認は行っていません