2025年10月6日月曜日

ELISE ハードトップの吹っ飛び防止

昔買ったエリーゼの社外ハードトップ,取り付け方が非常に不安.車体側への固定が,幌取り付け穴に金具を差し込んでいるだけで,ボルトで締結されていない.しかも金具は 8mm ほどしか差し込まれておらず,例えば縁石乗って車体がよじれたときに簡単に外れそう.実際に (どこのメーカーかは不明ながら) サーキットでエリのハードトップが風圧で吹っ飛んだ国内事例を,ネット上で 2件ほど見た.

純正品はフロントガラスのピラーを挟み込むような部品で固定するので,自分もそういう部品作りたいと思って早 10年w 重い腰を上げて 3D プリンタでブラケットを作ることにした.3D プリンタの部品だけで強固に固定できるとは思わないので,元の金具も残したまま,金具が外れた場合に風圧でハードトップが飛ばない程度の保険的位置づけとする.

まずは車体側の形状を計測.3D スキャナは持ってないので,ボール紙でピッタリ合うようにハサミで形を整えていき,型紙完成.リア側も同じような感じで形状を写し取る.

これを写真に撮って 3D モデリングソフトに取り込み,手動でトレースして,モデリング完成.例によって Thingiverse で 3D データ公開してます

で一旦形状確認のためにテスト出力することにした.樹脂がもったいない & 外形さえ確認できれば良い & 強度は不要,ということで,Top, Bottom, Wall を 2層,Infill を Lightning にする.特に Lightinig の効果が大きく,Lightinig は基本的には infill をせず,Top 面を作るための必要最小限のサポートのような infill が生成されるだけなので,樹脂 & 時間を節約できる (通常 7.5H→テスト出力 3.5H).
↑のスライサの断面図を見ると,中身がスカスカなのがよく分かる.

でテスト出力したものを車体につけてみたら,問題なさげなので本番出力.設定は Top, Bottom, Wall を 5層,infill を 30% にしたら,手で曲げようとしてもミシリとも言わないガチガチのパーツができたw
車体に接する部分は擦り傷になりそうだったのでフエルトを貼り付けたのち車体に取り付け.微妙にスキマ空いてるけど,固定は元の金具が担っているので,良しとする.

リア側はこんな感じ.

風圧程度では壊れない強度はあると思われるので,これでちょっとは安心できるようになって満足.
ヽ(´ー`)ノ

2025年9月21日日曜日

3D プリンタの直角を矯正した話

だいぶん前に買った 3D プリンタの Ender-3 Pro,結構できが良くて今まで不満なく不満があるところは改造しつつ,今のところ満足して使っている.で最近,出力したパーツの直角が出てないんじゃね? ということに今更ながら気づいた.

試しにサシガネで直角測ってみると,こんなに歪んでいる...

調べてみたところ,原因は 2つあって,
(1) ボルト穴に遊びがあるので,遊びの分だけフレームの直角・水平がずれる.これはよく考えればわかることで,これに関しては気づかなかった自分のミス.一旦ボルトを緩め,定規で測りながらボルトを締めることで解決.

(2) アルミ角材を T 字型にボルトで結合している箇所の,アルミ角材の切出しの直角が出ていない (2番めの写真はこれが原因).これはもともとのアルミ角材の加工がまずいということになる.
自分でヤスリで削って直角を出すことも考えたが,余計精度が狂いそうなので,角材と角材の間にアルミ箔を重ねたものを挟むことで直角を出すことにした.簡易的な方法だが,目視では分からないくらいには直角が出せた.
最後に直角を計測するテストパーツを出力して,問題ないことを確認できて満足ヽ(´ー`)ノ

この手のアルミ角材で組まれている 3D プリンタは巷に溢れているけど,どこもこんな感じなのかなぁ.同社の最新機種でもフレームの傾きは問題になってるっぽい→参考

2025年4月13日日曜日

PICO4 用 メガネレンズ

 VR ヘッドセットの PICO4 は,ネガネをかけて使うこともできるけど,メガネの鼻パッドにヘッドセットの重さがかかって鼻が痛くなる.PICO4 専用度付きレンズもあるみたいだけど,使ってないメガネのレンズを貼り付ければいいのでは? と思ってやってみた.

で PICO4 のレンズ部分にピッタリハマるフレームを 3D プリンタで作る.既存の物にピッタリ合うパーツを作るときは,自分は対象物の写真を撮って,曲線等で対象物の形をトレースしたあと,代表長を実物に合わせ込む.

でぎだ (Thingiverse で公開してます).あとはレンズをホットボンドで固定して (急に雑になるwww) 完成.

