84motのアイコン画像
84mot 2021年05月16日作成 (2021年05月16日更新)
製作品 製作品 閲覧数 553
84mot 2021年05月16日作成 (2021年05月16日更新) 製作品 製作品 閲覧数 553

陰影キープ ターンテーブル

陰影キープ ターンテーブル

アイデア

自分のカスタムしたバイクを眺めるのはとても楽しい時間。
その中でも夜のコンビニで眺めるバイクは、バイクに落ちる陰影で違った表情が見えて格別。

愛車の一番かっこいい陰影っぷりを追及してその姿をいつも見たい。

そんな思いから、バイクと太陽の方向との相対角度をキープしつつ回る事で最高の陰影をキープし続けるターンテーブルを作りました。

陰影っぷりによって表情が変わる例:

こんな感じに陰影の出方で表情が変わる。
最高の陰影状態の愛車を眺めてうっとりしたい。

※以下は家にあったおもちゃの例です

左から光 上から光 右から光
キャプションを入力できます キャプションを入力できます キャプションを入力できます

当初の思想↓

①バイクが乗るくらいのターンテーブルを作ってバイク乗せる
②太陽方位を返してくるWebAPIを使って経度・緯度・時間・日付に応じた正確な太陽方位を取得
③太陽方位とバイクの相対角度をいい感じにキープしつづける様テーブルを回す
④バイクが置かれている場所の天気を取得し、晴れの時は上記の動作、曇り、雨などの影がないときはランダム方向にバイクを向ける

だったのですが、時間の問題やら謎のAPIの挙動にいじめられるなどによりだいぶ規模が縮小してしまいました。
とりあえず小さなフィギュアが乗るレベルのものを作りました。
さらに太陽方位のAPIもうまく取得できなかったので簡易版です。無念。

デモ動画

サーボで初期位置に対象(バイク)を動かした後、天気、時間などにより所定の角度に調整し続けます。
(ただし実際は時間オーダーでジリジリ動く上、撮影日は曇りのため動画映えせず)

ここに動画が表示されます

部品

・obnizBoard1Y
・サーボ
・電源
・3Dプリンタで出力したちょっとしたパーツ
  テーブル部の足の部分とかその他諸々

以下本当は用意したかったもの
(・カスタムしたかっこいいバイク)
(・ターンテーブルを置いておける場所)
(・バイクが乗っても大丈夫な頑丈なテーブル)
(・テーブル回せるだけの強いモーター)

土台 テーブル裏の部品
キャプションを入力できます キャプションを入力できます

設計図

キャプションを入力できます

コード

当初は簡単なプログラムなのでブロックプログラミングでいけるかなと思っていました。(Jacascript触ったことないし)
ところがブロックプログラミングでは外部のAPIを使うブロックが存在しないことが判明。
途中からjavascriptをがんばって打ち込んでいました。

なので、コードはブロックプログラミングの残りかすみたいなものが多く存在します。
さらにデバッグ用のコードや途中でコピペしまくったものも苦労の足跡として特に消していないので超絶見にくいです。すみません。

もしコードを追おうとする人がいるのであればhtml箇所は無視してください(自動生成されたものを触っていないので)
途中のscript記載部が触ったところです。

実際のコード

