UfoSaCtrlTrip Ver1.0

UfoSaCtrlTripとは U.F.O SA , A10サイクロンSA , バッハスマート , ROCKET+1D の4機種を対象に最大3台を同時に接続でき、独自のランダムパターンおよび任意の固定パターンで制御できるAndroid野良アプリです。
制御方式をグレードアップし、より多彩なランダム動作を実現。
また、最大で3台の同時接続を可能としたことで、従来のUfoSaCtrlProおよびUfoSaCtrlDualの両方を完全内包した最新上位アプリとなります。

とりあえず筆者の使用範疇では特に問題が無いので、この版をそのままVer1.0正式版とします。

制御方式のグレードアップにより、設定値の書き方を変更しましたので、申し訳ありませんが従来の任意パターン設定をそのまま今回のUfoSaCtrlTripにコピーすることはできません。

また、かなり多くの仕様をいっぺんに盛り込んだため、バグが取り切れていない可能性がございます。
ただ、詳細なテストにもかなりの時間が掛かってしまうため、粗方ちゃんと動いていそうな気配(気配レベルですみません)がしているバージョンを一旦ベータバージョンとして公開させていただきたいと思います。

新制御方式でさらにバリエーション豊かなパターンが作り出せるようになりましたので、まずはその動きを皆さんにもご体感いただけたら、と思っております。

説明が不十分なところを後日補足、改定するかもしれません。(デモ動画も撮りたいし)

撮りました。3台同時ランダム制御デモ動画
ここをクリックorタップするとYoutubeに遷移します。

Android4.3以上でBLE(Bluetooth Low Energy)に対応している端末が必要になります。(近年の機種であればほぼ大丈夫)
ですが、画面オフ時のメディアボタン(イヤホンのリモコン操作や物理キーボードのメディアコントロールキー押下)による操作はAndroid5.0以上に限られます。
その他、古いバージョンでは通知のアイコンが異なっていたり、一部フォントが表示されない可能性があります。(コントロールそのものには支障はありません。)
また、野良アプリであるため、自力でAPKファイルをインストールできる作業能力が必要です。
2019-12-17追記:
カスタムROM(RevengeOS 3.0)ではありますがAndroid10での動作確認を軽く行いまして、基本動作は大丈夫そうでした。

使用機種や環境によって接続や制御の安定性は大きく変わります。なるべく良い環境を作ってください。(詳しくは後述します。)


このアプリでコントロールできる製品はこれらにものになります。

インストール

インストール時にはAndroidOSのバージョンにもよりますが、このアプリが使用する権限を許可していただく必要があります。

UfoSaCtrlTrip-003.png

具体的には
・BLUETOOTH……Bluetooth通信を行うために使用
・BLUETOOTH_ADMIN……接続しようとしたときにBluetoothがオフだった場合にオンにするために使用
・ACCESS_FINE_LOCATION……グッズを見つけ出すときに必要とされる権限(このアプリでは当然、位置情報など全く使用しないのですが、AndroidXでBluetooth機器探索時の必須権限とされてしまいましたので仕方なく要求するようにしています。)
・WAKE_LOCK……画面をオフにしてもグッズの制御を続けられるようにするために使用
・FOREGROUND_SERVICE……画面をオフにしたときにOS側に勝手にアプリを落とされないようにするために使用(但し、細かい話ですがTargetAPIを22としている都合上、完璧では無い可能性があります。(これもう22に拘る必要無いかもなぁ))

以上の権限をこのアプリでは許諾していただく必要があります。
くどいようですが、対象となるグッズを探索し、接続し、制御する。そのために必要となる機能のみを実装しており、必要となる権限のみを要求しています。

画面例

Screenshot_20191206-190957_Dev.pngUfoSaCtrlTrip-001.png

使用方法

画面の上から順に見て行きましょう。

UfoSaCtrlTrip-004.png

左上にUの字の中に点があるような形のアイコンが表示されます。(UfoSaCtrlの頭文字と乳首をイメージした造形です。)
これがUfoSaCtrlTripが起動している通知です。
このアプリでは画面をオフにしてもグッズの制御を続行するためにフォアグラウンドサービスを起動しています。
逆に言うと、終了させるときはしっかりと終了させないといつまでもサービスが残ってバッテリーを消耗させてしまうことになります。
アプリの終了はこの下のGとIが組み合わさったアイコンの辺りをタップするか、もしくはバックボタン(最近では物理ボタンが無いことの方が多いですかね。画面下に出せる◁(三角)マークのボタンです)をタップして、左上のサービス通知アイコンが消えていることを確認してください。

Androidバージョンが古いと左上のアイコンは

UfoSaCtrlTrip-005.png

筆者のサークルアイコン(GとIを組み合わせた形)になっているかもしれません。

右側の︙(縦3点)でメニューが開けるのですが、細かい話になるので後回しにします。


UfoSaCtrlTrip-006.png

1)〜3)まで3台分の接続とパターン選択を行える領域があります。
上の行が接続状態。この画面では「(none)」となっていて、機器未接続であること表しています。
そして、その右には「Connect」ボタンがあり、これをタップするとグッズとの接続を試行し始めます。

このとき、Bluetoothがオンになっていなかったりすると、

UfoSaCtrlTrip-007.png

こんな感じのダイアログが出てきますので、「許可」してあげてください。

Bluetoothがオンになっていると、

UfoSaCtrlTrip-008.png

こんな感じで「探索中」の状態になります。
このとき、探索を中断したい場合は「Cancel」ボタンをタップしてください。

※機器の接続をするときは一つ一つ丁寧に、やや時間間隔を空けながら行うことをオススメします。
 無線通信のやり取りの不安定さやラグの問題でごく稀にグッズ側が接続している状態になっても、アプリ側がその接続情報を認識できないケースが発生するためです。
 より詳細な話は後述しますので、細かい話でも良ければ後述の記事をご参照ください。
UfoSaCtrlTrip-009.png

アプリの方で接続を認識できると、接続できたグッズの名称が表示されます。
「UFOSA」
「CycSA」
「Bach smart」
「ROCKET」

接続を解除したいときは「DisConn」ボタンをタップしてください。

※いくら待っても接続できない場合

Android端末によっては位置情報(GPS)をオンにしないとBluetooth機器の接続をさせてくれないことがあります。
これは機種やOSによりけりですので、アプリ側では勝手にオンにする機能を設けておりません。
各自設定等で位置情報をオンにして様子を見てください。(高精度である必要はありません。端末のみでもOK)
接続が出来てしまえば、その後の通信制御そのものは位置情報がオフでもやってくれますので、即オフにしちゃって大丈夫。
位置情報オンが必要になるのは接続時のみです。


