DGCCtrlTester Ver0.10α DIYグッズコントローラー専用緻密なランダム制御動作を可視化するツール
え?UfoCtrlじゃなくて?ってか最近何か知らんけど『DGC』って付くの多くない?
DGCとは『DIYグッズコントローラー』つまり『DIY Goods Controller』の略称です。
汎用品の組み合わせで自作できるコントローラーで、有線の単純なモーターのみで動作するようなグッズであればそのモーターへの電力供給を制御することが出来ます。
そして、その制御のためのアプリとして今まではUfoCtrlを使用してきました。
今回UfoCtrlでは出来ない制御をするために新規にDGCCtrlなるものを開発しようとしています。その詳しい理由などについては前回記事『UfoCtrlでは出来ない緻密なランダム制御を実現するプロジェクト』をご参照ください。
今回公開しますのは、DGCCtrlでどのような指示値をAndroidアプリ側が出すのかを可視化出来るツールであるAndroid野良アプリ『DGCCtrlTester』になります。
DGCCtrlが即リリース出来ないのはまだDGC側のプログラムが全くの未着手だからです。
非常に多くの時間を要する巨大プロジェクトですので、簡単には成果物ができません。ですので、これは途中経過報告でもあります。
今回はAndroid側はこう動きたいと思っている、という現時点の説明をこの『DGCCtrlTester』アプリを通してさせていただきたいと思います。
Ver0.10αとありますようにプロトタイプもプロトタイプですし、今後の開発の中で変更なども発生するかと思いますので現時点のということでご了承ください。
緻密なランダム制御
DGCCtrlではとりあえずUfoCtrlにあったような任意の固定繰り返しパターンは搭載せずランダムコントロールのみに専念するつもりでいます。
DGCCtrlが実現出来てもUfoCtrlも使えるようにしておくつもりでいますので、固定繰り返しパターンで制御したい場合はUfoCtrlをご使用くださいということで。
なお、DGCCtrlとUfoCtrl両方からBLE通信で指示を出した場合は最後に通信を受けた方の指示に従うようにするつもりでいます。
DGCCtrlではランダム動作用のパラメタを一括でDGC側に送信する仕組みとします。
UfoCtrlではモーターの出力を変えたいときに都度のその出力指示をBLE送信しなければなりませんでしたが、DGCCtrlでは指示パラメタに変更が無い限りBLE通信を行う必要がありません。
DGCCtrlから出力するパラメタ指示値は以下になります。
・2つのモーターの動作状態(1ch:NA/Stop/Move, 2ch:NA/Stop/Sync/Mirror/Move)
・Pow(0-100)Min-Max
・Reverse(0-100)%
・Gradual(0-255)10ms
・PWMOn(1-255)10ms Min-Max
・PWMOff(0-255)10ms Min-Max
・PWMGradualRate(0-100)%
DGCは1台で2つのモーターを制御出来ますので1ch,2chと2つのモーター向けに指示を出す必要があります。
動作状態のNAとは今回の指示対象外(それまでの指示を継続)であることを表します。
2chの方にのみSync/Mirrorがありますが、これは1chの動きと同期を取る/反転動作するという意味です。
Stop/Moveは停止/動作ですね。この2つのモーターの動作状態を1Byteで送付します。
Pow はMin-Maxとありますように0〜100の値ですが最小値と最大値を各1Byte使用して送付します。
DGC側はこのPowの範囲内でランダムな値を選択して動くようにする予定です。
Reverse はモーターの回転方向を反転させる確率を単位%で0〜100の値で1Byteで送付します。正転だけさせたい場合は0、反転だけさせたい場合は100、50が確率均等ランダムになります。
Gradual UfoCtrlのときは勾配を指定していましたが、DGCCtrlではそのPowに到達するまでの時間を単位10msで0〜255の値で1Byteで送付します。つまり0〜2550msまでの値を取ることができます。0にすると即時でそのPowになるためGradual制御をオフに出来ます。
PWMOn こちらはUfoCtrlで言うところのPWM制御をする際のオンに相当する時間を10〜2550msでかつ最小値と最大値を各1Byte使用して送付します。DGC側はこのPWMOnの範囲内でランダムな時間を毎回選択してPWM制御中のオン時間を決定します。オンになる度にその時間を変動させられます。変動させたくない場合はMinとMaxの値を同じにすれば良いです。また、オンにする度にPowの値も上記で指示されたPowの範囲内からランダムで決定し直します。こちらは最小値であっても0にすることはできません。
PWMOff PWMOnと同じくオフに相当する時間を0〜2550msでかつ最小値と最大値を各1Byte使用して送付します。最小値と最大値をともに0に指定するとPWM制御そのものをしなくなります。(オンになりっぱなしになるので)
PWMGradualRate PWM制御中にオンにするときにいきなり決定したPowの値にせずに時間を掛けてPowの値に到達するような、いわゆるPWM制御中にもGradual動作をする確率を単位%で0〜100の値で1Byteで送付します。全て普通にPowの値で動作させたい場合は0にします。Gradual動作する場合はPWMOnの時間を使ってPowに到達します。つまり、普通のPWMOnが方形波みたいな出力だとするとPWMGradualはノコギリ波の(最初の盛り上がりのみ)ような出力になります。PWMオフのときにPWMGradualが適用された場合はPWMOffの時間を使ってPow0(停止)に到達します。
UfoCtrlのときと比べるとPWM制御が主役みたいな感じになっています。
例としてどんな動きになるのかグラフでも頑張って作ってみましょうか。