<html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous" ></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous" ></script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" /> </head> <body> <h3 id="bploading" style="text-align:center;">LOADING...</h3> <div id="OBNIZ_OUTPUT"></div> <br /> <script src="https://unpkg.com/obniz@latest/obniz.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/iothome/index.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/airobot/index.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ui/index.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/howler2.1.2/howler.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/opencv3.4/opencv.js" crossorigin="anonymous" ></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.3.0"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet@2.1.0"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/posenet@2.2.2"></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/clmtrackr/clmtrackr.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/clmtrackr/emotion_classifier.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/clmtrackr/emotionmodel.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/clmtrackr/model_pca_20_svm.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/ai/index.js" crossorigin="anonymous" ></script> <script src="https://unpkg.com/obniz-parts-kits@0.16.0/storage/index.js" crossorigin="anonymous" ></script> <script> $("#bploading").text("RUNNING..."); (async function(){ var obniz, slider, label, servomotor,angle1,angle2,offsetangle; function mathRandomInt(a, b) { if (a > b) { // Swap a and b to ensure a is smaller. var c = a; a = b; b = c; } return Math.floor(Math.random() * (b - a + 1) + a); } obniz = new Obniz('your_obnizID_here'); await obniz.connectWait(); obniz.display.print('サーボくるくる') slider = new ObnizUI.Slider(); label = new ObnizUI.Label('label'); labe2 = new ObnizUI.Label('label2'); servomotor = obniz.wired("ServoMotor",{"signal":0, "vcc":1, "gnd":2}); labe2.setText(await _ai.getWeather('aichi') ); angle1 = 90; //初期ーサーボ角度定義 servomotor.angle (angle1); await obniz.wait(1000); //サーボ動くまでの待ち時間 1000ms offsetangle = 30; // 飾りたい対象がかっこよく映る角度。(光源である太陽からの相対角度)。ここは任意 console.log('tsetやで'); console.log(angle2); /* 苦労の足跡① fetchでいけるんでしょきっと。 fetch('https://mgpn.org/api/sun/position.cgi?json&y=2000&m=5&d=5&h=12&min=15&lat=35.6544&lon=139.7447', { オプション }) .then((response) => { if (!response.ok) { throw new Error(); } return response.blob(); // あるいは response.json() }) .then((blob) => { }) .catch((reason) => { // エラー }); fetch('http://example.com/movies.json') .then(response => response.json()) .then(data => console.log(data)); */ /* 苦労の足跡② とりあえずconsoleに何か出したい const url = 'https://mgpn.org/api/sun/position.cgi?lat=35.6544&lon=139.7447'; fetch(url).then(function(response) { return response.text(); }).then(function(text) { console.log(text); }); */ /* 苦労の足跡③ json形式の指定とかがいるとか? let data = await (await fetch('https://mgpn.org/api/sun/position.cgi?json&y=2000&m=5&d=5&h=12&min=15&lat=35.6544&lon=139.7447', { mode: 'cors' })).json(); console.log(data); */ /* 苦労の足跡④ corsとはなんぞ。 let data = await fetch('https://mgpn.org/api/sun/position.cgi?json&y=2000&m=5&d=5&h=12&min=15&lat=35.6544&lon=139.7447', { mode: 'cors' }); let data1 = await data.json(); console.log(data1); */ /*  苦労の足跡⑤ fetchでなくXHRでなら。。。 太陽方位をとるAPIでないのであればうまくいく。なぜか。 let request = new XMLHttpRequest(); request.open('GET', "https://api.adviceslip.com/advice"); request.responseType = 'json'; request.onload = function() { console.log(request.response.slip.advice); }; request.send(); */ // 苦労の足跡⑥ さて太陽方位APIで。と思ったけどやっぱり無理ぽ。ここで時間切れ let request = new XMLHttpRequest(); request.open('GET', "http://mgpn.org/api/sun/position.cgi?json&y=2000&m=5&d=5&h=12&min=15&lat=35.6544&lon=139.7447",true); //request.responseType = 'json'; request.send(); request.onload = function() { console.log("onloadに入った"); console.log(request.response); }; await obniz.wait(200); if (_ai.sunny.includes( await _ai.getWeather('aichi') )) { //愛知が晴れの時 //API経由で取得することができなかったのでやむなく単純化。無念。 //6時が日の出、12時が南中、18時が日の入り、単純化して、太陽方向をサーボが向く様にする angle2 = ((test.getHours()-6)/6*90)+offsetangle; if (angle2 >180){ //サーボ最大角度制限 angle2 = 175; }else if (angle2 < 0 ){ //サーボ最小角度制限 angle2 = 5; } } else if (_ai.cloudy.includes( await _ai.getWeather('aichi') )) { //愛知が曇りの時 angle2 = mathRandomInt(1, 180); //ランダムな角度にする } else if (_ai.rain.includes( await _ai.getWeather('aichi') )) { //愛知が雨の時 angle2 = mathRandomInt(1, 180); //ランダムな角度にする } else if (_ai.snow.includes( await _ai.getWeather('aichi') )) { //愛知が雪の時 angle2 = mathRandomInt(1, 180); //ランダムな角度にする } while (true) { await ObnizUI.Util.wait(0); servomotor.angle (angle2); //ここまでに計算した値にサーボを動かす //デバッグ用。サーボがぐりぐり動くかどうかを確認する。 while ((await obniz.switch.getWait() == 'push')) { await ObnizUI.Util.wait(0); servomotor.angle(90); await obniz.wait(500); servomotor.angle(125); await obniz.wait(200); servomotor.angle(90); await obniz.wait(200); servomotor.angle(45); await obniz.wait(200); servomotor.angle(90); await obniz.wait(200); } } true; })(); </script> </body> </html>

あとがき

今回初めてobnizを触りましたが、携帯からも気軽にコードを触れる点はよいところだなと思いました。
半面、デバッグ環境という意味では機能が少なく、arduinoと同じ様に1つ1つコンソールに打ち出さなければいけないなど暗中模索状態では若干つらいものがありました。

とはいえ今回初めてWebAPIなどで遊ぶチャレンジができましたので、電子工作→Web という方向のルートとしてobnizを使っていくのはありだなーと感じましたし、とても楽しかったです。

ログインしてコメントを投稿する