この記事は 「Node-RED Advent Calendar 2019 - Qiita」の 17日目 の記事です。
今年の秋頃からNode-REDのはじめました。なんとなくですが使い方もわかってきたので工作をやてみようかなと思いました。 LEDを点灯させるのはよくある話なので、今回は木魚をならしてみたいと思います。

ハード編
木魚の鳴らし方としてはモーターを使用するを考えてましたが、SG90とかで駆動できるといいなあと思っていましたが、
木魚のバチを叩くほどのパワーはありませんでした。
歯車を使用してパワーを得ようとおもったのですが、今度はスピードが少しない感じです。
ということで、今回はソレノイドを使用して見ようと思います。 ソレノイドに関しては以下のサイトをみていただければと思いますが
簡単に言うとコイルに電源を流して、中の芯(ブランジャー)を動かすものになります。 身の回りのものでは電子ロックなどにも使われているような技術になります。
ブランジャーの動きによって種類があって
- プルソレノイド
- プッシュソレノイド
- 自己保持ソレノイド
があるようです。
小さいソレノイドは秋月電子さんや共立電子さんなどにも売っています。RaspberryPi程度の電源では小さなスイッチを操作する程度はありますが、 楽器のバチを叩く程度の大きなパワーを得られませんでした。 そこで今回はソレノイドで有名なタカハ機工さんのものを使用します。
大きめのパワーが得られて低い電圧でも駆動できるものを考えてCBS1240/CBS12400080(8Ω)に決めました。
【参考】
スペックとしては6Vで駆動できるようです。5Vだとちょっと動くかかなという不安はありますが…
タカハさんはAmazonPayで購入できるので通販もいいかなと思います。東京だったら秋葉原のラジオデパートの2階に明和電機さんのお店があるのでそちらで購入するのが手っ取り早いかもしれません。
回路としては以下の様になるかなと思います。RaspberryPiはGPIOは3.3Vなので、2SC1815を使用しています。

ここまできたらあとは木魚の高さを調節するためにタミヤのユニバーサルプレートを準備します。
昔ならボビーショップやプラモデル(ミニ四駆)を売っているようなところに売っていそうですが、地方ではそういう店に行っても割とおいてはいないので 通販をおすすめします。
ソフトウエア(Node-RED)編
あとはこれを制御するソフトウエアを作成することになりますが、今回はRaspberryPiにインストールしたNode-REDを使用します。
基本的にはGPIOのON/OFFを定期的に行う処理を行うことになります。繰り返しを行うので以下のエントリーを参考にループ処理を行います。
【参考】 qiita.com
こちらの例ではWhileループですが今回は無限ループで条件が発生した場合にはbreakするような処理になります。Whileの処理に近いといえば近いです。
手動で動作させるフローを先に出すとすると以下のようになるかなと思います。

今回のフローではGPIOの0/1切り替えをmsg.payloadで行い、全体の動作状態run/stopを司る変数をflow.modeとして制御しています。 一度フローを実行するとループに入り込んだ処理がストップ状態を書き換えてしまうので、新しく動作状態を作っています。
スタートとストップ
injectノードを使用してスタートとストップを操作できるようにしています。その後に続くchangeノードでflow.mode(string:{”run”|”stop”})と msg.payload(Integer:{0|1})を代入しています。
【スタート側の処理】

【ストップ側の処理】


ループ処理
ループに関する部分は以下のようになります。

switchノードでflow.modeでループ状態を判断し、

ループを抜けるかどうかを判断しています。

その後段のswitchノードでGPIOの0/1を判断しています。その後のchangeノードでmsg.payloadの0/1のトグル処理をしています。


もっと良い処理がありそうですが…
あとはmodeがrun状態であればGPIOに0.5秒毎に0/1が送られ、stop状態であればGPIOに0が常に送られます。

Webからの起動
Webからも木魚を鳴らせるようにしようと思います。
これはかんたんにhttp inノードを使ってURLアクセスをしたらflow.modeとmsg.payloadに代入しています。 injectノードのあとの処理を代用しても良かったのですが、今回は新規に作っています。
Web経由でスタートする場合には/mokugyo/on

Web経由でストップする場合には/mokugyo/off

Webアクセスの部分を切り出すとこのような形になっています。

changeノードで値を設定したらループのswitchノードと接続すればOKです。これはよくあるパターンです。
最終的にできたフロー再掲
最終結果のフローはこのような形になります。