下行の「Ptn」はPatternの略でして、ここで動作パターンの選択を行えます。1)〜3)まで接続した機器ごとに同じパターンを選択できますし、違うパターンを選択することも可能です。

UfoSaCtrlTrip-010.png

初期状態ではこんな感じで3パターン用意されています。
先頭の「Random」がUfoSaCtrlTrip独自のランダム制御パターンで、2行目以降は固定パターンです。

設定の変更によりこの固定パターンも自在に変更が可能。
固定パターンは任意でいくつでも設定することが可能です。(ただし、現状では設定値の容量制限を64KBとしていますのでその範囲内で、ということになります。足りない場合は言っていただければ拡張したバージョンを配布致します。)
設定の変更については大変細かい話になるので後述します。

3台分の接続情報の下には暗い青の帯がありまして、

UfoSaCtrlTrip-011.png

「Rel」というのはRelationの略です。
ここの値は、同じ種類のグッズを2台以上接続した場合にのみ機能します。(例えばU.F.O. SAを片乳ずつ2台接続した場合など)
・Random……無関係に動いたり、同期して動いたり、反転して動いたり
・Unrelated……無関係に動きます
・Mirror……反転して動きます
・Sync……同期して動きます
・Flip……同期して動いたり、反転して動いたり

接続した機器の数字の小さい方が基準となります。
例えば、1)と2)が同じグッズだった場合、2)の動きが1)の動きに対して「Rel」で設定した関係に従って動作するようになります。
同じように2)と3)が同じグッズだった場合は2)が基準となります。
1)2)3)全てが同じ種類のグッズだった場合は2)は1)を基準として、3)は2)を基準として動作します。ので、Mirror動作はこの場合2)だけが反転することになります。

※バッハスマートとROCKET+1dでは反転の概念がありませんので、反転を選択しても同期と同じことになります。
※どちらも同じ固定パターンを選択している場合は無関係を選択しても同じ動きになります。(パターンが同じなので)


今回、UfoSaCtrlTripではボリュームを「0(OFF), 1, 2, 3」の3段階に固定させていただきました。
ここからは各ボリュームでの設定となります。

UfoSaCtrlTrip-012.pngUfoSaCtrlTrip-013.png

左列縦に並んだ「0, 1, 2, 3」がボリュームで、現在指定しているボリュームのところに下部青線が光ります。
そして、「1, 2, 3」のボリュームの右側にはトグルスイッチが2つ並んでいます。

真ん中列の◢(右肩上がりの三角形)は回転(振動)状態を変化させるときに徐々に変化させることを表しており、当アプリではこれを「Gradual制御」と呼んでおります。
これを各ボリュームごとにオンにしたりオフにしたりすることができます。

Gradual制御はUfoSaCtrlシリーズが最初から搭載していた機能なのですが、従来はこの変化させる速度が固定であったのに対し、今回のUfoSaCtrlTripではその変化速度もバリエーションをもたせることが可能となりました!(設定によります)

じりじりと変化する制御が不要な場合はオフにしてください。
また、Gradual制御はBluetooth通信が頻繁に発生しますので、通信環境があまり良くないので頻繁に通信されても取りこぼしが多発するなどといった場合や、バッテリーの消耗を少しでも抑えたい場合、イクときだからじれったい動きすんな、などオフにすると良いかもしれません。

右列の◧(黒白縦線)は回転(振動)を小刻みにオンオフ切り替えるもので、当アプリではこれを「PWM制御」と呼んでおります。
PWM制御の機能は今回が初搭載です。
強めの回転(振動)とPWM制御を組み合わせることで、「おっおっおっ(^ω^)」的な刺激を受けることが可能になります。
不要な場合はオフにしてください。
このPWM制御もどの程度の頻度でオンオフを繰り返させるかを設定で変更することが可能です。

上記のGradual制御とPWM制御は同時には発生しません。
Gradual制御は回転(振動)状態を変化させるとき、PWM制御は一定の回転(振動)状態になったときに発動する制御です。

デモ動画を撮影しました。
ここをクリックorタップするとYoutubeに遷移します。

Gradual制御の変化速度バリエーション増加とPWM制御の新設により、UfoSaCtrlのランダム制御がよりバリエーションに富んだ、ほったらかしで任せられる制御になったのではないかと思っております。

なお、Androidの古いバージョンでは◧(黒白縦線)のフォントが表示できないかもしれません。

UfoSaCtrlTrip-014.png

ごめんちゃい。


画面最下段は

UfoSaCtrlTrip-015.png

左がボリューム0、停止状態にします。

真ん中は
・Always……常にボリュームの値を反映して、画面の状態に関わらず動作します。
・LCD……ボリュームが1〜3の状態にあっても、画面がオフになるまでは動き出しません。画面オフのときだけ動かしたい用。
の切り替えです。

右はロックボタン。
UnLock状態では画面上の全てのUIが弄れるようになっていますが、Lockに切り替えると、0〜3のボリュームボタンとこのLockボタンのみがタップ可能で他の部分は反応しなくなります。
設定を一通り終えてボリュームだけを変更したい状況にあるときにご使用ください。
なお、Lockされるのは画面上のUIだけですので、Android端末本体の電源ボタンやボリュームボタン、Bluetoothやイヤホンで接続したメディアボタン(音楽再生関連のリモコンボタン。キーボードからも操作できる場合があります。)による操作は常に受け付けます。

メディアボタン対応

イヤホン端子に付けられる、もしくは、Bluetooth接続によるリモコンやキーボードのファンクションキーのところにあるキーでUfoSaCtrlTripのコントロールをすることができます。
この機能はAndroid5.0以上のみの対応となります。
4.4や4.3でも画面オンの状態でならある程度は受け付けられると思いますが、画面オフにすると効かなくなってしまいます。

リモコン操作のイメージが湧かない方は『リモコン操作デモ For UfoSaCtrlPro』の記事にデモ動画と説明を記載しておりますのでそちらも合わせてご覧ください。

このリモコンキーでどのようにUfoSaCtrlTripをコントロールするか、その設定を変更することができます。

UfoSaCtrlTrip-016.png

画面右上のメニューボタンをタップして、「Switches」を選択します。
すると、