Powは毎回Min-Maxの範囲内で、最初にGradualで指定された時間を使って徐々にそのPowに近付いていき、Gradualの時間が経過(最初のPowの値に到達)したらPWM制御に移ります。
PWM制御ではまた毎回PowとReverseするかどうか、PWMOn,PWMOffの時間、PWMGradualの有無を決定し直して、そのときの決定値に従ってGradualしないなら即そのPowへGradualするならPWMOnの時間を使って徐々にPowへ到達し、PWMOnの時間が経過したらPWMOffの時間分停止するかもしくはGradualするならPWMOffの時間を使って徐々に停止します。
PWM制御はオンとオフを延々繰り返します。
この動きはAndroid側からBLE通信にて次のパラメタ指示値を出力するまで続きます。
ここで、「いや、いつもいつもこんなぐちゃぐちゃなランダムばかりだと逆につまらないんだけど?」と思われる方、ご安心ください。
Min-Maxと範囲で指定するパラメタはMinとMaxを同じ値にしてしまえば固定化出来ますし、Reverseは0なら正転のみ100なら逆回転のみに固定できます。Gradualを0にすればGradual制御を行わなく出来ますし、PWMOffのMin-Maxを0にすればPWM制御にオフになることが無い、つまり、ずっと回転しっぱなしに出来ます。
広くランダムに揺るがせたいなら値の幅の広く取り、動きを決め打ちさせたいなら範囲を無くせば良いだけの話です。
画面
DGCCtrlTesterアプリの画面を説明します。

あれ?いつも4つのデバイスが表示されるはずなのに2つ?って思われた方は筆者のアプリに超お詳しい方ですね。
初期状態を2つにしているだけで最大4つまで表示出来ます。メニューのSwitchでお好きな数だけ表示するようにしてください。


ただ、いつものことですが4つ表示させると画面がギチギチですので、

以下の説明は2つ表示の状態で進めさせていただきます。

スピナーのG0とか表示されているところはデバイスの種別を模擬したものとなっており、G0,G1,H0,H1の4種のデバイスを模擬出来ます。
このとき、G0とG1は同じデバイス種別でH0とH1も同じデバイス種別。ただしGとHは別種扱いです。
これはUfoCtrlにもあった機能なのですが、1つのデバイス内で1ch2ch(左右)の同期を取ったり取らなかったりする制御の他に同種のデバイス同士で同期を取ったり取らなかったりすることが出来ます。
G0,G1はお互いに同期を取ったり取らなかったりし、H0,H1も同様に同期を取ったり取らなかったりすることが出来ますがGとHが同期を取ることはありません。