…と思ったら,レンズが顔から離れすぎて,レンズを通して見える範囲が狭かったので,ホットボンド盛り盛りでレンズを浮かせることで,顔に近づけたら問題なくなった.

鼻が痛くならなくなって超快適ヽ(´ー`)ノ

2025年1月17日金曜日

Android14 で hosts 書き換えが効かないときの対応


●いきなり結論
プライベート DNS 設定を {「OFF」か「自動」} 以外にする

●現象
スマフォの OS を crDroid (Android14) に書き換えたら,hosts 書き換えによる広告ブロックが効かなくなった.
不思議なのが,WiFi では効いているっぽいが,モバイルデータ通信では効いていない.

●Chrome の問題?
で調べてみると,chrome では独自に DNS の名前解決結果を独自にキャッシュしているようで,それをクリアしないといけないらしい.
chrome://net-internals/#dns を開くと,Clear host cache を押したが効果なし.
Lookup ボタンもあるので,hosts に記載のあるアドレスを入力してみたが,やっぱり hosts は効いていないようだった.

●Android の問題?
Chrome の問題なのか Android の問題なのか切り分けるために,Terminal emulator で名前引きしてみたところ,やっぱり hosts が効いていない.この時点で Chrome は関係なくなったが,ググってみても AI に聞いてみてもそれらしい解決策は無し.

●発見
仕方がないので,Android 設定で DNS と名のつくものを探したところ,プライベート DNS なる項目を発見.
デフォルトでは自動になっていたので,OFF にしてみたが,やっぱり hosts は効かない.
そこで,自動・OFF 以外の項目を選んでみたところ,ビンゴヽ(´ー`)ノ 無事 hosts が効いて広告がブロックされるようになった.
素性のよくわからない DNS を使うのはイヤなので,DNS 指定で dns.google を指定しておいた.

●ただし課題が...
このプライベート DNS の設定は,VPN 接続時にも有効らしく,VPN 接続アプリで指定している自宅 LAN の DNS が無視されてしまう (つまり自宅 LAN 配下の機器の名前解決ができない).この場合,プライベート DNS を OFF にすれば VPN の問題はなくなったが,VPN 接続時は手動で OFF にするしかなさそう.

このプライベート DNS,hosts,そしてネットワークから指定された DNS,の優先順位がさっぱりわからん.

2024年11月16日土曜日

Tuya スマートプラグを PowerShell で制御する

前回ブラウザからスマートプラグを制御したとき,URL の情報が見えていたので,後は HTTP リクエストを送れさえすれば制御は余裕と思っていたらそうではなかった.
リクエスト送信前に署名鍵を Tuya から取得し,その鍵で送信するリクエストデータの署名を作成し送信しないとだめっぽい.

で探してみたら,すでに Unix shell から制御するコードはあったので,ありがたくこれを PowerShell に変換してみたのが一番下のコード.

ハマったポイントは,

  • UNIX Time を秒数で得る命令 (Get-Date -UFormat %s) はタイムゾーン分の誤差が発生する (PowerShell のバグっぽい) ので,タイムゾーンオフセット分増減が必要.
  • 署名を作るために必要な Client Secret (Tuya developer サイトから取得する) は 16進32桁なので,128bit の数値だと思ったら,これはそのまま文字列データとして 256bit の数値として扱わないと,Tuya 側で有効な署名と認められなかった