UfoSaCtrlTrip-017.png

このような設定画面が現れます。
「ボリュームボタン」と「送り戻しボタン」(次の曲、前の曲)のボタンの動きをそれぞれ、
・ON/OFF切替……それまで選択していたボリューム(1〜3)と停止状態(0)とを切り替えます。ボリューム上下、送り戻しどちらもボタンを押しても同じ動きをします。
・Volume調整……ボリュームを上下させます。サイクリックにしていますので3からさらに上げようとすると0に、0からさらに下げるようにすると3になります。
・Ptn変更……接続機器1)〜3)の全て選択パターンを一つずらします。ボリューム上下、送り戻しの押すボタンによってズレる方向は変わります。サイクリックですので、端っこのパターンまで来たらまた反対側の端っこのパターンへとズレていきます。
・Rel変更……選択Relationを一つずらします。ボリューム上下、送り戻しの押すボタンによってズレる方向は変わります。サイクリックですので、端っこの選択肢まで来たらまた反対側の端っこの選択肢へとズレていきます。
・Gradual/PWM切替……ボリューム下げや戻しボタンの場合はGradual◢を、ボリューム上げや送りボタンの場合はPWM◧をボリューム1〜3まで全て一斉に切り替えます。

音楽再生ボタンや一時停止ボタンは常に「ON/OFF切替」として機能します。

100均で良く見かけるリモコンシャッターはボリューム上げキーに相当することが多いです。
ハンズフリーリモコン付きマイクのボタンはヘッドセットフックに相当することが多いようです。UfoSaCtrlシリーズでは音楽再生/一時停止ボタンと同じように働きます。
当然のことながら、アナログのボリューム調節には反応しませんのでご注意ください。
また、Android端末本体に付いているボリュームボタンとリモコン等のボリュームボタンは同一視されます。分けて判定できるとより便利になるのですが、今のところ分けることができません。(というかそもそも同じキーコードなので分けるのは不可能かと)

Bluetooth機器との接続と通信のお話

ここまでの説明だけでも一応はUfoSaCtrlTripを使えるかと思います。
ここから先は細かい話になります。
ただ、UfoSaCtrlTripをより使いこなすために有益な情報がありますので、できればお読みいただきたく思います。

Bluetoothは2.4GHz帯を使用する無線通信規格です。
2.4GHz帯といえば、家電製品(電子レンジなど)が使っていたり、Wi-Fiで使われていたりと、かなり利用されている周波数帯です。
その中でBluetoothは特別に微弱な電力で通信を行いますので、他の電波にかき消されたりしやすいです。(その代わりバッテリーの消費が少なく済みます。近距離個人使用向けなんですね。)
それだけでなく、Android端末の出来の良さやバッテリー残量、グッズ側の角度(アンテナ指向性やグッズ本体の電波遮蔽具合)によっても通信の安定性は変わってきます。
Androidとグッズの間に人体が挟まるだけで通信安定性はガクッと落ちます。(この辺りはどこかの過去記事でも何回か触れています。)

ですので、なるべく通信環境を良い状態に保つことがUfoSaCtrlTripを快適に使うコツとなります。


グッズを接続するときに、タイミングによってはグッズ側が接続状態になっているのにアプリ側が接続状態にならないことがあります。
これはアプリとOSとのやり取り、OSとグッズとの無線通信のやり取りの都合上発生するラグとタイミングとの兼ね合いで起こってしまいます。

Bluetooth機器を探索して接続するという作業では、単なる通信よりもバッテリー消費が著しいこともありますし、セキュリティ的にもよろしいことではないので、「Connect」ボタンをタップしてから接続できるまでの間だけ探索するようにしています。
ですが、例えば、「Cancel」ボタンをタップして探索を中断しようとしたタイミングで接続が出来てしまったりすると、アプリ側は「もう良いよ」と言ったけど同時期にOS側では「繋がったよ」となって、しかし、アプリ側は「もう良いよ」と窓口を閉じてしまっているので通知が来ない。という状況になるのです。
ですので、この辺、「Connect」「Cancel」「DisConn」ボタンをガチャガチャタップしまくってるとOSまで接続したけどアプリに接続情報が通知されないという宙ぶらりんに陥りやすいです。

宙ぶらりんになってしまったグッズを再探索する仕組みは(筆者の探し方が悪いだけかもしれませんが)現状無く、再探索してもOS側としては既に接続済みとなっているグッズを改めて接続できたとアプリに教えてくれることはありません。
そうなってしまった場合は、一旦、Bluetoothそのものをオフにしてオンにし直すか、UfoSaCtrlTripアプリを一旦終了させて、グッズの方の接続状態が切れていることを確認してから接続を再試行してください。


また、OS側の仕組みが良く分からないのですが、ゴミキャッシュ等の影響か接続が異様にしにくくなったり、2台接続したのに、1台しか制御できない(1台目と2台目の制御通信がなぜか1台に集中して行われるようになってしまう)という現象が稀に起こることがあります。

これらの不具合はキャッシュを消去することで改善できるかと思います。
操作の一例が『U.F.O. SA/A10サイクロンSA/バッハスマート コントロールアプリDual版Ver.1.10』の記事にあります。(機種により操作が異なる場合があります。)
キャッシュパーティションのクリアは他のアプリにも影響があるかもしれませんので、ご利用は慎重に。
また、システムやデータを消さないようご注意ください。

Bluetooth通信の根幹はAndroidOSの仕組みに頼っているため、AndroidOSの方が不具合を起こすとこのような対処をするしか無くなります。
AndroidOSも決して完全なものではありません(というかBluetooth周りは特に酷評されてます)のでゴミキャッシュが溜まって悪さをすることが多いです。
通信状態が良ければゴミも溜まりにくい気がしますけど。


Androidのバージョンは新しい方が良く、特に5.1辺りまではOS側の実装でバグや迷走が続いていたためできれば5.1以上が望ましいかもしれません。
が、実機テストをしてみると必ずしも新しい端末なら良いとも限らない、というのが実情のようです。