その右のスピナーはランダムパターンの選択スピナーです。このパターンは設定で変更することが出来ます。(後述)

各デバイスの表示先頭には番号ボタンがあり、これをオンにしているときはデバイスが接続されている状態を模擬します。(青い下線が点灯します)
あ、そうだ序に、今回は画面下の方のVolumeの概念も取り敢えずは無くしておりまして(将来もし復活させたいと思ったときのことを考えて0,1という表示は残しています。)事実上オンかオフしかありません。ここまでランダムに出来るとVolumeの存在意義が非常に薄いと考えていますので。
ちなみにどうしてもVolumeが複数欲しい方は代替手段としてランダムパターンを別のパターンに切り替えてしまうという方法があります。UfoCtrlで実装していた自動Volume変更機能はありませんので手動による切り替えになってしまいますが、各Volume別に定義したいものを別パターンとして登録しておけば良いかと思います。

2つのデバイスを動作させている表示の例です。1つのデバイスで2つのモーターへの指示を出していますが、この例ではG0デバイスの2chには「S」という表示がされていて、これは1chと同期(SyncのS)させる指示を出していることを表します。反転同期の場合はM(MirrorのM)という表示になります。同期しない場合は1chの表示のように全てのパラメタの数値が表示されます。
G1デバイスの方は1ch2ch共に「-」と表示されていますが、これはG0デバイスと反転同期するように指示を出していることを表します。普通の同期なら「=」という表示に、同期しない場合はG0デバイスの1chの表示のように全てのパラメタの数値が表示されます。

数値の表示内容について説明します。
左上から「i」現在選択されているのがそのパターンの何番目のパラメタになるのかindex値を表示しています。パターンの定義方法については後述します。また同じデバイス内で1chにSync同期しているときは「S」と、Mirror同期しているときは「M」と、同じデバイス種別の別デバイスで上に表示したデバイスとSync同期しているときは「=」、Mirror同期しているときは「-」と表示します。
「Time」現在のパラメタを維持する時間です。単位はms。この時間が経過するとアプリは次のパラメタを選択し指示し直します。
「Pow_Min-Max」現在選択されているPowの値をMin-Maxという範囲値で表示します。MinMaxともに0〜100の値を取ります。
「Rvs」Reverse確率を表示します。単位は%。0〜100の値を取ります。
「Grd」Gradual制御を行う時間を表示します。単位はms。指示を出した最初はこのGradual制御を行う時間でして、この時間で指定のPowまで変化していきます。この時間が経過するとPWM制御に移ります。
「PWMOn_n-x」現在選択されているPWMOn時間をMin-Maxという範囲値で表示します。単位はmsです。
「PWMOff_n-x」現在選択されているPWMOff時間をMin-Maxという範囲値で表示します。単位はmsです。
「GR」PWMOnやOffの動きでGradual制御する確率の表示します。単位は%。0〜100の値を取ります。
上記のうちDGC(DIY Goods Controller)側に指示がされるのは「i」と「Time」の除いた項目となります。
制御の補足
デバイス間のSync動作やMirror動作というのは今回のDGCCtrlでは完璧なものではありません。
あくまでも、Syncなら同じ指示値をほぼ同時に出し、MirrorならReverseの確率を100-nとした指示値をほぼ同時に出すというだけです。
実際のところ、そんな中途半端なSync/Mirrorなんて要らんだろうと思って実装を止めようと思ったこともあったのですが(やたらと実装が難しくて開発のガンでもあったし)、上述したようにパラメタの範囲を狭めて固定化すると完全な同期も出来るので一応残した方が良いかという判断で今回は実装しています。
なぜデバイス間同期なんて考えているのかというと、ペニス用5ローターとかいう製品が存在していたり、筆者個人的にもまだ全く手付かずですが片乳2ローターの両乳4ローターという構成を考えたことがあって時折左右乳で同期したりした方が良いよなぁと思っていたりするからです。
ちなみにデバイス内の1ch2chの同期は同じマイクロコントローラ内で行われる処理になりますので、ほぼ完璧にSync/Mirrorに出来るはずです。
DGCにはTimeパラメタを送付しません。DGCは受け取った最後のパラメタに従って延々と動くように作るつもりです。
これが何を意味するかというと、例えば意図的にGradualの時間よりTimeの時間の方が短くなるようなパラメタにさせた場合、Gradual制御の途中でそのパラメタによる動作は打ち切られて次のパラメタ指示がされる……なんて動きもさせることが出来ます。
PWM制御もいつまで繰り返すのかというのはAndroid側が次の指示をいつ出すのかに掛かっていますので、よりランダムな制御が可能となっています。(当然PWM制御中のぶつ切りも毎回発生するわけですね)
例えばGradualでもPWMでもPowが徐々に変化している最中に次のパラメタ指示とかがされますと、その現在Powから次の指示Powに向かってGradual遷移したりしますので、かなりバリエーションに富んだランダムコントロールが出来るのではないかと思っています。
まあ、実際動作まで漕ぎ着けたところで「こんなはずでは……」ってなる可能性もあるっちゃあるんですけど……
パラメタの時間が2550msまでとなっているのは1Byteに収めるためです。
単位を10msとして1/10した値を詰め込んでデバイスに送信します。
2つのモーターの動作状態で1Byte、以降のパラメタで9Bytes。この9Bytesは1ch向けと2ch向けが同時に指示出しすることがありますから、最大で19Bytesが一回のBLE通信で送信されるデータ量になります。
この量であれば1回のやり取りで送り切ることが出来ますので通信安定性が維持出来ると考えています。(ちなみにUfoCtrlでは毎回3Bytes固定です)
設定
今まで筆者のアプリと同様にメニューのSettingsで設定値を編集することが出来ます。