でやった結果.Powershell で 10秒毎に消費電力を取得してみた.なかなか安価で消費電力のログ取れる環境は無いので,これはかなり満足度が高いヽ(´ー`)ノ

以下 PowerShell コード.

2024年11月10日日曜日

Tuya スマートプラグを PC から制御する

大昔にスマートプラグ (ネットワーク経由で On/Off できるコンセント) を買ったけど,独自の Android アプリでしか On/Off できなかったので,あまり使い道がなく放置していた.
で,最近これは Tuya という IoT プラットフォームに準拠した製品であることがわかったので,PC から制御してみた.
ところが Tuya のチュートリアル通りにやっても画面が説明と異なる等多々あり進まなかったので,自分でうまく行った手順を以下に記載しておく.

【開発者アカウント作成・デバイスのリンク】

●まずはスマートプラグと,Android の Smart Life アプリとの連携を済ませておく.

Tuya developer でアカウント作成

●Cloud → Create Cloud Project をクリック

●Create Cloud Project 画面で
  • Project Name: てきとう
  • Industry: Smart Home
  • Development: Smart Home
  • Data Center: データが保存されるサーバの場所? よくわからないがとりあえず Western America Datacenter
にして Create クリック

●Configuration Wizard はそのままで Authorize をクリック

●Devices → Link App Accout → Add App Account をクリックすると,QR コードが表示される

●Android の Smart Life アプリ右上の「+」 → QR コードをスキャン,をタップ後,PC の QR コードを読み込む

●Android アプリの「ログインを確認」をタップ

●以下のような画面が出てくるので,そのまま OK.これで Tuya developer アカウントとデバイスがリンクできた.

【デバイスを PC から制御する】

●どんな操作ができるか (コマンドがあるか) 調べてみる.
ここで表示されている Device ID が後々必要なので控えておき,Devices → All Devices → Debug Device をクリック

●Device Debugging をクリック.
Standard Instruction Set を見ると,使用できる設定系のコマンドがわかる.うちのだと,switch_1 / switch_2 で 2個あるコンセントの On/Off, countdown_n は秒数を設定するとその時間経過後に On/Off を反転する.

Standard Status Set を見ると,状態取得系のプロパティがわかる.うちのだとコンセントの On/Off 状態や,現在の電力が取得できる.

●Cloud → API Explorer をクリック

●Device Control の左の▶をクリック,Send Commands をクリック.

  • device_id: 先程調べた Device ID
  • code: switch_1 など
  • value: true, false など
で Submit Request をクリックすると,スマートプラグが On/Off される.
ここで,Request URL / Response をみると,どういうリクエストを送ればいいかが一発でわかるので,後は好きな言語で好きなように制御できる.もう少し手順が必要

●Get the status of a single device を実行すると,上の Standard Status Set で調べたプロパティが取得できる.

【最後に】

このスマートプラグ,電力計が付いていたので買ったものだが,電力見るのも専用アプリだけでログも取れないので放置していたが,これからは PC でログ取りできるので,かなり使えるアイテムになったヽ(´ー`)ノ

2024年8月31日土曜日

人生最大のデータ消失危機

 約 3年前に買った 6TB HDD の WD60EZAZ に突然アクセスできなくなった.症状としては

  • HDD を PC に接続すると,Win 起動中に HDD アクセスに行った時点で進まなくなる
    • OS 自体は別 SSD に入っており,OS が読めないわけでない
    • つまり,HDD を繋いでいるだけで OS が起動しない
  • (あまりおすすめしないけど) 経験的に,OS 起動後に SATA ケーブルを繋いでも HDD は認識するので,それをやってみたら,やはり HDD にアクセスした時点で何も進まなくなる
    • HDD アクセスしない他のアプリは動作可能

つまり,Win 用 HDD 修復ツールは一切使用できないことになる.

ここで GParted Live on USB が非常に役に立った.GParted は Linux 用パーティション操作ソフトだが,Linux が USB から起動できて,さらに testdisk (パーティション修復), photorec (削除ファイル復活) 等の HDD リカバリに有用なツールも使える.また Linux では HDD アクセスエラーになったら適当なところで諦めてくれるので,OS ごと固まることがない.

で色々調べた結果,プライマリパーティションテーブルは物理的に壊れているようだが,バックアップのパーティションテーブルは無事なようなので,ダメ元で Linux で NTFS パーティションをマウントしてみたら普通にマウントできたヽ(´ー`)ノ
今回の学びとしては,Windows でだめでも,Linux ならまだワンチャンアクセスできるということを得た.


最後に,HDD を廃棄する際の伝統儀式を実施.可能な限りバラバラにし,ネオジム磁石を取り出して完了w

自分は,Windows 上で Disk エラーを検出すると通知を出すようにしていて,前回の HDD 異常時はそれですぐに気付けて大事になることはなかったけど,今回はなんの前触れもなく突然壊れて困った.3TB / 4TB / 6TB と立て続けで HDD が壊れたので (それ以前は HDD 異常の経験無し),大容量になるにつれて HDD が脆くなってきたのかなぁ.

2024年4月28日日曜日

懸念していたことが現実になった

冠山峠道路のトンネルが開通したとのことで,林道の方に登るついでにトンネル見に行くか,と徳山ダムに向かって出発.で,現地に着いたら,

おいおいおいー,林道封鎖されとるやんけ(;´д⊂)

トンネルが開通したら林道の方は廃道にされるかも,と懸念していたが,それが現実のものになってしまった.一時的なものかもしれないけど,積極的に林道を修復する理由もなくなったので,走れるチャンスは確実に減ったはず.封鎖を確認したのは岐阜側で,もしかしたら福井側から登れるのかもしれんけど,景色がいいのは岐阜側の道なので,福井側から登っても意味がない.自分の行動範囲ではピカイチで景色が良かっただけに,ここが走れなくなるのは非常に悲しいなぁ.
あと,冠山峠道路のトンネル開通前はここを走りに来るのはドライブ目的の車しかなかったので交通量は少なかったが,今回は結構交通量多かった気がする.

つうわけで本来は通る予定がなかった冠山峠道路のトンネルを通って,能楽の里牧場なる場所に向かった.

実はあんまり期待してなかったんだけど,山頂は,木が一本もない素晴らしい眺め.しかも,360度全周にわたって視界を遮るものが無い絶景.
冠山峠道の林道が走れなくなった代わりに,いい場所見つけたヽ(´ー`)ノ