サクサク繋がる機体もあれば、通信がやたらと失敗する機体も。バージョンが古くても良く動いてくれる場合もありますし、これもう分かんねえな(^^ゞ

2019-12-17追記:

仕様が公表されていることが少ないので難しいですが、電波出力の強い端末を使うことで単純に通信安定性が良くなったりします。
例えばFire7Tabletで1.9dBm、FireHD10Tabletでは7.5dBm。当然HD10の方が繋がりが良いです。(BLEとBluetoothで出力が異なる場合もありますので注意。ちなみにHD10はスペック上同じ強度ですが、7の方はBT3.0だと9.0dBmの強度があるそうです。)
ちなみに、Wi-Fiの出力は15〜17dBmとなっていますので、Wi-Fiとぶつかるだけでも当然負けます。

環境に気を遣ってもどうしても通信が不安定(グッズの動作が不自然に長時間一定だったりすると、通信失敗している可能性があります)な場合は、そもそもの通信頻度を落としてあげることで通信失敗の確率を下げられるかもしれません。
Gradual制御とPWM制御はランダムパターンのバリエーションを豊かにしてくれる機能ですが、その分、通信は頻繁に行われることになります。
場合によってはこれらをオフにした方が、グッズのランダム動作が安定するかもしれません。
また、後述する設定の変更によっても多少改善できるかもしれません。

画面をオフると制御が止まってしまう場合

最近のAndroid端末ではバッテリーの持ちを重視して(というかあまりに適当かつ大胆にバックで動きまくる悪徳アプリ(SNSアプリとか通販アプリとか)が氾濫しているせいだと思いますが)画面をオフにしたときに積極的にアプリを停止させてこようとします。
UfoSaCtrlでは「画面をオフにしたまま長時間グッズの動作制御ができる」という点が大いなる売りポイントですので、画面をオフにしたらグッズが止まる(というかアプリが強制的にKillされている)なんて状況は避けたいわけです。

そのため、当アプリではForeground ServiceというOSや他のアプリから勝手にKillされにくい仕組みを導入している(つもり)です。
が、それでも画面オフでアプリをKillされてしまう場合は、各自でOSや他のタスクキルアプリ等の設定を見直していただく必要があります。
UfoSaCtrlTripが勝手に終了されないように端末の設定をお願いいたします。
(逆に終わらせるときはちゃんと通知アイコンが消えるように終わらせてくださいね。でないとバッテリーを無駄に消耗します。)

一例(あくまでも例。OSやメーカーの調整、アプリの導入などによって環境が違い過ぎるので)として、こちら『U.F.O. SA/A10サイクロンSA/バッハスマート コントロールアプリ ご注意』『U.F.O. SA/A10サイクロンSAコントロールアプリPro版Ver.1.10』の記事もご参照してみてください。

設定の変更

皆大好き設定変更!
皆さんそれぞれに好みが異なりますし、グッズの種類やヘタれ具合なんかによっても、より好みに合う設定は変わってくるものだと思います。
標準の設定ではちょっとなあ……と思ったら、思い切って設定変更にチャレンジしてみましょう!

メニュー(画面右上の︙縦三点)から「Settings」をタップしましょう。
画面いっぱいに文字がうわぁ〜〜〜と表示されます。
設定値は全てテキストです。
ですので、書き順とかが重要になります。
設定画面にもメニューがありまして、

UfoSaCtrlTrip-018.png

RecoveryBasicDataはUfoSaCtrlTripに標準で添付されてくる基本データに戻します。
Save#1〜#3の3箇所にセーブできて、Load#1〜#3でそれぞれ呼び出せます。
ただし、このセーブはアプリ内でのセーブですので、アプリをアンインストールしたり、アプリのデータを削除などすると消えてしまいます。
大事なデータは各自でテキストエディタなどに切り貼りして保存することをオススメします。
(アプリにその機能を持たせるのはやたらと権限や機能が必要となるし、その割にあまり意味が無いので実装していません。全選択コピーして他のエディタに貼り付けるだけで任意の場所に保存できますのでそれでお願いいたします。)

それでは、設定データを見てみましょう!


[U.F.O. SA Start,Stop,Displacement Threshold: int(0~100): 3要素必須 Gradual動作開始時,減速時,似たようなPowerを続けないための最低変化量]
12,5,5
[U.F.O. SA Vol.1 PowerPattern: int(0, StartThreshold~100): 要素数は自由(ランダムに選ばれる)]
0,12,12,17,17,22,25
[U.F.O. SA Vol.2 PowerPattern: int(0, StartThreshold~~100): 要素数はVol.1と合わせる(ランダムに選ばれる)]
0,12,17,17,22,27,35
[U.F.O. SA Vol.3 PowerPattern: int(0, StartThreshold~~100): 要素数はVol.1と合わせる(ランダムに選ばれる)]
32,32,37,37,42,42,50
[U.F.O. SA TimePattern: int(1~): 要素数は自由(ランダムに選ばれる) 単位100msec]
10,16,22,28,34,40,46,52
[U.F.O. SA TimeIndexLimit: int(1~): 要素数はPowerPatternと合わせる 各数値はTimePattern要素数以内とする]
5,8,6,8,8,6,4
[U.F.O. SA GradualPattern: int(0,1〜){/int(1〜)}: 要素数は自由。Power変化値/時間(単位100msec)の分数型で記載。時間が1のときは分子のみ記載可能。約分せず。0はGradualさせない(確率を変えるために複数使用)。]
0,0,0,0,1,3/2,2,3,1/2,3/4,1/3,2/3
[U.F.O. SA PWMPattern: int(0,2〜){/int(2〜)/int(0〜)}: 要素数は自由。On時間(単位100msec)/Off時間(単位100msec)/OnのときPowerを何%に増(減)速するか。約分せず。0はPWMさせない(確率を変えるために複数使用)]
0,0,0,0,0,2/2/175,4/2/150,2/4/200,4/4/125,4/8/175
[■■■■■]
[A10CycloneSA Start,Stop,Displacement Threshold: int(0~100)]
35,25,5
[A10CycloneSA Vol.1 PowerPattern: int(0~100)]
0,40,45,50,55,60,65
[A10CycloneSA Vol.2 PowerPattern: int(0~100)]
0,40,48,56,64,72,80
[A10CycloneSA Vol.3 PowerPattern: int(0~100)]
50,58,66,74,82,90,100
[A10CycloneSA TimePattern: int(1~)]
10,16,22,28,34,40,46,52
[A10CycloneSA TimeIndexLimit: int(1~)]
5,8,8,8,8,6,4
[A10CycloneSA GradualPattern: int(0,1〜){/int(1〜)}]
0,0,0,0,1,3/2,2,3,1/2,3/4,1/3,2/3
[A10CycloneSA PWMPattern: int(0,2〜){/int(2〜)/int(0〜)}]
0,0,0,0,0,2/2/175,4/2/150,2/4/200,4/4/125,4/8/175
[■■■■■]
[Bach Smart Start,Stop,Displacement Threshold]
20,15,5
[Bach Smart Vol.1 PowerPattern]
0,20,25,30,35,40,45
[Bach Smart Vol.2 PowerPattern]
0,20,28,36,44,52,60
[Bach Smart Vol.3 PowerPattern]
50,58,66,74,82,90,100
[Bach Smart TimePattern]
10,16,22,28,34,40,46,52
[Bach Smart TimeIndexLimit]
5,8,8,8,8,6,4
[Bach Smart GradualPattern]
0,0,0,0,1,3/2,2,3,1/2,3/4,1/3,2/3
[Bach Smart PWMPattern]
0,0,0,0,0,2/2/175,4/2/150,2/4/200,4/4/125,4/8/175
[■■■■■]
[ROCKET+1D Start,Stop,Displacement Threshold]
20,15,5
[ROCKET+1D Vol.1 PowerPattern]
0,20,25,30,35,40,45
[ROCKET+1D Vol.2 PowerPattern]
0,20,28,36,44,52,60
[ROCKET+1D Vol.3 PowerPattern]
50,58,66,74,82,90,100
[ROCKET+1D TimePattern]
10,16,22,28,34,40,46,52
[ROCKET+1D TimeIndexLimit]
5,8,8,8,8,6,4
[ROCKET+1D GradualPattern]
0,0,0,0,1,3/2,2,3,1/2,3/4,1/3,2/3
[ROCKET+1D PWMPattern]
0,0,0,0,0,2/2/175,4/2/150,2/4/200,4/4/125,4/8/175
[■■■■■]
[MinimumInterval: int(1〜): 最小通信時間間隔。通信取りこぼしが発生する場合は数値を大きめに取ってみてください。 単位100msec]
2
[RelationChangePhases: int(1~): 2要素必須 min,max: 2機目のRel設定でRandomを選択している際に、Sync,Mirror,Unrelatedを切り替えるまでにいくつのパターンを消化するか、の最小値最大値を指定]
3,7
[SwitchHeightWeight:int or float(0~): Volume等下部ボタンの画面高さを指定します]
1.25
[Custom1 Vol.1: 先頭行にこのパターンに付ける名称を、2行目以降にパターンをPower,Time,Gradual,PWMで記述。行数自由。カスタムデータではPWMのPower増減割合設定はありません、直にPowerの値を変えてください。ここからはコメント行がデータの区切りとして扱われます。1パターンにつき3ボリューム分のデータが必要です。]
Demo
42,30,0,0
0,10,0,0
42,10,1,0
0,10,0,0
42,10,3/2,0
0,10,0,0
42,10,2,0
0,10,0,0
42,10,8/3,0
0,10,0,0
42,10,5,0
0,10,0,0
42,10,3/4,0
0,10,0,0
42,10,1/2,0
0,10,0,0
42,10,1/5,0
0,10,0,0
[Custom1 Vol.2]
42,30,0,0
0,10,0,0
42,32,0,2/2
0,10,0,0
42,32,0,6/2
0,10,0,0
42,32,0,2/6
0,10,0,0
[Custom1 Vol.3]
42,32,2,4/4
-42,32,1/2,2/6
-12,6,5,0
-24,50,1/3,8/2
[Custom2 Vol.1]
Dummy
0,50,0,0
[Custom2 Vol.2]
0,50,0,0
[Custom2 Vol.3]
0,50,0,0
[DataEnd]

うっわあ〜何この量! げんなりっ。
でもこれ、実は繰り返しばっかりで、意味合い的にはUfoSaCtrlProやUfoSaCtrlDualのときよりも設定項目そのものは減っている(はず)です。
量は増えてるけど楽になってるはず。

上から大まかに

U.F.O. SAが接続されたときのランダム制御設定
[■■■■■]
A10CycloneSAが接続されたときのランダム制御設定
[■■■■■]
Bach Smartが接続されたときのランダム制御設定
[■■■■■]
ROCKET+1Dが接続されたときのランダム制御設定
[■■■■■]
その他の設定
任意の固定パターン設定

というブロックに分けることができます。
今回、ランダム制御は接続されたグッズごとに設定値を分けることにしました。
グッズによってスイートスポットとなる値がかなり違うというのが主な理由です。
一方、固定パターンの方ではグッズによる分けはありません。
グッズによる分けが必要な場合は普通に別パターンとして設定してもらえば良いという考えです。
ただし、ボリュームを3段階固定としたことで、どのパターンでも必ず3ボリューム分の設定を書いてもらう必要があります。
(手間だが、その分、単純に比例で強くするだけでなくボリュームによってドラスティックに制御を変えることが可能となります。)


ランダム制御のパラメタ。
書き順は変更しないでください。
行の先頭に"["を書いた場合はコメント行とみなします。何行書いても構いません。空白行を入れても大丈夫だったはず。
それ以外の場合はばっちりデータ行とみなされます。
今回、データ行に使用するのは0〜9の数字、"-"マイナス、"."カンマ、"/"スラッシュ。あと一部"."小数点のみです。"sg"の英文字は不要になりました。(あ、後で出てくる任意固定パターンのパターン名のところだけは英字でもなんでもありです。)

U.F.O. SA の設定値を例に上から順に解説していきます。
Start,Stop,Displacement Threshold: int(0~100): 3要素必須 Gradual動作開始時,減速時,似たようなPowerを続けないための最低変化量
12,5,5

グッズのモーターに与える力は0(停止)〜100(最大)となっており、U.F.O. SAとA10サイクロンSAは逆回転もあるので、それはマイナスで表しています。
ランダム制御の設定値ではマイナスの値は使用しません。逆回転はプログラムの方でランダムに付与します。

最初の数字はGradual制御で停止状態から動き始めるときに、真っ正直に1から増やし始めると最初のうちはモーターが唸るだけでグッズが動いてくれません。なので、ここにある数値までは一気に飛ばしますよ、という値です。
次の数字は逆にGradual制御で徐々に弱くしていくときにどこまで粘るかという数値。動いている状態から弱くしていく分には多少小さな値でも動き続けることができるので、最初の設定とは分けています。ここのある数値まで減らしてから停止状態になるという感じです。
最後の数字は次のパターンに移行するときに似たような強さが連続しないように、少なくともここの値の分の差が無いパターンは選択しないというしきい値です。
それぞれ、0〜100の整数値、カンマ区切りで記述してください。

U.F.O. SA Vol.1 PowerPattern: int(0, StartThreshold~100): 要素数は自由(ランダムに選ばれる)
0,12,12,17,17,22,25

今までSpeedと表現してきたものを今回Powerに改めさせていただいております。
ぶっちゃけ値大きくしてもそれに比例して速度が速くなるわけではないので、ちょっと違和感を覚えてしまいまして。
すみませんが、今回からPowerということでお願いします。

ボリュームを1にしたときにここに書いた値の中からランダムに選択されるPower値を列記します。
0は停止状態、自然数で100までです。負の値は不要です。
従来はここに書いた値にボリューム値を乗じてさらにオフセット値を追加していたのですが、今回はここの値を正負反転させる以外は全くいじらずにそのまま送信します。

同じ値を複数書くことも可能ですし、数値の大小も別に綺麗に並べる必要はありません。
同じ値を複数書く意味は「当選確率」を上げるというところにあります。
ここに書かれた値からランダムに選ばれますので、同じ値を複数書いているものの方が当然選択される確率が上がります。
ただし、その上の行で書いたDisplacement Thresholdの値の制限により、似たような値が連続して選択されることは防がれますので、単純にここに書いた数に応じて確率が上がるものとは限りません。
停止させたくなければ0は書かなくても大丈夫です。実際Vol.3のデータには0を書いていません。
ここの値はボリューム1,2,3の順番で3行記述する必要があります。
数値をいくつ書いても良いのですが、ボリューム1,2,3で同じ数分だけ書くように揃える必要があります。

U.F.O. SA TimePattern: int(1~): 要素数は自由(ランダムに選ばれる) 単位100msec
10,16,22,28,34,40,46,52

PowerPatternで採用された値を何秒間維持するかです。こちらもランダムで選択されます。(こちらは同じ値が連続して選択される場合もあります。)
10で1秒です。カンマ区切りでいくつ書いても構いません。同じ値を書いて確率を上げることも可能です。
この秒数を経過すると次のPower値およびTime値の選択をし直して、次の状態へと移行していきます。
なお、この値はGradual制御には無関係です。

U.F.O. SA TimeIndexLimit: int(1~): 要素数はPowerPatternと合わせる 各数値はTimePattern要素数以内とする
5,8,6,8,8,6,4

TimePatternで書いた数値はいつでも全て選択されて欲しい数値とは限りません。例えば、停止状態はそんなに長くしたくないとか、強いのが長く続くのは辛いからヤダとか、あると思います。
そこで、ここに書く値は選択されるTimePatternの範囲を制限します。
カンマ区切りでPowerPattern書いた個数と同じだけ値を書く必要があります。
書ける値は1〜TimePatternに書いた個数までです。
この例ですと、Power0のときのTimeIndexLimitが5となってTimePatternに書かれている「10,16,22,28,34,40,46,52」のうちの先頭の5つ「10,16,22,28,34」からのみ時間が選ばれる、ということになります。
次のPower12はTimeIndexLimit8なので全ての選択肢の中から時間が選ばれる、ということです。
最後のPower25はTimeIndexLimit4なので先頭の4つ「10,16,22,28」から時間が選ばれます。

U.F.O. SA GradualPattern: int(0,1〜){/int(1〜)}: 要素数は自由。Power変化値/時間(単位100msec)の分数型で記載。時間が1のときは分子のみ記載可能。約分せず。0はGradualさせない(確率を変えるために複数使用)。
0,0,0,0,1,3/2,2,3,1/2,3/4,1/3,2/3

Gradual制御とは現在のPowerの状態から次のPowerの状態へと移行するときに、いきなり次のPowerにせずに徐々に次のPowerの値へと近づけていくようにする制御のことを指しています。
Gradual制御をオンにしているときは、ここに書かれている設定からGradual制御パターンを選択して実行します。
「0」はGradualさせない、ということでオンにしているからと言って全ての回転(振動)変化がじんわり行われるとは限りません。
もちろん「0」を書かないというやり方もありです。一方、「0」しか書いていないとオンにしてもGradual制御は一切されません。

ここでは「0」を4つ、「0」以外を8つ書いていますのでGradual制御になる確率は2/3です。もちろん変更できます。
整数値で書く場合は100msec単位ごとにPowerの値を書いた値の分だけ変化させます。
「1」が従来から使用されている100msecごとに1変化というパターンです。
2,3と上げていくごとに単位時間当たりの変化量が大きくなるのでより素早くPowerが変更されることになります。
停止や反転に至るときは設定の最初で書いたStop Thresholdの値まで減ったところで停止になります。
また反転や停止状態からの動き出しはまずStart Thresholdの値まで一気に上昇してからここの変化量の値に従って強くしていきます。

分数を書くことでより細かい指定が可能です。
分子が変化量、分母が単位時間(100msec)という形でき記述してください。
例えば「3/2」というのは200msec当たり3変化させます。
約分はしません。
ですので「6/4」と書くと400msec当たりで6変化させますが、200msec時間経過したときにはまだ変化させませんので、変化の仕方が大雑把になります。

※ここで1点注意があります。
UfoSaCtrlは純正のアプリにならって100msec単位で制御を行いますが、実際にはAndroid端末から100msec単位で連続送信を行うと高い確率で制御不能状態に陥ることが実機テストにより明らかになっています。
この現象を筆者は以前、グッズ側の限界と断定していましたが、Android端末側の限界である可能性も多々あります。
必ずしも処理性能の不足とは限らず、動くものは古くて遅い端末でも結構ちゃんと動きます。
ですが、端末の出来や通信状態によってこの辺りの安定性は大きく変わってしまいます。
そこでUfoSaCtrlTripでは100msec単位で設定を書くけれども実際の送信は最低でも200msecの間隔を空けるようにプログラムで制御しています。(この間隔は後で出てくる設定値の変更で変えることが出来ます。)
つまり、「1」と書いていても、実際には200msec単位で2ずつ変化していくことになります。分母の最低値が2にされるイメージです。

U.F.O. SA PWMPattern: int(0,2〜){/int(2〜)/int(0〜)}: 要素数は自由。On時間(単位100msec)/Off時間(単位100msec)/OnのときPowerを何%に増(減)速するか。約分せず。0はPWMさせない(確率を変えるために複数使用)
0,0,0,0,0,2/2/175,4/2/150,2/4/200,4/4/125,4/8/175

PWM制御は、Gradual制御をしていないときには即時に、Gradual制御をしているときは規定のPowerに到達したときに、短い間隔で小刻みにオンオフを繰り返して動きに変化を与える制御のことを指しています。
PWM制御をオンにしているときは、ここに書かれている設定からPWM制御パターンを選択して実行します。
「0」はPWMさせない、ということでオンにしているからと言って全ての回転(振動)が小刻みにオンオフされるわけではありません。
もちろん「0」を書かないというやり方もありです。一方、「0」しか書いていないとオンにしてもPWM制御は一切されません。

ここでは「0」を5つ、「0」以外も5つ書いていますのでPWM制御になる確率は1/2です。もちろん変更できます。
「0」以外を書く場合はここでは3つのパラメタを"/"半角スラッシュで区切って書く必要があります。
1つ目、2つ目はそれぞれオンにする時間とオフにする時間で100msec単位。
「2/2」というのは200msec単位でオンオフを繰り返すことを表しています。
前者の数字が大きいとオンになっている時間比率が高まり、後者の数字が大きいとオンになっている時間比率が下がります。

ただオンオフするだけだと、ずっとオンになっている状態に比べて弱くなってしまいます。
そこでPowerをより強く補正できるようにしています。
それが"/"半角スラッシュで区切って書く3つめの数値です。パーセントで自然数で書いてください。100で元のPowerといっしょです。
「2/2/175」ですと200msec単位でオンオフを繰り返すので動きは半減してしまいますが、Powerを175%に強めることで動いているときはより強く動くようになり、全体平均で見るとずっとオンで動いているときと近い感じで動くようなります。
(理論上は2/2/200が完全一致なのですが、Powerの値を2倍したら本当にパワーが2倍になるのかといったら……状況によりけり(摩擦等の兼ね合いで2倍を超えることもあります)なのでこの辺りはお好みで変更してください。)

ただし、この3つ目のパラメタはランダム制御の設定値にしか書きません。
後で出てくる固定パターンの方では書きません(書いても無視されます)。
その理由は、固定パターンだったらその行にPowerの値を書くんだから、上乗せしたかったらPowerの値そのものを大きくすれば良いだけ、だからです。

ここまでがランダム制御の設定値の説明でした。
これを各グッズごとに4ブロック書く必要がありますが、実際に使用しているグッズのところだけ弄っていただければ良い、ということになります。


次にその他の設定のブロックです。

MinimumInterval: int(1〜): 最小通信時間間隔。通信取りこぼしが発生する場合は数値を大きめに取ってみてください。 単位100msec
2

UfoSaCtrlTripでは比較的確実に通信を行える時間間隔として200msecを採用しています。
グッズに対して連続してPowerを変化させる通信を行うときでも毎回最低200msecの時間を空けることで通信エラーの発生率を低く抑えようとしています。
非常に良い通信環境を保持できている場合はこれを100msecに変更しても上手く制御できるかもしれません。
その場合はここの値を1にしてみてください。
(うちでは無理でした。)
逆にちょくちょく一定速度の状態が長時間続いたりして(通信エラーが起こるとPowerの変更がされないので同じ状態が続くことになります)、通信環境が悪いと思われる場合はここの値を3なり4なりに変更して通信時間間隔を広げることで制御がマシになる可能性があります。

ただし、ここで注意点があります。
グッズへの通信は例えて言うとサンプリング的な感じで通信されます。(厳密には違う部分があります。)
例えばここの値を3にしたとして、
Gradual制御で「3/2」が選択されたとします。
200msecの時点で3変化させるところですが、最低間隔が3なので通信は延期されて300msecの時点で3変化と送信されます。
400msecの時点で合計6変化させるところですが、次の送信は600msecの時点になります。そのときは既に合計9変化させるべきタイミングですので、6変化ではなく9変化として送信されます。つまり、スムーズな変化ではなくガチャガチャになることがあります。
また、PWM制御で「2/2/175」が選択されたとします。
時間0でオンになって、本来なら200msecの時点でオフにするところですが、最低間隔が3なので通信は延期されて300msecの時点でオフが送信されます。次は400msecの時点でオンにしたいところですが、最低間隔の都合上次の通信は600msecの時点で、ここでオンになります。PWM制御の方では必ずオンオフを繰り返すようにはしていますが、借金が膨らむみたいにずっと遅れが膨らんでいく形になり、実質「3/3/175」と指定されているのと同じ動きになります。

RelationChangePhases: int(1~): 2要素必須 min,max: 2機目のRel設定でRandomを選択している際に、Sync,Mirror,Unrelatedを切り替えるまでにいくつのパターンを消化するか、の最小値最大値を指定
3,7

同じ種類のグッズを2台以上接続し、かつ、そのRelを「Random」「Flip」にしているときにのみ使われる設定値です。
「Random」では「Sync」「Mirror」「Unrelated」の3つの状態を
「Flip」では「Sync」「Mirror」2つの状態を切り替えていくわけですが、
毎回変えているようだと、あっ今同期してる、とか、あっ今反転してる、とか全く分からずに「Unrelated」との区別が非常につけづらくなってしまいます。
そこである程度同じRelを続けるようにしていまして、いくつパターンを消費したら他のRelに移行するか、という値の最低値と最大値をここに記述しています。
初期設定では最低3パターン消化したら次のRelへ。最大でも同じRelは7パターンまでしか続かないようにしています。

SwitchHeightWeight:int or float(0~): Volume等下部ボタンの画面高さを指定します
1.25

これはボリューム0〜3までのボタンの高さを表す値です。ここの値だけは小数値を使います。
初期値では1.25でして、これは画面上半分のボタンより上の領域の高さが1行あたり1なのに対して、ボタンの行は1.25倍の高さで表示するということをあらわしています。
ボタンを大きく表示させたい場合はここの値を増やしてください。
ただし、大きくしすぎると他の部分が見切れるなど画面が崩壊するかもしれませんのでご注意ください。


最後のブロックは任意固定パターンの設定です。
ここから先は記述する行数が可変となるため、コメント行(ぎょうの先頭に"["大括弧を書いてある行)を各パターン設定の区切りとしています。
ですのでコメント行を自由に増やすことはできません。
また、一つのパターンを定義するのに1,2,3の3つボリューム分定義を書く必要があります。
使わないボリュームについては内容は適当でも構いませんが、3ボリューム分必ず定義してください。

先にも書いたとおり、任意パターンでは接続したグッズによる区別は付けません。
接続するグッズによりパターンを変えたい場合は、その分別パターンとして定義して、それぞれ接続した1)〜3)のパターン設定でそのグッズに合ったパターンを選択するようにしてください。

