Node-RED MCU用のノードを作成しよう！（Servoノード編）

# はじめに

趣味的ロボット研究所の管理人([@404backG](https://twitter.com/404backG))ことbackgroundです。
先日、Node-RED MCU本の補足書に執筆させていただきました。Qiitaには初投稿です。

[Node-RED Advent Calendar 2023](https://qiita.com/advent-calendar/2023/node-red) の14日目を担当します。この記事では**Node-RED MCU用のノードの作成**について書かせていただきます。

▼普段はホームページにいろいろ書いています。

https://404background.com/

▼ホームページでのNode-RED関連の記事はこちらにまとめています。

https://404background.com/know-how/node-red/

▼補足書にも書いたのですが、Node-RED MCU用のLINE Notifyノードは作成したことがあります。

https://404background.com/program/node-create/
 
# この記事の目的
　Node-REDで使うことができるノードは、**そのすべてがNode-RED MCUに対応しているわけではありません。** また、今回扱うサーボモーターのように、知識が無いと使い方が分からないこともあると思います。まだまだ足りていないノードがあるのです。
　こういった現状の問題を解決するには、**有識者がノードを作れば良い**と考えています。

　この記事では、**電子工作やプログラミングにはじめて触れる人でも簡単に使える便利なノードを作ること**を目的とします。
 
　今回の内容ぐらいならJavaScriptで書いてfunctionノードで実行することもできるのですが、ノードを並べるだけで使えるようにした方が第三者にとって便利でしょう。
　詳しく書くと膨大な量になるので、私の作成の手順を簡単に紹介します。
 
# 環境について
▼Node-RED MCUの環境はRaspberry Pi 400に構築しています。

https://404background.com/program/node-red-mcu-v4/

:::note warn
10/12にリリースされたModdable SDK 4.2で、ESP-IDFのバージョン5.1.1が必要になりました。
[『はじめてのNode-RED MCU Edition』](https://www.kohgakusha.co.jp/books/detail/978-4-7775-2249-1)とは環境構築の方法が変わっているところがありますので、ご注意ください。
変更内容は以下のページからご確認ください。
https://www.kohgakusha.co.jp/support/node-red-mcu/index.html
:::

:::note info
バージョンアップデートに合わせて、補足書も出版されています。11月11日版は私も執筆させて頂きました。
https://techbookfest.org/product/b3T2EQ7Sw4BGzjwvv1ak1K?productVariantID=6KyS0CyiTvYmyBZDtLb4Uh

https://techbookfest.org/product/wwADMShyx2RuB9zjnrUaz0?productVariantID=6v5hDHmdjF9Qv0t8H2KgUj

:::
　ボードは**Moddable Two**を使います。ESP32とタッチディスプレイを搭載しています。
▼ハッカソンでも使いました。

https://protopedia.net/prototype/4716


# 既存のノードでサーボモーターを制御してみる
　Arduino IDEならServo.hなどのライブラリを使えば簡単にサーボモーターを制御できますが、Node-RED MCUには現状、サーボモーター用のノードがありません。
　サーボモーターを制御する方法を知る必要があります。以前、XIAO ESP32C3でServo.hが使えなかったので、パルスで制御したことがあります。
▼180°回転のサーボについてはこちら

https://404background.com/program/esp32c3-2/

▼連続回転サーボについてはこちら

https://404background.com/program/esp32c3-3/

　今回は**PWM outノード**で制御してみます。
　ここではSG90に準拠して、周期は20ms、パルス幅は500μs~2400μsとします。連続回転サーボの場合はパルス幅が異なります。
 
▼ピンのHIGHとLOWを制御するのですが、その時間間隔で角度を調整できます。
![角度.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/62d2de8f-fe25-d92f-5079-5147235d19dc.png)
 
　PWM outノードには0~1の値で、HIGHとLOWの割合を入力します。周波数を設定できるので、周期20msから換算して50Hzで設定しておきましょう。
▼PWM outノードの設定画面はこちら
![20231213_21h03m39s_grim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/33dfd3da-767e-23cd-d7c2-a9e69155fadb.png)

▼例えば0°の場合はパルス幅が0.5msであり、一周期のうちの割合でいうと0.025になります。これをPWM outノードに送ります。
![角度 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/548de1ef-ce74-32c5-0e2a-c0a25463e91b.png)


▼実行するフローはこちら。msg.payloadに0°、90°、180°の場合の値が順番に代入されます。
![20231212_22h36m57s_grim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/14aeb830-dbb8-5628-03f6-f5b41bed08e7.png)


▼実際にSG90を動かしたときの様子。
<iframe width="560" height="315" src="https://www.youtube.com/embed/BhvjqbTuwLU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>


▼パルス幅を700~2300に変更して、連続回転サーボのSG90-HVも動かしてみました。回転速度や向きを制御できます。
<iframe width="560" height="315" src="https://www.youtube.com/embed/XB4vE0FRNw0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>

# サーボモーター用のノードを作成する
　既存のノードでサーボモーターを制御できたので、自作ノードにまとめていきましょう。
　PWM outノードのようにピンからの出力ができるようにすることも考えたのですが、[node-red-mcuリポジトリ](https://github.com/phoddie/node-red-mcu)の構造を理解する必要があって大変です。ここでは簡単に、受け取った角度から計算して、PWM outノードに数値を渡すようにします。
 
▼以下のようなフローで使えるようにします。
![角度 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/b50fd0b8-bed7-09a0-f205-3aed5567beb6.png)

:::note info
ノードの作成については、Node-RED User Group Japanの「ノードの開発」に関するページが非常に参考になります。
https://nodered.jp/docs/creating-nodes/
:::
　Node-REDには多種多様なノードがありますが、**見方を変えるとサンプルが大量にあるということでもあります。** 参考になりそうなものは積極的に取り入れていきます。

　主に以下の4つのファイルを用意します。
* .htmlファイル：Node-REDでのノードの表示を設定する
* .jsファイル：ノード内の処理を記述する
* package.json：.jsファイルがどこにあるのかを示す
* manifest.json：ビルド時、ノードを含めるために必要

　manifest.jsonはNode-RED用のノードを作成する場合とは異なりますね。**credentialsの扱いも異なるのでご注意ください。** LINE Notify用のノードを作成したときに直面しました。
 
:::note warn
　通常のノードでは、パスワードなどの資格情報は**credentials**として扱われます。これはフローを書き出す際に含まれないので、フローを安全に共有することができます。

　その影響で、Node-RED MCUでビルドするときも含まれません。マイコンに資格情報を保存したいときは、credentials以外のプロパティとして扱う必要があります。
 　フローを第三者と共有する場合などにおける、資格情報の扱いには十分に気を付けてください。
:::
　node-red-mcuリポジトリには、ノードを作成する際のサンプルとして**lower-caseノード** が用意されています。各ファイルの記述やmsg.payloadの扱いについては、こちらが最小限の構成で分かりやすいです。

https://github.com/phoddie/node-red-mcu/tree/main/examples/lower-case

　さて、サーボモーターによってパルスの幅が異なるので、**パルス幅の最大値と最小値、周期**を入力できるようにしておけば汎用性があるでしょう。0~180°ではなく、0~270°の場合もあるので、**角度の最大値と最小値**も入力できるようにします。また、初心者でも使いやすいようにデフォルト値はSG90に合わせておきます。

　最大値と最小値の入力といえば、dashboardノードのsliderにちょうど良さそうな入力項目があります。今回はこれを取り入れます。

https://github.com/node-red/node-red-dashboard/blob/master/nodes/ui_slider.html

▼sliderの設定画面はこちら
![20231212_22h08m07s_grim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/d5328546-6844-6a1d-c9ce-29c3dce57686.png)

　Rangeノードも参考になりそうですね。こちらでは数値型への変更をしています。

https://github.com/node-red/node-red/blob/master/packages/node_modules/%40node-red/nodes/core/function/16-range.html

　主にプログラムを書くのはhtmlファイルとJavaScriptファイルです。ノードの開発に関するページを読みつつ、ソースコードと実際のノードを観察しつつ、ノードをインストールしてデバッグを繰り返すと形になっていくかと思います。

 https://nodered.jp/docs/creating-nodes/node-js


 https://nodered.jp/docs/creating-nodes/node-html


# 自作ノードをインストールする

　node-red-mcuリポジトリ内にて、lower-caseで検索すると**node_types.jsonにlower-caseノードのパスが指定されていることが分かります。** 自作ノードでも同様に、パスの追加を忘れないようにしましょう。

https://github.com/phoddie/node-red-mcu/blob/main/node_types.json

　私の場合はWindowsのVSCodeで開発してGitHub DesktopからCommit & Pushし、Raspberry Pi環境のDesktopフォルダにCloneしています。インストールするときにファイルのパスが必要なので、分かりやすい場所に置いておきましょう。

　ノードをインストールするには、LX Terminalを開いて以下のコマンドを実行します。
```
cd .node-red
npm install ファイルのパス
```

　Node-REDを再起動するには以下のコマンドを用います。
```
sudo systemctl restart nodered.service
```


　Node-REDをサービスとして起動しているので、プロンプトから実行する場合とは違い、LX TerminalにNode-REDの起動状態やエラーなどが表示されません。この場合、以下のコマンドでサービスの状態を確認することができます。
```
sudo journalctl -f -u nodered
```
　自作ノードがNode-REDに反映されていない場合は、エラーが出ていないか確認しましょう。

　今回私が作成したノードは、GitHubに公開しています。

https://github.com/404background/node-red-mcu-servo/tree/main

▼実際にServoノードをインストールして、フローを作成しました。
![20231213_21h03m27s_grim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/7912aac9-3775-8df8-f139-180c5cb6c140.png)

▼ノードの設定画面はこちら。初期値が既に設定されているので、ノードを繋ぐだけで使うことができます。
![20231213_21h03m33s_grim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616003/ac55d8b6-e90a-3dfb-3af6-93f357650f35.png)


▼実際の動作はこちら。Moddable Twoに表示されたsliderを動かすと、サーボモーターも回転します。
<iframe width="560" height="315" src="https://www.youtube.com/embed/tQKZNu7PTCM" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>


# 最後に
　ノードの作成について述べてきましたが、いかがでしたでしょうか。
 
　ノードを使うだけならまだしも、作成するのは難しそうだと感じている方もいるかもしれませんがご安心ください。私もNode-RED初心者であって、完全には理解できていません。
 
　私はそもそも機械系の学生であって、プログラミングに関してはほぼ独学です。JavaScriptとHTMLに触ったのは最近のことで、バッククオーテーションを使うことにビックリしていたほどです。それでも既存のノードを参考にしつつ形にすることができました。
　これからノードを作成してみたい！という方の参考になれば幸いです。
　
 　今回はPWM outノードに接続して使うようにしていますが、Servoノードだけで使えるようにしたいなと考えています。GPIO関連のファイルを参照するので、別のパッケージとして作るよりnode-red-mcuリポジトリにプルリクエストを出すべきじゃないかなと思いつつ。勉強します…