2024年3月30日土曜日

天神風の道公園で春の訪れを感じながらバイクツーリング


最近,技術的な話題はともかく,日記的な話題の blog を上げるのがだるくなってきて,めっきり更新頻度が減っている当 blog.
ここで,AI に blog 記事書かせてみたらいいんじゃね? と思ってやってみた.

入力した文章はこれ↓
====================================
次の文章を元にblogの記事を書いてください.

冬は寒かったので全然バイクに乗っていない.
今日は暖かかったので,本年初のバイクのり.
多くのライダーが集まる湖畔の里つきがせはスルーして天神風の道公園に行った.
ここは見晴らしが良く人も少ないのでお気に入り.
桜はあまり咲いてなかった.梅らしきものは咲きかけ.
====================================

出力された記事
===== ここから =================================

天神風の道公園で春の訪れを感じながらバイクツーリング

冬の間は寒くてバイクに乗る機会が減っていましたが、今日は暖かかったので今年初のバイクツーリングに行ってきました。多くのライダーが集まる湖畔の里つきがせはスルーして、見晴らしが良く人も少ない天神風の道公園を目指しました。

公園に到着すると、眼下に広がる景色に感動しました。遠くの山々まで見渡せる絶景は、まさに春の訪れを感じさせてくれます。桜はまだあまり咲いていませんでしたが、梅の花が咲き始めており、春の訪れを告げていました。

公園内を散策していると、気持ち良い風を受けてリフレッシュできました。人も少なく、静かな環境で自然を満喫することができました。

今年のツーリングシーズンは、天神風の道公園からスタートすることができて、とても良い思い出になりました。これから暖かくなるにつれて、色々な場所に出かけたいと思います。

公園情報

  • 天神風の道公園
  • 奈良県奈良市月ヶ瀬梅林
  • 駐車場あり
  • 無料

おすすめポイント

  • 見晴らしが良く、遠くの山々まで見渡せる
  • 人が少なく、静かな環境
  • 春は桜や梅の花が楽しめる

まとめ

天神風の道公園は、見晴らしが良く、静かな環境で自然を満喫できる公園です。春は桜や梅の花が楽しめるので、ツーリングの目的地におすすめです。

===== ここまで =================================

すげえよwww 「春の訪れ」とか自分では絶対書かないしそんな文才無いwww
しかも自己満足な記事ではではなく,公園情報や見どころまでまとめられて,ちゃんと他の人にとって役に立つ記事になっている.しょうもない記事を書くライターは廃業だなこれ.
これ見たら,ソースコード書くだけの人もそのうち淘汰されるだろうなぁ,というのも実感が湧いてくるね.

2024年3月24日日曜日

C++ で構造化アセンブリプログラミング

動機

原始的なアセンブラしか無い原始的な CPU のプログラミングをすることになった.
でアセンブリプログラミングの一番の萎えポイントとして,例えば C 言語だと
if(a == b){
  c = d;
}else{
  e = f;
}
みたいに書けるところが,構造化記述できないアセンブラだと
  cmp a, b
  jnz label0
  mov c, d
  jmp label1
label0:
  mov e, f
label1:
とラベルやら分岐命令やら,自分で生成しないといけないのでめんどくさいし,if がネストすると可読性も悪い.真面目にやるなら bison/flex とかでまともな構造化アセンブリ言語を設計するところだけど,そこまでやるのはなぁ... と思ったところで,C++ のクラス / 演算子オーバーロードをうまいこと使えば,構造化アセンブリプログラミングもどきが出来るのでは? と思った.
例えば,C++ で "r0 = r1;" と書いてコンパイル・実行すれば,"mov r0, r1" というテキストが得られる,みたいなイメージ.

まずは代入演算

//////////////////////////////////////////////////////////////////////////////
// Register

class RegisterObject {
public:
  RegisterObject(const char* szName) : m_szName(szName){}
  const char *Name(void) const {return m_szName;}
  
private:
  const char* m_szName;
};

class GpReg : public RegisterObject {
public:
  GpReg(const char* szName) : RegisterObject(szName){}
  