動作確認
では、実際に動かしてみようと思います。
無事に動作しました!
おわりに
【今回作成したフロー】
[
{
"id": "c7f37167.82ae8",
"type": "tab",
"label": "フロー 1",
"disabled": false,
"info": ""
},
{
"id": "1aaeee48.d52b52",
"type": "inject",
"z": "c7f37167.82ae8",
"name": "スタート",
"topic": "",
"payload": "1",
"payloadType": "num",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 100,
"y": 60,
"wires": [
[
"9814504b.3fe4e"
]
]
},
{
"id": "8507ccb5.08e81",
"type": "rpi-gpio out",
"z": "c7f37167.82ae8",
"name": "",
"pin": "7",
"set": true,
"level": "0",
"freq": "",
"out": "out",
"x": 940,
"y": 160,
"wires": []
},
{
"id": "95fb4ec1.979e7",
"type": "delay",
"z": "c7f37167.82ae8",
"name": "",
"pauseType": "delay",
"timeout": "0.5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"x": 790,
"y": 400,
"wires": [
[
"d653f7e0.0643a8"
]
]
},
{
"id": "c867ec32.1ecab",
"type": "switch",
"z": "c7f37167.82ae8",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "0",
"vt": "num"
},
{
"t": "eq",
"v": "1",
"vt": "num"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 590,
"y": 280,
"wires": [
[
"8507ccb5.08e81",
"9d8ff730.f633d8"
],
[
"8507ccb5.08e81",
"c4583abd.9d70b8"
],
[]
]
},
{
"id": "9d8ff730.f633d8",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "1",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 840,
"y": 260,
"wires": [
[
"95fb4ec1.979e7"
]
]
},
{
"id": "c4583abd.9d70b8",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "0",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 840,
"y": 300,
"wires": [
[
"95fb4ec1.979e7"
]
]
},
{
"id": "d653f7e0.0643a8",
"type": "switch",
"z": "c7f37167.82ae8",
"name": "",
"property": "mode",
"propertyType": "flow",
"rules": [
{
"t": "eq",
"v": "stop",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 330,
"y": 300,
"wires": [
[
"5b0120c0.1a77d"
],
[
"c867ec32.1ecab"
]
]
},
{
"id": "5b0120c0.1a77d",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "0",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 620,
"y": 160,
"wires": [
[
"8507ccb5.08e81"
]
]
},
{
"id": "9814504b.3fe4e",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "mode",
"pt": "flow",
"to": "run",
"tot": "str"
},
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "1",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 260,
"y": 60,
"wires": [
[
"d653f7e0.0643a8"
]
]
},
{
"id": "b918518b.9cd01",
"type": "inject",
"z": "c7f37167.82ae8",
"name": "ストップ",
"topic": "",
"payload": "1",
"payloadType": "num",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 100,
"y": 120,
"wires": [
[
"c534e253.12e65"
]
]
},
{
"id": "c534e253.12e65",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "mode",
"pt": "flow",
"to": "stop",
"tot": "str"
},
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "0",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 260,
"y": 120,
"wires": [
[
"d653f7e0.0643a8"
]
]
},
{
"id": "f8156f4b.6600a",
"type": "http in",
"z": "c7f37167.82ae8",
"name": "WEBアクセスでスタート",
"url": "/mokugyo/on",
"method": "get",
"upload": false,
"swaggerDoc": "",
"x": 190,
"y": 500,
"wires": [
[
"5859b9e7.453f78"
]
]
},
{
"id": "5859b9e7.453f78",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "mode",
"pt": "flow",
"to": "run",
"tot": "str"
},
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "1",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 430,
"y": 500,
"wires": [
[
"8593011b.c3a39",
"d653f7e0.0643a8"
]
]
},
{
"id": "8593011b.c3a39",
"type": "debug",
"z": "c7f37167.82ae8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 670,
"y": 520,
"wires": []
},
{
"id": "81a03b2e.ebacf8",
"type": "http in",
"z": "c7f37167.82ae8",
"name": "WEBアクセスでストップ",
"url": "/mokugyo/off",
"method": "get",
"upload": false,
"swaggerDoc": "",
"x": 190,
"y": 560,
"wires": [
[
"552120e4.469a5"
]
]
},
{
"id": "552120e4.469a5",
"type": "change",
"z": "c7f37167.82ae8",
"name": "",
"rules": [
{
"t": "set",
"p": "mode",
"pt": "flow",
"to": "stop",
"tot": "str"
},
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "0",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 430,
"y": 560,
"wires": [
[
"8593011b.c3a39",
"d653f7e0.0643a8"
]
]
}
]

