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

3duilab が 2021年04月26日14時34分32秒 に編集

初版

タイトルの変更

+

角度検出できるドアセンサーをサーボモータで閉じる

タグの変更

+

IoT

+

非接触センサー

+

obniz

+

ドアセンサー

メイン画像の変更

メイン画像が設定されました

本文の変更

+

非接触空間センサー**双方向ハンドセンサー**(https://interactive-hand-sensor.com/root/)を使って**人の動線を検出する-1**です。 **ドアの角度を検出できるセンサー**で細かい動きを観測します。**今部屋から出ようとしている**とか**一瞬ドアが開いてすぐ閉まった**とかをウェブブラウザから**遠隔操作で検出**できます。 ## デモ動画 @[youtube](https://youtu.be/keM3mYh-kH4) ## システム概要 - センサーコントローラ:ドアの位置をUARTでobnizに送信する - obniz:UART受信の値からアニメのドア位置を描画する - obniz:サーボボタンクリックでサーボを動作してドアを閉める ==センサーの詳細は**ユーザーマニュアル**(https://interactive-hand-sensor.com/root/user-manual)を参照して下さい。== ## 接続図 ![キャプションを入力できます](https://camo.elchika.com/c28532e22e2f7fec8a4a328bc4dfe2f8dfe0c628/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f31383164613832352d646330322d343939302d626461342d3362323431386663646437372f34633034623532312d656636342d343031352d626266382d623738323238373136666130/) ![キャプションを入力できます](https://camo.elchika.com/2ff8f2e85f0a877bdc9169b3a73488ab95e3d8cf/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f31383164613832352d646330322d343939302d626461342d3362323431386663646437372f61366139303565322d383264332d346531612d623539322d373064363638313135656235/) ## システム詳細 ### ドア位置検出 - 写真のようにセンサーをケーブルで延長してドア蝶番周囲に両面テープで貼り付けます。 - センサー上にドアがある場合はその位置が現在位置です。 - センサー間にドアがある場合は前後のセンサーが反応するのでその大きい方の位置が現在位置です。 - ドアが開き、センサーを外れてしまうと外れた位置が現在位置です。 ### ドア位置アニメーション - 前回のドア描画を背景で上書きし消します。 - 現在のドアを描画します。 - ドア周囲の壁などを描写します。 ==サーボモータの描画も同様です。== ### サーボモータ - サーボモータのPWMは常に出力されています。 - ボタンクリックでPWMをドア角度相当のdutyに変更します。 - サーボモータはアクリル板に両面テープで接着しL字アングルで補強しています。 ## ソースコード ```html:obniz_app.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://cdnjs.cloudflare.com/ajax/libs/jcanvas/21.0.1/min/jcanvas.min.js"></script> <! *** jcanvas ***> <script src="https://unpkg.com/obniz@3.x/obniz.js" crossorigin="anonymous" ></script> </head> <body> <div id="obniz-debug"></div> <!img src="https://obniz.com/ja/users/4978/repo/image.png" style="position:absolute; left: 5%; top: 30%"> <input type="text" value="140" id="in_angle" maxlength="3" style="position: absolute; left: 5%; top: 38%; width:100px"/> <input type="text" value="degree" id="in_unit" maxlength="3" style="position: absolute; left: 12%; top: 38%; width:100px; border:0" readonly/> <button class="btn btn-primary" id="set" style="position: absolute; left: 5%; top: 45%; width : 70px">Set</button> <! *** button ***> <button class="btn btn-primary" id="reset" style="position: absolute; left: 9.5%; top: 45%; width : 70px">Reset</button> <! *** button ***> <button class="btn btn-primary" id="m30" style="position: absolute; left: 5%; top: 50%; width : 70px">-30</button> <! *** button ***> <button class="btn btn-primary" id="p30" style="position: absolute; left: 9.5%; top: 50%; width : 70px">+30</button> <! *** button ***> <canvas width="700" height="300"></canvas> <! *** jcanvas ***> <script> const SANG = 140.0; var obniz = new Obniz("OBNIZ_ID_HERE"); var ang = 90; // door angle var sAng2 = 0; // servo angel for animation var sAng = 0; // servo angle var stt = 0; // start time for elapse const position = '{"x":230, "y":50, "width":400, "height":20, "b_c":"white", "margin":10, "x2":150, "y2":120, "w2":120}';// b_c:back color const pos = JSON.parse(position); // called on online obniz.onconnect = async function() { // *** connect *** var uart = obniz.getFreeUart(); // ***uart *** uart.start({ tx: 9, rx: 10, gnd:8, baud:57600}); var servo = obniz.wired("ServoMotor", {gnd:5,vcc:4,signal:3}); servo.range = { min: 0.9, max: 1.34 } // *** servo S125 1T/2BB*** // servo.range = { min: 0.8, max: 2.7 } // MG92B servo.angle(sAng); // half position servo.on; // called while online. ************* loop *************** obniz.onloop = async function() { if(uart.isDataExists()){ lang = ang lsAng = sAng2; angStr = uart.readText(); // '0'~ '7' or '9' var cNum = parseInt(angStr.charAt(0));// 7, 6, .., 1, 0, 9 aLst = [110,93,80,70,60, 35,20,0,-0,125];// angle list ang = aLst[cNum]; console.log(sAng2);// ang, cNum let delBar = (val, col) => val + ((col == pos.b_c) ? pos.margin : 0); let dLst = []; // *** door *** dLst.push({fillStyle: pos.b_c, x: pos.x, y: pos.y, width: delBar(pos.width, pos.b_c), height: delBar(pos.height, pos.b_c), rotate: lang});// delete last door dLst.push({fillStyle: '#d4d4d4', x: pos.x,y: pos.y, width: delBar(pos.width,'#d4d4d4'), height: delBar(pos.height,'#d4d4d4'), rotate: 0});// default door position (grey) dLst.push({fillStyle: 'green', x: pos.x, y: pos.y, width: pos.width, height: pos.height, rotate: ang}); // current door dLst.push({fillStyle: pos.b_c, x: 0, y: 0, width: (pos.x + pos.margin*2) << 1 , height: (pos.y + pos.margin) << 1}); // corner square to hide dLst.push({fillStyle: pos.b_c, x: 0, y: 0, width: 600 , height: 80}); // corner square2 to hide dLst.push({fillStyle: 'grey', x: 0, y: (pos.y), width: pos.x << 1 , height:pos.height}); // left wall dLst.push({fillStyle: 'grey', x: pos.x + pos.width + pos.margin * 3, y: pos.y, width: (pos.x - pos.margin) << 1 , height:pos.height}); // right wall // *** servo *** dLst.push({fillStyle: 'yellow', x: pos.x2, y: pos.y2, width: 50, height: 50 }); sAng2 = getSAng2(); dLst.push({fillStyle: pos.b_c, x: pos.x2 + pos.w2 * Math.cos((SANG-lsAng) * Math.PI/180) * 0.5, y: pos.y2 + pos.w2 * Math.sin((SANG-lsAng) * Math.PI/180)* 0.5, width: delBar(pos.w2, pos.b_c), height:delBar(pos.height, pos.b_c), rotate: (SANG-lsAng)});// current servo dLst.push({fillStyle: 'orange', x: pos.x2 + pos.w2 * Math.cos((SANG-sAng2) * Math.PI/180) * 0.5, y: pos.y2 + pos.w2 * Math.sin((SANG-sAng2) * Math.PI/180)* 0.5, width: pos.w2, height:pos.height, rotate: (SANG-sAng2)});// current servo for (var rect of dLst) $('canvas').drawRect(rect); $('canvas').drawArc({fillStyle: 'purple', strokeWidth: 5, x: pos.x2, y: pos.y2, radius: pos.margin}); $('canvas').drawArc({strokeStyle: '#000', strokeWidth: 5, startArrow: true, arrowRadius: 15, arrowAngle: 90, x: pos.x2, y: pos.y2, radius: 50, start:160, end:220}); } servo.angle(sAng); // half position servo.on(); }; $("#set").on("click", function() { // jQuery id="close" on_method to click_event, handler_function sAng = parseInt($("#in_angle").val()); stt = performance.now(); }); $("#reset").on("click", function() { // jQuery id="close" on_method to click_event, handler_function sAng = 0; stt = performance.now(); // $("#in_angle").val(sAng.toString()); // overwrite text box }); $("#p30").on("click", function() { // jQuery id="close" on_method to click_event, handler_function sAng += 30; $("#in_angle").val(sAng.toString()); // overwrite text box }); $("#m30").on("click", function() { // jQuery id="close" on_method to click_event, handler_function sAng -= 30; $("#in_angle").val(sAng.toString()); // overwrite text box }); function getSAng2() { if (stt) { const elaEnd = 5000; var elaMs = performance.now() - stt; if (elaMs > elaEnd) { elaMs = elaEnd; stt = 0; return sAng; } return sAng * (elaMs / elaEnd); } else { return sAng; } } }; // called on offline obniz.onclose = async function() { uart.end(); for (i=0; i<10; i++) { servo.angle(0.0); // half position servo.on(); } }; </script> </body> </html> ``` 下のコード、ライブラリはこちら(https://os.mbed.com/users/maro/code/Nucleo_IHS11a/) ```html:mbed_Nucleo_IHS11a.cpp // *** IHS ver1.1a *** // *** Setting in Sensor.h: every/normal, single-board/cube/cube-dual(row-length) *** #include "mbed.h" #include "CLED.h" #include "SerialTest.h" // **************** global valiables ************************* extern const int COL_LEN; // **************** global functions ************************* char getMaxIdx(); // **************** global objects *************************** Sensor sensor(-70); // The smaller the value, the higher the height CLED cled(11); // IHSxx SerialTest st; // ********************** main ******************************* int main() { // ********************** get initial value ****************** cled.set(10); wait(1); sensor.set_adAryInit(); // set initial value // st.intvExec('x'); // *************************** loop ************************** while(1) { sensor.setAd(); st.intvExec(getMaxIdx()); } } char getMaxIdx() { Sensor& sen = sensor; const int MAX_AD = 100; const uint8_t NG_IDX = 9; uint8_t idx = NG_IDX; int maxV = 0; for (uint8_t i=0; i < COL_LEN; i++) { int val = sen.getColAd(i); if (val > maxV) { idx = i; maxV = val; } } uint8_t rev = (maxV > MAX_AD) ? idx : NG_IDX; return 0x30 + rev; } ```