Default値をここに記載しておきましょう。(ランダムパターン記載部は長いので1つのみ掲載します)
#Random(ConnectConfigを除き、設定数値記載行に書かれた「0123456789-/,」以外はコメントとみなす。複数行書けるPatternの終わり、RandomPattern全体の終わりには必ず必須コメント行(行頭##)が必要)
U.F.O. (Low)
#Weight=n(1-65535)/Time=m-n(1000-65535ms)/Pow=m-n(0-100)/ReverseRate=m-n(0-100%)/Gradual(Powへの到達時間)=m-n(0-2550ms)/PWMOn=m-n(10-2550ms)/PWMOff=m-n(0-2550ms)/PWMGradualRate=m-n(0-100%)
#実際のGradual,PWMOn,PWMOffは10ms刻みになります(データ通信量削減のため10で割った値を送信するため)
#省略したときの値Pow=0/ReverseRate=0/Gradual=0/PWMOn=2550/PWMOff=0/PWMGradualRate=0
4/1000-3500
3/1000-5000/3-13/50
3/1000-6000/3-13/50/800-2550
3/1000-5000/6-26/0-100/g/80-300/0-300/0-100
3/1000-6000/6-26/0-100/800-2550/80-300/0-300/0-100
3/1000-5000/12-52/0-100/g/40-90/0-110/0-40
3/1000-6000/12-52/0-100/800-2000/40-90/0-110/0-40
1/1000-3000/14-28/50
1/1000-5000/14-28/50/800-2550
1/1000-3000/14-80/0-100/g/80-300/0-300/0-100
1/1000-5000/14-80/0-100/800-2550/80-300/0-300/0-100
1/1000-3000/14-100/0-100/g/40-90/0-110/0-40
1/1000-5000/14-100/0-100/80-2000/40-90/0-110/0-40
##PatternEnd(1つのパターンの終わりを表す必須コメント行)
##RandomEnd(RandomPattern全体の終わりを示す必須コメント行)
#RelationChangePhases m-n: int(1〜255)Sync/Mirror/Unrelatedを切り替えるまでにいくつのパターンを消化するか、の最小値最大値を指定, Sync/Mirror/Unrelated Weight: int(0〜) 重み付け(確率)
2-5,3/3/8
#ConnectConfig: デバイス名パターン正規表現,制御書き込み対象Characteristicパターン正規表現,RelationChangePhases m-n, Sync/Mirror/Unrelated Weight
(?i)dgc.*,.*3333.*,2-5,3/3/8
(?i)dgc2.*,.*3333.*,2-5,3/3/8
##ConnectConfigEnd
記述のノリはUfoCtrlと同じです。
ランダムパターンのパラメタの記載は上述のパラメタに近いように見えますが、実は設定ではより広範囲な指定をしています。
この設定値の範囲からまずはAndroidアプリ側である程度パラメタ値を絞り込んで上述したようなパラメタを作り出しDGCに転送するのです。
ランダムパターンに記載する項目は以下のようになります。
・Weight=n(1-65535) このパターンが選択される確率を上げたい場合はここの重み付けの値を大きくします。
・Time=m-n(1000-65535ms) Andoidアプリ側でのみ使用するTimeの値を範囲指定します。毎回この範囲内でランダムに決定されます。
・Pow=m-n(0-100) ここの値はそのままDGCに転送されます。
・ReverseRate=m-n(0-100%) 回転方向を逆転させる確率も設定では範囲指定可能です。毎回この範囲内でランダムに決定してDGCへ転送します。
・Gradual(Powへの到達時間)=m-n(0-2550ms) この値も設定では範囲指定可能です。毎回この範囲内でランダムに決定してDGCへ転送します。
・PWMOn=m-n(10-2550ms) ここの値はそのままDGCに転送されます。PWMOnは0msを許さないため最小値は10msになります。
・PWMOff=m-n(0-2550ms) ここの値はそのままDGCに転送されます。PWMOffは0msも可能(オフにしない)です。
・PWMGradualRate=m-n(0-100%) PWM制御でGradual遷移させる確率も設定では範囲指定可能です。毎回この範囲内でランダムに決定してDGCへ転送します。
という具合に幾つかの項目ではDGCに指示するパラメタは固定値なのに設定では範囲指定出来るようになっていて、範囲指定した場合は毎回範囲内でランダムに値を決定するようにしています。
これにより一様にランダムで良いという場面ではパラメタの範囲を広く取って記述しておけば良く、記述する総量を減らすことが出来ます。
UfoCtrlの設定に慣れている方はご存知かと思いますが、各項目は省略することが可能です。
以降省略の場合は記述そのものをしなくて良いですし、途中の項目のみ省略の場合は「//」とスラッシュ区切りの中身を無しに出来ます。
また範囲指定の片側だけ省略することも出来ます。
省略したところにはデフォルト値が適用されます。
省略したときの値Pow=0/ReverseRate=0/Gradual=0/PWMOn=2550/PWMOff=0/PWMGradualRate=0です。
例えばPowのところで「-75」と書くと「0-75」とみなされます。(「75」だけだと「75-75」いわゆる固定とみなされますので注意。)
全体的にUfoCtrlを知ってくださっている前提での説明になってしまっているので、UfoCtrlに詳しくない方がこの記事を見ても「なんじゃこら分からん」としかならないと思いますが、これはまだプロトタイプですのでより詳細な説明は正式リリースが出来るようになったときにまた改めてということでご容赦ください。
まだまだ変更の可能性は山ほどありますのでね。
ダウンロードファイル
勝手な再配布はしないでください。
また、このファイルのみへの直接リンクを貼ることもご遠慮ください。
特に、うちのサイトは弱小なので、検索で上位に表示されるサイトに勝手にコピーされると、盗まれたのとほぼ同じ状況に陥ります。
何かしらの問題が発覚して、こちらのサイトでファイルを差し替えても、それが皆さんの元には反映されなくなることにも繋がります。
DGCCtrlTesterアプリ配布ページはこちらです。
DGCCtrlTester Ver0.10α(UfoCtrl開発活動支援プラン)