編集履歴一覧に戻る
mametarou963のアイコン画像

mametarou963 が 2021年04月18日10時55分08秒 に編集

コメント無し

本文の変更

## 背景 私事ですが、会社で老眼はやっぱりしんどいという話題が何度かあがりました。 また、同年代にも近くが見えにくくなっている気がするという話が出ました。 調べてみると、パソコン作業をする方のほうが症状が出やすい傾向にあるようです。 コロナの影響により、自粛する機会が増え、 パソコンやテレビ、スマートフォンを見る機会も以前よりさらに増えるものと思いますので、 老眼に気を付けて生活する必要があると考えました。 そこで、老眼予防トレーニングを楽しく、効率的に続けられるガジェットを考えてみました。 ### 一般的な老眼予防トレーニング [たった10秒で、目指せ「55歳まで老眼鏡いらず」](https://style.nikkei.com/article/DGXNASFK18015_Y0A810C1000000/)で紹介されている手順は以下の通りです。 1. 近視、遠視の人はメガネやコンタクトで、きちんと遠くが見える状態に矯正する 1. 目の前15cmのところに指やペンを立て、まず先端にピントを合わせる努力をする 1. まずその先端にピントを合わせる。続いて一直線上にある遠くのものに、それぞれ1秒ずつピントを合わせる 1. 2と3を繰り返す。2秒×5往復(たった10秒!)これを1日10回を目標に ### 一般的な老眼予防トレーニングの問題点と仕様 先のトレーニングを実際にやってみると(人によっては)以下の問題が発生します 1. 「近くのものにピントを合わせる」「遠くのものにピントを合わせる」の甘辛が自分判定なのでだんだん雑になる 1. 遠くの景色がないオフィスなどでは「遠くのもの」を選択することが難しい 1. 通常ではありえない位置に鉛筆を置くため、周りから、「あの人何やっているの?」と白い目で見られる これらの問題を解決するようなガジェットを考えました。 ### トレーニング準備 * トレーニングに使用するもの * 老眼予防トレーニングガジェット(obniz Board 1Y + Joy Stick) * Web画面が表示できるデバイス(PCやスマホなど) 1. 「Web画面が表示できるデバイス」から、ピントが合う範囲で一定距離をおきます 1. 老眼予防トレーニングガジェットのジョイスティック部分を持ち、目から15cm程度のところにガジェットの液晶をかまえます 1. トレーニングを開始します ### トレーニング 1. 老眼予防トレーニングガジェット側の液晶側にピントを合わせ(近くのものにピントを合わせる)、表示された矢印方向にジョイスティックを入力します 1. Web画面にピントを合わせ(遠くのものにピントを合わせる)、表示された矢印方向にジョイスティックを入力します 1. 1と2を繰り返します。(※好きなタイミングで終了) ### 改善内容・効果 本ガジェットは「一般的な老眼予防トレーニングの問題点」を解決します 1. ピントが合っていないと正しい矢印を入力できないので、しっかりピントを合わせて毛様体をトレーニングすることができます 1. 景色の見えずらく、室内で遠くのものを設定しにくい環境でも、web画面に表示される矢印を見ることで「遠くのものにピントを合わせる」ことが可能になります 1. 物を目元15cmに持ってくる動作はかなり気味が悪いですが、「老眼対策トレーニングガジェット」を目元に持ってきているため、周りに活動の意図が伝わりやすく、不審がられる心配がない ## 部品 * obniz Board 1Y * JoyStick * (必要に応じて)モバイルバッテリー ※パソコンなどからのUSB給電でも可 ![部品](https://camo.elchika.com/e5b960bf226e7961bb1e98911b26dff120e79d8c/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66643265623836652d623336622d343438652d383961342d6164366436373031303335312f64303665356465352d373230372d346233342d613232662d313038303536333666623632/) ## 接続図 [obniz公式のJoyStick通り](https://obniz.com/ja/sdk/parts/JoyStick/README.md)に接続してください。 そのまま左手で握れば操作できます。 右手で操作したい方は、ピン0~4の代わりに7~11を使用し、ソースのピンアサインを変えれば対応できます。 ![接続図](https://camo.elchika.com/7b4e8c82f22e23c22c3582a1d0afc55aa17de7e1/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66643265623836652d623336622d343438652d383961342d6164366436373031303335312f64663336336231392d353763662d343862362d626165382d333130303563383032643665/) ## 持ち方 ![持ち方](https://camo.elchika.com/30586ab14ff386fdc038ae12fafa16d7f20996a7/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66643265623836652d623336622d343438652d383961342d6164366436373031303335312f61633565343139322d346262332d343462322d383462322d663665313830383562353737/) ## 動作のようす(トレーニングのようす)

+