  GpReg& operator=(const GpReg& src){
    printf("\tmov\t%s, %s\n", Name(), src.Name());
    return *this;
  }
};

//////////////////////////////////////////////////////////////////////////////
// Register インスタンス

GpReg r0("r0");
GpReg r1("r1");
GpReg r2("r2");
GpReg r3("r3");

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  r0 = r1 = r2;
  return 0;
}
GpReg class は汎用レジスタをイメージしていて,特殊なレジスタがあれば RegisterObject か GpReg を継承する感じ.C++ ソースコード上の変数名 (r0 とか) は実行時には失われてしまうので,m_szName に変数名をセットしておく.
代入演算のキモは言うまでもなく "operator=" で,= が呼ばれたら mov 命令のテキストを出力する.
で実行結果:
        mov     r1, r2
        mov     r0, r1
おお,いい感じ.アセンブラだと r0 = r2 が直接代入できないので一旦 r1 を経由する,みたいなケースが多々あるが,それが 1行で書けるのはありがたい.

比較演算

次に,if-else-endif の構造化をやる前に比較演算子を定義する.
対象 CPU は,== なら cmpeq みたいに比較演算子毎に比較命令があり,その結果をフラグレジスタ f0 にセットする.条件分岐命令は f0 の値をみて分岐するかどうか決める.
class FlagReg : public RegisterObject {
public:
  FlagReg(const char* szName) : RegisterObject(szName){}
};

//////////////////////////////////////////////////////////////////////////////
// Register インスタンス

FlagReg f0("f0");

//////////////////////////////////////////////////////////////////////////////
// global な operator

FlagReg& operator==(const GpReg& a, const GpReg& b){
  printf("\tcmpeq\t%s, %s, f0\n", a.Name(), b.Name());
  return f0;
}

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  r0 == r1;
  return 0;
}
RegisterObject を継承して FlagReg を定義する. operater== で,== が呼ばれたら cmpeq 命令を出力して,== の返り値として f0 を返す.
で実行結果:
        cmpeq   r0, r1, f0
これはなんの問題もない.

if-else-endif

そしてこの取り組みの一番の目的である,if-else-endif の構造化をやってみる.
//////////////////////////////////////////////////////////////////////////////
// 構造化構文

int g_LabelCnt = 0;
std::vector<int> g_Label;

void _if(FlagReg& f){
  printf("\tjnset\t%s, _L%d\n", f.Name(), g_LabelCnt);
  g_Label.push_back(g_LabelCnt);
  ++g_LabelCnt;
}

void _else(void){
  printf("\tjmp\t_L%d\n", g_LabelCnt);
  printf("_L%d:\n", g_Label[g_Label.size() - 1]);
  
  g_Label.pop_back();
  g_Label.push_back(g_LabelCnt);
  ++g_LabelCnt;
}

void _endif(void){
  printf("_L%d:\n", g_Label[g_Label.size() - 1]);
  g_Label.pop_back();
}

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  _if(r0 == r1);
    r0 = r2;
  _else();
    r1 = r3;
  _endif();
  return 0;
}
_if ではフラグレジスタを受取り,必要な分岐命令を生成する.また if-else-endif はネストするので,分岐先ラベルの情報はスタックに push / pop する必要がある.
で実行結果:
        cmpeq   r0, r1, f0
        jnset   f0, _L0
        mov     r0, r2
        jmp     _L1
_L0:
        mov     r1, r3
_L1:
おおぉ,これこれ! これがやりたかったんだよ.この時点でこのやり方はかなりうまくいく感触を得ていたが,念の為 if がネストするケースをテストしてみたら,
コード:
//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  _if(r0 == r1);
    _if(r1 == r2);
      r2 = r0;
    _else();
      r3 = r1;
    _endif();
  _else();
    r1 = r3;
  _endif();
  return 0;
}
実行結果:
        cmpeq   r0, r1, f0
        jnset   f0, _L0
        cmpeq   r1, r2, f0
        jnset   f0, _L1
        mov     r2, r0
        jmp     _L2 ←※ここ
_L1:
        mov     r3, r1
_L2:
        jmp     _L3
_L0:
        mov     r1, r3
_L3:
んー,間違いではないんだけど,jmp _L2 の飛び先は jmp _L3 しか無いので,最適化の観点では「ここ」で jmp _L3 にすべき.
この最適化をやるためには,直接アセンブリテキストを出力するのではなく,一旦中間言語とかでメモリ上に溜めておき,最後に最適化フェーズを流す,等しないといけないということがわかった.
それを解決して,あとはメモリアクセスとかラベルへのサブルーチンコールとかを実装すれば,普通に使えそう.