[Custom1 Vol.1: 先頭行にこのパターンに付ける名称を、2行目以降にパターンをPower,Time,Gradual,PWMで記述。行数自由。カスタムデータではPWMのPower増減割合設定はありません、直にPowerの値を変えてください。ここからはコメント行がデータの区切りとして扱われます。1パターンにつき3ボリューム分のデータが必要です。
Demo
0,10,0,0
42,10,3/2,0

パターン定義のボリューム1の先頭行にはパターン名を書いてください。ボリューム2,3のところでは不要(逆にあったらエラー)です。
ここでは「Demo」という名前にしています。これが画面上のパターン選択の選択肢に現れる文字列です。

[Custom1 Vol.2]
42,32,0,2/2
0,10,0,0
[Custom1 Vol.3]
42,32,2,4/4
-42,32,1/2,2/6

内容を適当に抜粋してます。データの区切りとなるコメント行は先頭が"["大括弧であることだけがチェックポイントですので、それ以降の文字列は自由です。
ただし、データの順番は必ずボリューム1,2,3の順に、コメント行区切りで3パターン定義してください。
それぞれパターンの最後まで行くとまた先頭からパターンを繰り返すようになっています。

行数は自由です。いくらでも複雑なパターンにしてください。
各行は必ず、カンマ区切りで4つのデータが必要です。
Power , Time , Gradual , PWM

Powerは-100〜0〜100の整数値です。固定パターンですのでプログラムの方で勝手に反転とかさせません。ですので、逆回転にさせたい場合は意図的にマイナス値を書く必要があります。(ただし、バッハスマートとROCKET+1Dの場合はマイナス値では反応しないのでプログラムの方で必ずプラス値に反転させます。結果として、-10の次に10とか書いていると全く変化しないということになります。)

TimeはそのPoweを維持している時間。100msec単位。10で1秒です。自然数で記述してください。

Gradualは上記のランダム制御での書き方と同じです。0でGradual制御せず、n/mの分数型で分母を省略して書くことも可能。約分はしませんが、最低通信間隔(MinimumInterval)の影響を受けます。

PWMも基本的に上記のランダム制御での書き方と同じなのですが、"/"半角スラッシュで区切って書く値は先頭の2つだけ、最後の3つ目のパラメタは書いても無視されます。PWM制御に応じてPowerを増強させたい場合は、Powerの値そのものを大きく記述してください。(固定パターンに倍率書く意味は無いんよ)

コメント行区切りで3ボリューム分を定義し、1ボリュームの先頭行にはパターン名を書く。
この決まりさえ守っていれば、固定パターンはメモリの許す限りいくつでも定義することができます。
ただし、現状では定義ファイル全体で64KBまでとしていますので、拡張が必要な場合はお手数ですが筆者までコメントをお寄せください。

今までのUfoSaCtrlProやUfroSaCtrlDualで使用してきた固定パターンをそのまま今回からのUfoSaCtrlTripに移植したい場合、各データ行を次のように変換してください。
・"s"を"0"に全て置換
・"g"を"1"に全て置換
・全てのデータ行の末尾に",0"を追加
これでほぼ同じ動きが再現できます。(厳密には最低通信間隔を確保する処理を変更しているので若干異なる部分が出るかもしれませんが、まず気付かない範囲だと思われます。)

但し、今回、パターン名を書く位置が変わっていたり、一つのパターンの定義に必ず3つのボリュームを書く必要が生じている点に注意して移植してください。

ダウンロードファイル

勝手な再配布はしないでください。
特に、うちのサイトは弱小なので、検索で上位に表示されるサイトに勝手にコピーされると、盗まれたのとほぼ同じ状況に陥ります。
何かしらの問題が発覚して、こちらのサイトでファイルを差し替えても、それが皆さんの元には反映されなくなることにも繋がります。

早速すみません。2019-12-11 14:45頃に差し替えをしております!
最後に修正した部分が、別のところに問題を起こしておりました。
具体的にはGradual制御中もTimer加算がされてしまうため、規定のPowerで動くべき時間が減ったり、Gradual制御中にタイムアップして次のパターンへと移行してしまう不具合が発生しておりました。
現在のファイルはその問題を修正したものになります。
それ以前にダウンロードされた方はお手数おかけして申し訳ありませんが、再ダウンロードをお願い致します。

諸事情によりアプリの無料配布を終了致しました。
今後は活動を支援してくださる方とのみ細細と共有していければと思います。

今後のUfoCtrlアプリ配布ページはこちらです。
UfoCtrl Ver1.00 (UfoCtrl開発活動支援プラン)

(βを取っただけで中身は変わっておりません)

ブログに無理矢理載せている都合上、ちょっと特殊なダウンロード形式にしているので、Androidの標準ブラウザではダウンロードに失敗するかもしれません。Chromeなら大丈夫みたい。ブラウザをある程度選んでしまうようです。ご了承ください。

アップデートインストール後に動作がおかしくなった場合は再起動してみてください。
それでもおかしい場合はキャッシュのクリアや一旦アンインストールしてからインストールし直してみてください。
その際、設定を書き換えている方はその設定が消えてしまいますので、操作をする前に設定の退避(テキストファイルなどに移して保存)をしてください。

この版はベータ版です正規版に昇格しました。
特に問題が無ければそのまま正規版に昇格しますが、どこか想定通りに動かない等問題がありましたらお手数お掛けしてすみませんがコメントをお寄せいただけると幸いです。

最後に

アダルドグッズや同人コンテンツなどをご購入の際にはこのサイトのリンクを踏んでから購入していただけると、いくばくかの紹介料をいただけるので筆者が大変助かります。(製品の種類は問いません。)
このアプリや筆者の作成コンテンツが役に立ったとか面白かったとか、ありましたら応援していただけると幸いです。

このアプリの対象となる製品はこちらです。

2019-12-11 2019-12-11

コメント

No title 太郎 [2020-05-21 23:18]

リンクからUFOSAを購入させていただきました。応援しています。

Re: No title 山牧田 湧進 [2020-05-21 23:35]

ありがとうございます!

お互いにUFOSAをバリバリ活用してチクチク楽しみましょう!

この記事のタグ

U.F.O.

SA

アプリ

制御

自作