近く側(obnizの液晶)と遠く側(PC)を交互に見ながら、表示される矢印をjoyStickで入力していく様子です。 ビデオ側のピントが人間のピントにおきかえてご覧いただければと思います。 @[youtube](https://www.youtube.com/watch?v=6Eya4aOEEQE&feature=youtu.be)

## プログラム ```html:プログラム <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" /> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://unpkg.com/obniz@3.13.0/obniz.js" crossorigin="anonymous" ></script> </head> <body> <canvas id="canvas" width="300" height="300" style="-webkit-font-smoothing:none" ></canvas> <script> // enum var KeyInput = { up: 0, down: 1, right: 2, left: 3, neutral: 4, }; // enum // 乱数で状態で上下左右待ち状態を決めるという横着をしたいため、0-3の並びは変えない var TrainingArrowState = { upDisp: 0, downDisp: 1, rightDisp: 2, leftDisp: 3, wait: 4, }; var TrainingDispType = { obnizDisp: 0, webDisp: 1, }; var obniz = new Obniz("OBNIZ_ID_HERE"); obniz.onconnect = async function () { var joyStick = new JoyStick(obniz); var keyInputDisplay = new KeyInputDisplay(); var obnizDisplay = new ObnizDisplay(obniz); var webDisplay = new WebDisplay(); var trainingFacilitator = new TrainingFacilitator(); joyStick.add(keyInputDisplay); joyStick.add(trainingFacilitator); trainingFacilitator.add(obnizDisplay); trainingFacilitator.add(webDisplay); trainingFacilitator.trainingStart(); console.log("start"); }; class TrainingFacilitator { constructor() { this.dispType = TrainingDispType.obnizDisp; this.arrowState = TrainingArrowState.wait; this.facilitatorKeyInput = KeyInput.neutral; this.trainingFacilitatorObservers = new Array(); } trainingStart() { this.dispType = TrainingDispType.obnizDisp; this.arrowState = Math.floor(Math.random() * (3 + 1 - 0)) + 0; console.log("state is " + this.arrowState); this.trainingFacilitatorObservers.forEach((observer) => observer.notifyTrainingFacilitator(this.dispType, this.arrowState) ); } // オブザーバーの追加 add(observer) { this.trainingFacilitatorObservers.push(observer); } // キー入力の受信時 notifyKeyInput(trainingFacilitatorInputVal) { var inputCorrect = false; if ( trainingFacilitatorInputVal == KeyInput.up && this.arrowState == TrainingArrowState.upDisp ) inputCorrect = true; else if ( trainingFacilitatorInputVal == KeyInput.down && this.arrowState == TrainingArrowState.downDisp ) inputCorrect = true; else if ( trainingFacilitatorInputVal == KeyInput.left && this.arrowState == TrainingArrowState.leftDisp ) inputCorrect = true; else if ( trainingFacilitatorInputVal == KeyInput.right && this.arrowState == TrainingArrowState.rightDisp ) inputCorrect = true; // 正解した場合、各状態を更新 if (inputCorrect == true) { console.log("collect!"); // 描画する画面タイプの更新 this.dispType = (this.dispType + 1) % (TrainingDispType.webDisp + 1); // enumが使えないため苦肉の策 // 矢印の更新 this.arrowState = Math.floor(Math.random() * (3 + 1 - 0)) + 0; // 状態の通知 this.trainingFacilitatorObservers.forEach((observer) => observer.notifyTrainingFacilitator(this.dispType, this.arrowState) ); } } } class ObnizDisplay { constructor(obniz) { this.obnizDisplay = obniz.display; } notifyTrainingFacilitator( trainingFacilitatorDispType, trainingFacilitatorState ) { this.obnizDisplay.clear(); this.obnizDisplay.line(59, 32, 69, 32); this.obnizDisplay.line(64, 27, 64, 37); if (trainingFacilitatorDispType != TrainingDispType.obnizDisp) { return; } if (trainingFacilitatorState == TrainingArrowState.upDisp) { this.obnizDisplay.line(64, 13, 64, 23); this.obnizDisplay.line(64, 13, 60, 17); this.obnizDisplay.line(64, 13, 68, 17); } else if (trainingFacilitatorState == TrainingArrowState.downDisp) { this.obnizDisplay.line(64, 51, 64, 41); this.obnizDisplay.line(64, 51, 60, 47); this.obnizDisplay.line(64, 51, 68, 47); } else if (trainingFacilitatorState == TrainingArrowState.leftDisp) { this.obnizDisplay.line(45, 32, 55, 32); this.obnizDisplay.line(45, 32, 49, 28); this.obnizDisplay.line(45, 32, 49, 38); } else if (trainingFacilitatorState == TrainingArrowState.rightDisp) { this.obnizDisplay.line(83, 32, 73, 32); this.obnizDisplay.line(83, 32, 79, 28); this.obnizDisplay.line(83, 32, 79, 38); } } } class WebDisplay { notifyTrainingFacilitator( trainingFacilitatorDispType, trainingFacilitatorState ) { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); // + ctx.beginPath(); ctx.moveTo(135, 150); ctx.lineTo(165, 150); ctx.stroke(); ctx.beginPath(); ctx.moveTo(150, 135); ctx.lineTo(150, 165); ctx.stroke(); if (trainingFacilitatorDispType != TrainingDispType.webDisp) { // 画面描画タイプがobniz出ない場合は画面はまっさらにしておく return; } if (trainingFacilitatorState == TrainingArrowState.upDisp) { ctx.beginPath(); ctx.moveTo(150, 125); ctx.lineTo(150, 95); ctx.stroke(); ctx.beginPath(); ctx.moveTo(150, 95); ctx.lineTo(160, 105); ctx.stroke(); ctx.beginPath(); ctx.moveTo(150, 95); ctx.lineTo(140, 105); ctx.stroke(); } else if (trainingFacilitatorState == TrainingArrowState.downDisp) { ctx.beginPath(); ctx.moveTo(150, 175); ctx.lineTo(150, 205); ctx.stroke(); ctx.beginPath(); ctx.moveTo(150, 205); ctx.lineTo(140, 195); ctx.stroke(); ctx.beginPath(); ctx.moveTo(150, 205); ctx.lineTo(160, 195); ctx.stroke(); } else if (trainingFacilitatorState == TrainingArrowState.leftDisp) { ctx.beginPath(); ctx.moveTo(125, 150); ctx.lineTo(95, 150); ctx.stroke(); ctx.beginPath(); ctx.moveTo(95, 150); ctx.lineTo(105, 140); ctx.stroke(); ctx.beginPath(); ctx.moveTo(95, 150); ctx.lineTo(105, 160); ctx.stroke(); } else if (trainingFacilitatorState == TrainingArrowState.rightDisp) { ctx.beginPath(); ctx.moveTo(175, 150); ctx.lineTo(205, 150); ctx.stroke(); ctx.beginPath(); ctx.moveTo(205, 150); ctx.lineTo(195, 140); ctx.stroke(); ctx.beginPath(); ctx.moveTo(205, 150); ctx.lineTo(195, 160); ctx.stroke(); } } } } // 表示のテスト class KeyInputDisplay { notifyKeyInput(displayInputVal) { var inputCharactor = "・"; if (displayInputVal == KeyInput.up) inputCharactor = "↑"; else if (displayInputVal == KeyInput.down) inputCharactor = "↓"; else if (displayInputVal == KeyInput.right) inputCharactor = "→"; else if (displayInputVal == KeyInput.left) inputCharactor = "←"; $("#xStatus").text(inputCharactor); console.log(inputCharactor); } } // JoyStickクラス // JoyStick入力を上下左右入力に変換・キーの入れっぱなしを吸収 // うまくクラスに隠せなかったためしかたなくglobal変数 keyInput = KeyInput.neutral; joyStickObservers = new Array(); joyStickXval = 0; joyStickYval = 0; class JoyStick { constructor(obniz) { this.keyInput = KeyInput.neutral; this.joyStick = obniz.wired("JoyStick", { gnd: 4, sw: 0, y: 1, x: 2, vcc: 3, }); // onchangexとonchangeyはほぼ同じロジックのため関数化したかったが難しかったためコピペ this.joyStick.onchangex = function (val) { joyStickXval = val; var newKeyInput = KeyInput.neutral; if (Math.abs(joyStickXval) > 0.9 && Math.abs(joyStickYval) > 0.9) { } else if (joyStickXval > 0.9) { newKeyInput = KeyInput.down; } else if (joyStickXval < -0.9) { newKeyInput = KeyInput.up; } else if (joyStickYval > 0.9) { newKeyInput = KeyInput.left; } else if (joyStickYval < -0.9) { newKeyInput = KeyInput.right; } if (keyInput != newKeyInput) { joyStickObservers.forEach((observer) => observer.notifyKeyInput(newKeyInput) ); keyInput = newKeyInput; } }; this.joyStick.onchangey = function (val) { joyStickYval = val; var newKeyInput = KeyInput.neutral; if (Math.abs(joyStickXval) > 0.9 && Math.abs(joyStickYval) > 0.9) { } else if (joyStickXval > 0.9) { newKeyInput = KeyInput.down; } else if (joyStickXval < -0.9) { newKeyInput = KeyInput.up; } else if (joyStickYval > 0.9) { newKeyInput = KeyInput.left; } else if (joyStickYval < -0.9) { newKeyInput = KeyInput.right; } if (keyInput != newKeyInput) { joyStickObservers.forEach((observer) => observer.notifyKeyInput(newKeyInput) ); keyInput = newKeyInput; } }; } // オブザーバーの追加 add(observer) { joyStickObservers.push(observer); } } </script> </body> </html> ```