MENU

オリジナルライドウォッチをつくる 〜ZX(ゼクロス)ライドウォッチ〜

今回ご紹介するのは、自分にとって最後のオリジナルライドウォッチ『ZX(ゼクロス)ライドウォッチ』、またの名を『10号誕生!仮面ライダー全員集合!!ライドウォッチ』、あるいは『仮面ライダーSPIRITSライドウォッチ』です。

開発経緯

開発のきっかけは、『グランドジオウライドウォッチ』の変身音です。『クウガ』から『ビルド』までの名前を、歌に乗せて読み上げるやつですね。自分がこれを聞いたときに思ったのは、「昭和ライダーでも同じように、ライダーの名前を読み上げる歌があったな」ということでした。

その歌というのは、水木一郎さんの『九人ライダー永遠に』という歌で、この歌のサビの部分です。この歌が世に出たのは自分が生まれる前だったりするのですが、なぜ自分がこの歌のことを知っていたかというと、1984年に放送されたテレビ特番『10号誕生!仮面ライダー全員集合!!』内にて10人ライダーが集結するときにこの歌が流れていて、この番組の録画を兄が何度も何度も繰り返し見ていたからです。それで、自分の中にも記憶として残っていました。

さて、『グランドジオウライドウォッチ』の変身音を聞きながらそんなことを考えていたので、「こんな昭和の歌もあるよ」とネタ的にツイートしようかなと思ったときに「ちょっと待てよ」と。「そういう歌があるのなら、それを変身音にした昭和ライダーのライドウォッチを作れば良いのでは」と、そこで思い至りました。

そんなわけで、「『九人ライダー永遠に』を変身音にする」というところから開発がスタートしているため、この曲が劇中で使用され、また10号ライダーという一つの区切りである『ZX(ゼクロス)』をテーマにまとめ上げるのが一番収まりが良いだろうと考え、今回この形になりました。「どうせ昭和ライダーのウォッチを作るなら、BLACK (RX)、真、ZO、Jまで含めれば良いのに」と思われた方もいるかもしれませんが、彼ら「便宜上は昭和ライダーだが生まれは平成(BLACKはRXとして)」というライダーは、皆さまご存知の通り、劇場版『Over Quartzer』でフォローされましたので、言ってしまえば『ジオウ』という作品にとって「蛇足」ではあるのかもしれませんが、劇中で出ることもないであろう昭和10人ライダーのライドウォッチを作っておくことは補完的には意義のあることかなと思い、ZXをテーマに押し切ることにしました。この決断によって、設計においても色々うまくまとまる部分が出てきたのですが、それは追い追いご紹介します。

作品内容

この『ZXライドウォッチ』ですが、前述のテレビ特番『10号誕生!仮面ライダー全員集合!!』の内容を強く意識したものになっています。そのため、そちらを視聴頂いた後に改めてこのウォッチを見て頂くと、「ああ、なるほど」と思うところが出てくると思います。東映特撮ファンクラブに入会されている方は、そちらからご視聴頂くことが可能ですので、宜しければ是非。

まず、ウォッチ非展開時の外観です。この状態では、ただの『ZXライドウォッチ』としてしか機能しません。まだ『仮面ライダー』ではないのです。

電源スイッチは背面下部で、起動音は上記番組のオープニングと同じになっています。スイッチ部の緑色はZXのマフラーのイメージです。今回は珍しく、塗装が全体的にうまくいったと思います。

ウォッチを展開すると、発光と共に9人ライダーが出現し、『10号誕生!仮面ライダー全員集合!!ライドウォッチ』として機能するようになります。ZXが10人目の仮面ライダーとなった瞬間です。この状態でジクウドライバーにウォッチを装填すると、ドライバーの表示が『ZX』から『SHOWA』に切り替わります。

9人ライダーの発光については、「あの歌に合わせてライダーが順に光っていったらカッコ良いよな!」という思いから入れ込もうと思ったのですが、これが後で説明するタッチ召喚機能の実装を一段と難しくしてしまいました。詳細は後述します。

そして、ウォッチの展開によるドライバーの表示変更ですが、動画にあるようにジクウドライバーに挿した状態で展開しても、ドライバーの認識が変化するようになっています。これも、「一回ウォッチを外して展開して挿し直すより、ウォッチをつけたまま展開して変化した方が絶対カッコ良いしビックリするよな!」という思いから実装しました。発想が小学生です。

ちなみに、昭和10人ライダー状態になると、Rスロットに挿している『ジオウ』の認識も、『2018』から『1971』に変化します。これは、「せっかくだからジオウの表示も昭和っぽくした方が良いかな!せっかくドライバー側に表示が仕込まれてることだし!」ぐらいの気持ちで実装したもので、それ以上の深い意味はありません。

昭和10人ライダー状態で発動するアーマータイムの音声は、前述のとおり『九人ライダー永遠に』のサビを使用しています。ただ、『九人ライダー』の名の通りで、元々はスーパー1の劇場版のために作られた曲のため、ZXの読み上げ音声は入っていません。そのため、ZXだけは『10号誕生!仮面ライダー全員集合!!』の番組内でのZX自身の名乗りを合成しています。

昭和10人ライダー状態になると、さらにフィニッシュタイムが発動可能になります。このときのウォッチの音声は、ちょっと聞き取りにくいですが、「ライダーシンドローム!」になっています。これも、ZXライドウォッチを作るからには是非やっておきたいことでした。「ライダーシンドローム」については、2014年公開の映画『平成ライダー対昭和ライダー 仮面ライダー大戦 feat.スーパー戦隊』の最後でも昭和ライダー達が使用していたので、そちらでご存知の方もおられるかもしれません。

ちなみに、フィニッシュタイムの最後でZXだけ赤く発光しているのは、わかる人にはわかるかもしれませんが、「ZXは必殺のZXキックを放つときには体が赤く発光する」という設定に基づいています。トドメの一撃、というイメージですね。漫画『仮面ライダーSPIRITS』でもよく言及されていたと思います。

そして、タッチ操作による昭和ライダー達の召喚機能です。これについては、『ジオウ』本編でグランドジオウが平成ライダー達のレリーフをタッチして平成ライダーを召喚しているのを見て、それと同様の機能を玩具的に再現してみたくて入れ込んでみました。最初は召喚音声が鳴るだけでも良いかな、と思っていたのですが、「せっかくジクウドライバーに昭和ライダーの表示が仕込まれているんだから、これも一緒に表示させた方が絶対カッコ(以下略)」ということで、頑張って入れ込んでみました。

また、せっかくライダーごとのタッチ操作を組み込んだので、ジクウドライバーとの連動だけでなく単独でも遊べる機能として、各ライダーのテーマ曲を一曲、フルコーラスで再生できる機能も追加してみました。

ハードウェア解説

まず、「商品化されていないのに、この1号からZXまでのライドウォッチのシールはどこから出てきたのか?」について、最初にご説明しておきます。これらは全て、知り合いの方に新規に描き下ろして頂きました。先方のご希望により紹介は控えさせて頂きますが、この方のご協力なしには今回のZXライドウォッチは成立しませんでした。改めましてお礼申し上げます、ありがとうございました。

それでは、いつものように必要な具材を最初にザッと紹介してしまいます。ベースとなっているのは、今更ですが『DXグランドジオウライドウォッチ』です。

そして中の電子部品は、自分にとって定番の以下の具材です。

Arduino Pro miniは、今回はウォッチ側とジクウドライバー側で計2つ使用することになります。

フルカラーLEDのNeoPixelですが、いつも使用しているスイッチサイエンス取り扱いのものではなく、共立エレショップ取り扱いのものを使用しました。こちらの方がやや省スペースで配線可能なためです。今回はほぼ白色でしか発光させないため、別にフルカラーLEDである必要性はなかったのですが、やはり配線の扱いやすさのため、NeoPixelを使用しました。

今回独自の機能であるタッチ操作は、以下の5つの具材を使用して実現しています。

やり方は色々あると思うのですが、自分の場合は試行錯誤の末、こうなりました。詳細は後述します。

もう一つの機能であるジクウドライバーの表示切替ですが、これはウォッチとドライバー間の赤外線通信によって実現しており、そのため以下の具材を使用しています。詳しくは後述します。

後は、配線に必要なコードとかです。今回はウォッチの展開ギミックがあるので、できるだけ柔らかいコードを使用する必要があります。

 

それでは、実装上のポイントを簡単にご紹介していきます。まずはライダー召喚のためのタッチ機能の実装について。

タッチ機能についてはカイザフォンXのときに既に実装しており、メインとなるモジュールは同じものを使っています。今回厄介だったのは、各ライダーを発光させるために、透過性を持たせたままタッチできるようにする必要があった、というところです。カイザフォンXのときはその必要がなかったので、銅テープの上にラベルを貼り付ける形でタッチの電極を作れば良かったのですが、今回はそれだと光が通りません。

この部分は色々試行錯誤したのですが、最終的に静電容量フィルムと導電性の両面テープ、銅テープを組み合わせる方式で何とか形にできました。

まず、静電容量フィルムを使えば、透過性という点ではクリアできます。ただ、静電容量フィルムにはコードを半田付けすることができません。今回フィルムを貼り付ける部分はウォッチの展開ギミックの影響を最も強く受ける部分であり、コードの固定が弱くなってしまうと、ウォッチの展開を繰り返すとすぐに壊れてしまう可能性があります。

そこで、「コードを半田付けで固定するための銅テープと静電容量フィルムを導電性の両面テープで貼り付けて電荷の通り道を作る」という、かなり強引な手法でクリアしました。なお、静電容量フィルム自体に粘着性はないので、フィルムとラベルシールの間は普通の両面テープシートで接着させています。

もちろん、最後はグルーガンでガチガチに固めています。

ちなみに、この発光&タッチ機能は、対象を10人ライダーに絞ったことによって実現できた機能と言えます。というのも、本来『グランドジオウライドウォッチ』は4枚のプレートが展開することで、前面のジオウを含め計20人のライダーを扱うことができるのですが、今回10人に絞ることで、前面の2枚のプレートのみを展開すれば数とすれば間に合うことになり、後ろの2枚のプレートを土台としてLEDを固定することができました。昭和ライダー15人を扱っても、とても無茶をすればできたかもしれませんが、見栄えは決して良いものにはならなかったと思います。また、今回用いたタッチセンサが同時に扱えるタッチ数は12個までなので、もし昭和ライダー15人を扱うなら、もう一つタッチセンサを追加しなければならなくなり、そうなるとさすがに筐体に部品を押し込むのがかなり難しくなっていたと思います。

 

続いて、ジクウドライバーの表示変更の方法についてです。これは、ウォッチとジクウドライバーの間で赤外線通信を行うことによって実現しているのですが、このアイデア自体は私が考えたものではありません。Twitterで相互フォローさせて頂いているかっぱ次郎様が『オールインワンライドウォッチ』を作成する際に考案された方法であり、今回はその方式を自分なりにアレンジして使用させて頂きました。ここではハードウェアの解説に留め、詳しいことは次のソフトウェア解説で説明させて頂きます。

まずはジクウドライバー側ですが、回路としてはこんな感じになっています。

点線赤枠で囲んでいる部分が元々のジクウドライバーの配線で、それにArduinoからの配線を後付けするような形になっています。電源はジクウドライバー本体の電池からとっています。

配線はこんな感じで、ドライバー本体の基板とArduino基板はすべてピン/ソケットで接続するようにしています(Arduinoは電池ボックスの裏に貼り付けています)。Arduinoを配線している間は普通のジクウドライバーのようには動作しない(←ライドウォッチを挿しても認識しないし、回転をさせても認識しない)のですが、配線を全て取ってしまえば元のジクウドライバーとして遊べるようになるので、いつでも戻せるようにこうしています。
なお、ジクウドライバー本体の基板に半田付け・基板接続するときは、必ずドライバー側の電池は抜いておきましょう。念のため。

赤外線受信モジュールはここ、Lスロット側から顔を出すようになっています。幸いなことにクリアパーツなので、穴開けは不要です。

先ほど述べた通り、上図の配線をすると、通常のジクウドライバーとしては機能しなくなってしまい、R/Lスロットにウォッチを装填しても反応してくれません。しかし動画の中では、Rスロットに挿したジオウライドウォッチが反応しているように見えます。

実はこれはフェイクみたいなもので、Rスロットのこの部分にスイッチを追加しており、ここを通過するものは全て『ジオウ 2018』として認識されるようになっています。その代わり、Rスロット側も、ウォッチからの赤外線通信によって、後から認識を自由に変えることができるようになっています。

ライドウォッチの認識ピンによってジクウドライバー側の認識スイッチが押されてしまうとややこしいことになってしまうので、ジオウ・ZXライドウォッチ共に、認識ピンは全て削っています。

ジクウドライバーの回転認識スイッチも、同様の理由で取り外しています。ジクウドライバーの制御は全て、赤外線通信を通してソフト的に行います。

続いてZXライドウォッチ側ですが、回路図を載せるのを忘れていたので、ここで載せておきます。

配線自体は数が多くて大変ですが、やればどうにかできるレベルでした。意外なところで躓いたのが、赤外線LEDの位置です。

最初は「できるだけ赤外線受信モジュールに近い位置で光らせないとダメだろう」と思って、ライドウォッチの認識プレートの穴からちょっとだけ顔を出すぐらいの位置で固定してみたのですが、実際ジクウドライバーとの連携をテストしてみると、これが全然うまくいかず。逆にドライバーとウオッチの間の距離をある程度離してみるとうまく動いてくれたので、赤外線LEDはドライバーの赤外線受信モジュールからできるだけ距離を空けるよう、なるべくウォッチ本体の奥まった位置で固定することにしました。これで、ドライバーとの連携動作がうまく動いてくれるようになりました。

ソフトウェア解説

最後に、ソフトウェア解説です。

ベースは以前万丈ライドウォッチをご紹介する際に公開したコードの通りなのですが、今回ライダーの召喚用に新たな状態遷移を追加しています。簡単に表すと、こんな感じになります。

一応ライダータイムの遷移も残していますが、今回はこのときは音が鳴らないようにしています。

 

続いて赤外線通信によるジクウドライバーの表示変化の方法についてですが、まず前提として、ジクウドライバーをどうやってソフト的に制御できるようにするかを説明します。

上図はドライバーのRスロットを内側から見た図です。動画内でも同様の説明をしていますが、ジクウドライバーは結局のところ、赤枠部分の電位の変化(HIGH/LOW)でウォッチを認識し、黄枠部分の電位の変化で回転を認識しています。つまり、この部分の電位を物理スイッチの操作に依らず、マイコンで直接操作してやれば、ドライバーの基板にウォッチの認識とドライバーの回転を錯覚させることができるようになります。Lスロット側も同様です。

ジクウドライバーにおいては、何もスイッチが押されていない状態では電位はHIGHになります。これをArduino側でGNDに落としてやればLOWになります。

ドライバーの回転については単純にHIGH/LOWを繰り返すだけで認識されますが、ウォッチの認識はきちんと理屈を考える必要があります。

ウォッチを装填すると、ドライバー側の認識スイッチが連続でON/OFFされて、上図①〜⑦のような電位変化が連続で発生します。この順番を再現する形で電位変化を発生させれば、ウォッチを認識させることが可能になります。認識後に逆順で電位を変化させれば、ウォッチを外すことに相当します。各ウォッチごとに異なる電位変化を発生させる必要がありますが、これについてほ、クレーンの丈様が公開してくださっている識別パターン一覧を参考にしてプログラムを作成させて頂きました。ありがとうございました。

 

これでジクウドライバーの操作をソフト的に制御できることがわかったので、最後にウォッチとドライバーの間の赤外線通信の方法の説明です。

先にも述べましたとおり、この方法自体は私が考え出したものではなく、かっぱ次郎様が考案されたものです。その内容についてはこちらで公開してくださっていますが、今回はそちらをベースに少しアレンジさせて頂きました。具体的には、Lスロットの操作だけでなく、Rスロットとベルトの回転も操作できるように拡張しています。

この二つの操作を追加したのは、タッチ操作によるライダー召喚をスムーズに行うためです。まず、RスロットではなくLスロットに昭和ライダーを認識させてしまうと、召喚のたびにRスロット側の『ZI-O』が表示されてから各昭和ライダーの表示がなされる(あるいは、Rスロットをリセットしても表示までに時間がかかる)ことになり、ちょっと間延びしてしまう感じがししました。また、召喚のたびに毎回ベルトを回転させる動作も、あっても良いかもしれませんが、個人的にはちょっと億劫な感じがしましたので、これも省略できるようにしたいと思いました。

そんなわけで、ウォッチ側からは、「RとLのどちらのスロットを操作するか」「どのライドウォッチを認識させるか」「ウォッチの認識後にドライバーの回転を認識させるか」の3つの情報を赤外線に乗せて通信させることにしました。イメージとしては、こんな感じです。

3つの情報の前後に、送信開始認識用と送信終了認識用の情報を合わせて送信しています。この赤外線送受信プログラムについては、かっぱ次郎様の記事内でも紹介されていた以下の本の内容を参照して作成致しました。

ちょっと躓いたところとしては、赤外線LEDの点滅間隔の調整です。詳しくは上記の本を読んで頂きたいですが、赤外線信号で「1(HIGH)」を表したいときには、その期間ずっと赤外線LEDを点灯させておけばよいということはなく、対向の赤外線受信モジュールの中心周波数(キャリア周波数)に合わせて一定間隔の細かい点滅を繰り返すことで「1」を認識させる必要があります。その「細かい点滅」の調整係数が、使用するArduinoの動作周波数によって異なるということに気づくのが遅れて、ちょっとハマってしまいました。手持ちのArduinoの都合で、最初の検証では16MHzで動作するArduino UNO、本番では8MHzで動作するArduino Pro miniを使っていたので。具体的にどういう値を設定したかは、最後に掲載するソースコードをご参照ください。

それから、ライドウォッチの識別情報には1byteを割り当てているので、理屈では0〜255までの数字を扱うことができるはずなのですが、255を送ったときには何故か赤外線受信モジュールが反応してくれませんでした。そのため、「ウォッチの認識はさせずにドライバーの回転だけ認識させたい」というときには、ウォッチの識別情報は255ではなく121(←正規のライドウォッチの認識番号の上限+1)を送るようにしています。

だいぶ長くなってしまいましたが、解説は以上になります。お疲れ様でした。

まとめ

ということで、ZXライドウォッチのご紹介でした。前作のクウガライドウォッチから二ヶ月弱での制作になりましたが、これは会社の夏期休暇をうまく挟んで時間をとれたからで、通常なら三ヶ月かかってもおかしくないぐらい大変でした。その分やり遂げた時にはかなりの達成感がありましたが、正直、二度と作りたくないライドウォッチです。

余談ですが、今回ZXライドウォッチを作成するにあたり、「昭和ライダーのことをある程度ちゃんと知らなくちゃいけんよな」と思い、「仮面ライダーSPIRITS」の既刊(「新」含む) を全巻購入・読破し、また通勤のときにひたすら昭和ライダーの主題歌を聞き込んでいました。結果、これまで正直、昭和ライダーには特に強い思い入れがあるというわけでもなかったのですが、「やっぱり昭和もカッコ良いなあ」と思うに至りました。ライダーのカッコ良さは時代を超えて不変です。

『ジオウ』については元々がレジェンドライダーが題材ということで、「今回はレジェンド題材とかで特に自分が何か作るということはしなくて良いかなあ」と放映当初は思っていましたが、終わって見れば例年通り色々作ってしまいました。今回も一年間楽しませて頂き、制作スタッフの方々に改めて感謝申し上げます。ありがとうございました。

(↑これまで作ってきた『ジオウ』関連の作品達。ネオディエンドライドウォッチ#Rin_chのK様の元にあります)

今回のZXライドウォッチで、自分の『ジオウ』関連の作品作りは最後になります。自分としては結構やりきった感がありますので、心置きなく『ゼロワン』へと移行できそうです。具体的に何を作るかが決まっているわけではありませんが、今後も折を見て何か作っていきたいと思いますので、今後とも宜しくお願い致します。

 

 

ソースコード

最後に、参考としてソースコードの全文を掲載しておきます。まずはジクウドライバー側です。

[highlight_cpp]

#define R_SW_A_PIN 2
#define R_SW_B_PIN 3
#define R_SW_C_PIN 4
#define L_SW_A_PIN 5
#define L_SW_B_PIN 6
#define L_SW_C_PIN 7
#define ROLL_SW_PIN 8
#define POWER_LED_PIN 9
#define IR_RX_PIN 10
#define R_SLOT_SW_PIN 11

#define SW_TEST_PIN_1 11
#define SW_TEST_PIN_2 12
#define SW_TEST_PIN_3 13

#define SIDE_R 0
#define SIDE_L 1
#define ROLL_OFF 0
#define ROLL_ON 1

uint8_t r_slot_sw = HIGH;
uint8_t prev_r_slot_sw = HIGH;

////////// IR信号の受信 ////////////////////////////////////////////////////////////

#define IR_ON LOW
#define IR_OFF HIGH

#define LEN_IR_DATA 8

// 使用する赤外線受信モジュール(OSRB38C9AA)の中心周波数
// (キャリア周波数)が37.9kHzなので、それに応じて定数を定める
#define IR_LONG_DURATION_MICRO_SEC 600

////////// ジクウドライバーの制御 ////////////////////////////////////////////////////////////

#define NUM_INPUT_CODE 7
#define SET_INTERVAL_MS 20 // これより短くすると動作が安定しない

const uint8_t INIT_CODE = B11111100; // ドライバーの両側に何も挿さっていない状態を想定
const uint8_t R_DELIMITER_CODE = B00011100; // Rスロット側のピン認識区切り用コード
const uint8_t L_DELIMITER_CODE = B11100000; // Lスロット側のピン認識区切り用コード
const uint8_t R_MASK_CODE = B00011100; // Rスロット側の電位の状態を保持するためのコード
const uint8_t L_MASK_CODE = B11100000; // Lスロット側の電位の状態を保持するためのコード
const uint8_t END_CODE = B00000000; // 両スロット共通のコード送信完了用コード

const uint8_t RIDER_CODES[][3] PROGMEM = {
// ピンありを”0″、ピンなしを”1″として、スイッチCBAの順に01を並べる
{B110,B101,B100}, // No.001 ZI-O 2018
{B110,B101,B011}, // No.002 ZI-O 2019
{B110,B101,B101}, // No.003 ZI-O 2038
{B110,B101,B001}, // No.004 ZI-O 2058
{B110,B100,B101}, // No.005 ZI-O ****
{B110,B100,B011}, // No.006 ZI-O 2000
{B110,B100,B010}, // No.007 ZI-O 0000
{B110,B100,B001}, // No.008 ZI-O 1971
{B110,B011,B101}, // No.009 ZI-O 1989
{B110,B011,B100}, // No.010 RIDER NEXT
{B110,B011,B010}, // No.011 ZI-O ライダ
{B110,B011,B001}, // No.012 GEIZ 2068
{B110,B010,B101}, // No.013 GEIZ 2019
{B110,B010,B100}, // No.014 GEIZ 2038
{B110,B010,B011}, // No.015 GEIZ 2058
{B110,B010,B001}, // No.016 GEIZ ****
{B110,B001,B101}, // No.017 GEIZ 2000
{B110,B001,B100}, // No.018 GEIZ 1010
{B110,B001,B011}, // No.019 GEIZ 1971
{B110,B001,B010}, // No.020 GEIZ 1989
{B101,B110,B100}, // No.021 GEIZ 2020
{B101,B110,B011}, // No.022 GEIZ ライダ
{B101,B110,B010}, // No.023 TSUKUYOMI 2068
{B101,B110,B001}, // No.024 RIDER NEXT
{B101,B100,B110}, // No.025 RIDER ****
{B101,B100,B011}, // No.026 RIDER 2019
{B101,B100,B010}, // No.027 RIDER ライダ
{B101,B100,B001}, // No.028 RIDER 0000
{B101,B011,B110}, // No.029 NEXT 0000
{B101,B011,B100}, // No.030 FUTURE 0000
{B101,B011,B010}, // No.031 NEW 0000
{B101,B011,B001}, // No.032 KUUGA 2000
{B101,B010,B110}, // No.033 AGITO 2001
{B101,B010,B100}, // No.034 RYUKI 2002
{B101,B010,B011}, // No.035 FAIZ 2003
{B101,B010,B001}, // No.036 BLADE 2004
{B101,B001,B110}, // No.037 HIBIKI 2005
{B101,B001,B100}, // No.038 KABUTO 2006
{B101,B001,B011}, // No.039 DEN-O 2007
{B101,B001,B010}, // No.040 KIVA 2008
{B100,B110,B101}, // No.041 DECADE 2009
{B100,B110,B011}, // No.042 W 2009
{B100,B110,B010}, // No.043 OOO 2010
{B100,B110,B001}, // No.044 FOURZE 2011
{B100,B101,B110}, // No.045 WIZARD 2012
{B100,B101,B011}, // No.046 GAIM 2013
{B100,B101,B010}, // No.047 DRIVE 2014
{B100,B101,B001}, // No.048 GHOST 2015
{B100,B011,B110}, // No.049 EX-AID 2016
{B100,B011,B101}, // No.050 BUILD 2017
{B100,B011,B010}, // No.051 CROSS-Z 2017
{B100,B011,B001}, // No.052 GREASE 2017
{B100,B010,B110}, // No.053 ROGUE 2017
{B100,B010,B101}, // No.054 BRAVE 2016
{B100,B010,B011}, // No.055 SNIPE 2016
{B100,B010,B001}, // No.056 LAZER 2016
{B100,B001,B110}, // No.057 PARA-DX 2016
{B100,B001,B101}, // No.058 POPPY 2016
{B100,B001,B011}, // No.059 RIDER1 1971
{B100,B001,B010}, // No.060 RIDER2 1971
{B011,B110,B101}, // No.061 V3 1973
{B011,B110,B100}, // No.062 RIDERMAN 1973
{B011,B110,B010}, // No.063 X 1974
{B011,B110,B001}, // No.064 AMAZON 1974
{B011,B101,B110}, // No.065 STRONGER 1975
{B011,B101,B100}, // No.066 SKYRIDER 1979
{B011,B101,B010}, // No.067 SUPER-1 1980
{B011,B101,B001}, // No.068 ZX 1984
{B011,B100,B110}, // No.069 BLACK 1987
{B011,B100,B101}, // No.070 BLACK RX 1988
{B011,B100,B010}, // No.071 SHIN 1992
{B011,B100,B001}, // No.072 ZO 1993
{B011,B010,B110}, // No.073 J 1994
{B011,B010,B101}, // No.074 GENM 2016
{B011,B010,B100}, // No.075 CRONUS 2016
{B011,B010,B001}, // No.076 EVOL 2017
{B011,B001,B110}, // No.077 SHOCKER 1971
{B011,B001,B101}, // No.078 ALFA 2016
{B011,B001,B100}, // No.079 OMEGA 2016
{B011,B001,B010}, // No.080 NEO 2017
{B010,B110,B101}, // No.081 RIDE STRIKER
{B010,B110,B100}, // No.082 ALL RIDERS ライダ
{B010,B110,B011}, // No.083 SUPER SENTAI -SS-
{B010,B110,B001}, // No.084 HEISEI -HR-
{B010,B101,B110}, // No.085 SHOWA -SR-
{B010,B101,B100}, // No.086 KAMEN RIDER ライダ
{B010,B101,B011}, // No.087 EVIL EVIL
{B010,B101,B001}, // No.088 ANCIENT 0000
{B010,B100,B110}, // No.089 GAME GAME
{B010,B100,B101}, // No.090 FUTURE 0000
{B010,B100,B011}, // No.091 X MAS 1225
{B010,B100,B001}, // No.092 SPECIAL -SP-
{B010,B011,B110}, // No.093 RIDER 0000
{B010,B011,B101}, // No.094 ZI-O ライダ
{B010,B011,B100}, // No.095 SINGULAR 0000
{B010,B011,B001}, // No.096 NOTHING 0000
{B010,B001,B110}, // No.097 MILLENIUM 2000
{B010,B001,B101}, // No.098 MAX MAX
{B010,B001,B100}, // No.099 DIEND 2009
{B010,B001,B011}, // No.100 GENIUS FIN
{B001,B110,B101}, // No.101 MUTEKI FIN
{B001,B110,B100}, // No.102 MUGEN FIN
{B001,B110,B011}, // No.103 TRIDRON FIN
{B001,B110,B010}, // No.104 KIWAMI FIN
{B001,B101,B110}, // No.105 INFINITY FIN
{B001,B101,B100}, // No.106 COSMIC FIN
{B001,B101,B011}, // No.107 PTOTYRA FIN
{B001,B101,B010}, // No.108 XTREME FIN
{B001,B100,B110}, // No.109 COMPLETE FIN
{B001,B100,B101}, // No.110 EMPEROR FIN
{B001,B100,B011}, // No.111 LINER FIN
{B001,B100,B010}, // No.112 HYPER FIN
{B001,B011,B110}, // No.113 ARMED FIN
{B001,B011,B101}, // No.114 KING FIN
{B001,B011,B100}, // No.115 BLASTER FIN
{B001,B011,B010}, // No.116 SURVIVE FIN
{B001,B010,B110}, // No.117 SHINING FIN
{B001,B010,B101}, // No.118 ULTIMATE FIN
{B001,B010,B100}, // No.119 RIDE GADGET
{B001,B010,B011} // No.120 RIDER ライダ
};

#define NONE 0
uint8_t r_rider = NONE;
uint8_t l_rider = NONE;
uint8_t r_reset_code[3] = {R_DELIMITER_CODE, R_DELIMITER_CODE, R_DELIMITER_CODE}; // 入力と逆順でコードを保持
uint8_t l_reset_code[3] = {L_DELIMITER_CODE, L_DELIMITER_CODE, L_DELIMITER_CODE}; // 入力と逆順でコードを保持

void generate_set_code(uint8_t set_side, uint8_t* code){
// 逆サイドの電位状態を保持する形のコードに書き換える
if(set_side == SIDE_R){
for(uint8_t i=0; i
#include

#define SOUND_POWER_ON 1
#define SOUND_EJECT 2
#define SOUND_ZX_RIDER_TIME 3
#define SOUND_ZX_ARMOR_TIME 4
#define SOUND_SHOWA_SINGLE 5
#define SOUND_SHOWA_RIDER_ARMOR_WAITING 6
#define SOUND_SHOWA_INIT 7
#define SOUND_SHOWA_ARMOR_TIME 8
#define SOUND_SHOWA_FINISH_READY_AND_WAITING 9
#define SOUND_SHOWA_FINISH_TIME 10
#define SOUND_SUMMON_1ST_READY 11
#define SOUND_SUMMON_2ND_READY 12
#define SOUND_SUMMON_V3_READY 13
#define SOUND_SUMMON_RIDERMAN_READY 14
#define SOUND_SUMMON_X_READY 15
#define SOUND_SUMMON_AMAZON_READY 16
#define SOUND_SUMMON_STRONGER_READY 17
#define SOUND_SUMMON_SKYRIDER_READY 18
#define SOUND_SUMMON_SUPER1_READY 19
#define SOUND_SUMMON_ZX_READY 20
#define SOUND_SUMMON_1ST 21
#define SOUND_SUMMON_2ND 22
#define SOUND_SUMMON_V3 23
#define SOUND_SUMMON_RIDERMAN 24
#define SOUND_SUMMON_X 25
#define SOUND_SUMMON_AMAZON 26
#define SOUND_SUMMON_STRONGER 27
#define SOUND_SUMMON_SKYRIDER 28
#define SOUND_SUMMON_SUPER1 29
#define SOUND_SUMMON_ZX 30
#define SONG_1ST 31
#define SONG_2ND 32
#define SONG_V3 33
#define SONG_RIDERMAN 34
#define SONG_X 35
#define SONG_AMAZON 36
#define SONG_STRONGER 37
#define SONG_SKYRIDER 38
#define SONG_SUPER1 39
#define SONG_ZX 40

#define READY_CHANGE_WAIT 1000
#define ARMOR_TIME_WAIT 6500
#define RIDER_TIME_WAIT 1000
#define FINISH_TIME_WAIT_SHORT 1000
#define FINISH_TIME_WAIT_LONG 2000

#define SOUND_VOLUME_DEFAULT 22

unsigned long sound_wait_start_time = 0;
boolean is_armor_time_waiting = false;
boolean is_rider_time_waiting = false;
boolean is_armor_time_finish_waiting = false;
boolean is_rider_time_finish_waiting = false;
boolean is_ready_change_waiting = false;

uint8_t volume = SOUND_VOLUME_DEFAULT;

SoftwareSerial ss_mp3_player(2, 3); // RX, TX
DFRobotDFPlayerMini mp3_player;

void control_sound(){
if(prev_state != state){
switch(state){
case STATE_SINGLE_A:
switch(prev_state){
case STATE_SINGLE_B:
mp3_player.playMp3Folder(SOUND_SHOWA_SINGLE);
break;
case STATE_READY_WP:
case STATE_WEAPON:
case STATE_READY_CH:
case STATE_CHANGED:
case STATE_READY_CR:
case STATE_CRITICAL:
case STATE_SUMMON:
mp3_player.playMp3Folder(SOUND_EJECT);
break;
default:
;
}
break;
case STATE_SINGLE_B:
mp3_player.playMp3Folder(SOUND_SHOWA_SINGLE);
break;
case STATE_READY_WP:
if(prev_state != STATE_WEAPON){
mp3_player.pause();
}
break;
case STATE_WEAPON:
// 本来は武器サウンドが鳴るが、今回は対応させない
break;
case STATE_READY_CH:
if(prev_state != STATE_CHANGED){
if(open_close_state == RIDERS_CLOSE){ // ZX
mp3_player.pause();
}else{ // 10人ライダー
sound_wait_start_time = millis();
is_ready_change_waiting = true;
}
}else{ // ZXモードから昭和ライダーモードに移行したとき
mp3_player.playMp3Folder(SOUND_SHOWA_RIDER_ARMOR_WAITING);
}
break;
case STATE_CHANGED:
mp3_player.pause();
if(prev_state != STATE_SUMMON){ // STATE_SUMMONのときの音声は、処理の都合上状態遷移の中で鳴らす
if(side == SIDE_RIDER_TIME){
sound_wait_start_time = millis();
is_rider_time_waiting = true;
}else if(side == SIDE_ARMOR_TIME){
sound_wait_start_time = millis();
is_armor_time_waiting = true;
}
}
break;
case STATE_READY_CR:
mp3_player.playMp3Folder(SOUND_SHOWA_FINISH_READY_AND_WAITING);
break;
case STATE_CRITICAL:
mp3_player.pause();
if(side == SIDE_RIDER_TIME){
sound_wait_start_time = millis();
is_rider_time_finish_waiting = true;
}else if(side == SIDE_ARMOR_TIME){
sound_wait_start_time = millis();
is_armor_time_finish_waiting = true;
}
break;
default:
;
}
}else{
unsigned long now = millis();
if(is_ready_change_waiting){
if(now – sound_wait_start_time >= READY_CHANGE_WAIT){
mp3_player.playMp3Folder(SOUND_SHOWA_RIDER_ARMOR_WAITING);
is_ready_change_waiting = false;
}
}else if(is_rider_time_waiting){
if(now – sound_wait_start_time >= RIDER_TIME_WAIT){
// mp3_player.playMp3Folder(SOUND_RIDER_TIME); // 本来はライダータイムが鳴るが、今回は対応させない
is_rider_time_waiting = false;
}
}else if(is_armor_time_waiting){
if(now – sound_wait_start_time >= ARMOR_TIME_WAIT){
if(open_close_state == RIDERS_CLOSE){
mp3_player.playMp3Folder(SOUND_ZX_ARMOR_TIME); // ZX
}else{
mp3_player.playMp3Folder(SOUND_SHOWA_ARMOR_TIME); // 10人ライダー
}
is_armor_time_waiting = false;
}
}else if(is_rider_time_finish_waiting){
if(now – sound_wait_start_time >= FINISH_TIME_WAIT_LONG){
mp3_player.playMp3Folder(SOUND_SHOWA_FINISH_TIME);
is_rider_time_finish_waiting = false;
}
}else if(is_armor_time_finish_waiting){
if(now – sound_wait_start_time >= FINISH_TIME_WAIT_SHORT){
mp3_player.playMp3Folder(SOUND_SHOWA_FINISH_TIME);
is_armor_time_finish_waiting = false;
}
}
}
}

////////// 発光処理 ////////////////////////////////////////////////////////////////

#define LED_COLOR_PIN 8

#include
#define N_COLOR_LED 10
#define LED_1ST 0
#define LED_2ND 1
#define LED_V3 2
#define LED_RIDERMAN 3
#define LED_X 4
#define LED_AMAZON 6
#define LED_STRONGER 7
#define LED_SKYRIDER 8
#define LED_SUPER1 9
#define LED_ZX 5
#define LUMINANCE_BASE 127
#define LUMINANCE_MAX 255
#define LED_COUNT_MAX 2000 // LOOP_INTERVAL_MSが20msで、40sまでの発光定義を想定

struct color_rgb {
uint8_t r;
uint8_t g;
uint8_t b;
};

struct color_rgb COLOR_WHITE = {LUMINANCE_MAX,LUMINANCE_MAX,LUMINANCE_MAX};
struct color_rgb COLOR_RED = {LUMINANCE_MAX,0,0};

uint16_t led_counter = LED_COUNT_MAX;
unsigned long prev_blink_time = 0;
unsigned long inc_dim_start_time = 0;
boolean is_lighting = false;
boolean is_inc = false;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_COLOR_LED, LED_COLOR_PIN, NEO_GRB);

void led_base_pattern_all_on(struct color_rgb *color){
inc_dim_start_time = 0;
for(uint8_t i=0;ir,color->g,color->b));
}
}

void led_base_pattern_all_off(){
inc_dim_start_time = 0;
for(uint8_t i=0;i= interval_ms){
if(is_lighting){
for(uint8_t i=0;ir, color->g, color->b));
}
}
is_lighting = !is_lighting;
prev_blink_time = now;
}
}

void led_base_pattern_all_dim(struct color_rgb *color, int interval_ms, uint8_t steps){
unsigned long now = millis();
if(inc_dim_start_time == 0){
inc_dim_start_time = now;
}
int ms_per_step = interval_ms / steps;
int current_step = (now – inc_dim_start_time) / ms_per_step;
if(current_step > steps){
current_step = steps;
}
uint8_t r_step = color->r/steps;
uint8_t g_step = color->g/steps;
uint8_t b_step = color->b/steps;
for(uint8_t i=0;i= interval_ms){
if(is_lighting){
pixels.setPixelColor(LED_ZX, pixels.Color(0,0,0));
}else{
pixels.setPixelColor(LED_ZX, pixels.Color(color->r, color->g, color->b));
}
is_lighting = !is_lighting;
prev_blink_time = now;
}
}

void led_base_pattern_zx_inc(struct color_rgb *color, int interval_ms, uint8_t steps){
unsigned long now = millis();
if(inc_dim_start_time == 0){
inc_dim_start_time = now;
}
int ms_per_step = interval_ms / steps;
int current_step = (now – inc_dim_start_time) / ms_per_step;
if(current_step > steps){
current_step = steps;
}
uint8_t r_step = color->r/steps;
uint8_t g_step = color->g/steps;
uint8_t b_step = color->b/steps;
pixels.setPixelColor(LED_ZX, pixels.Color(r_step*current_step, g_step*current_step, b_step*current_step));
}

void led_base_pattern_zx_dim(struct color_rgb *color, int interval_ms, uint8_t steps){
unsigned long now = millis();
if(inc_dim_start_time == 0){
inc_dim_start_time = now;
}
int ms_per_step = interval_ms / steps;
int current_step = (now – inc_dim_start_time) / ms_per_step;
if(current_step > steps){
current_step = steps;
}
uint8_t r_step = color->r/steps;
uint8_t g_step = color->g/steps;
uint8_t b_step = color->b/steps;
pixels.setPixelColor(LED_ZX, pixels.Color(r_step*(steps-current_step), g_step*(steps-current_step), b_step*(steps-current_step)));
}

void led_base_pattern_zx_blink_slowly(struct color_rgb *color, int interval_ms, uint8_t steps){
unsigned long now = millis();
if(inc_dim_start_time == 0){
inc_dim_start_time = now;
}
int ms_per_step = interval_ms / steps;
int current_step = (now – inc_dim_start_time) / ms_per_step;
if(current_step > steps){
current_step = steps;
}
uint8_t r_step = color->r/steps;
uint8_t g_step = color->g/steps;
uint8_t b_step = color->b/steps;
if(is_inc){
pixels.setPixelColor(LED_ZX, pixels.Color(r_step*current_step, g_step*current_step, b_step*current_step));
}else{
pixels.setPixelColor(LED_ZX, pixels.Color(r_step*(steps-current_step), g_step*(steps-current_step), b_step*(steps-current_step)));
}
if(now – inc_dim_start_time >= interval_ms){
is_inc = !is_inc;
inc_dim_start_time = 0;
}
}

void led_base_pattern_rider(struct color_rgb *color, uint8_t rider){
// 特定のライダーを点灯させる
inc_dim_start_time = 0;
pixels.setPixelColor(rider, pixels.Color(color->r,color->g,color->b));
}

void led_base_pattern_rider_seq(struct color_rgb *color, uint8_t rider){
// 指定したライダーまでをすべて点灯させる
inc_dim_start_time = 0;
if(rider <= LED_ZX){ // 1号、2号、V3、ライダーマン、X、ZX for(uint8_t i=0;i<=rider;i++){ pixels.setPixelColor(i, pixels.Color(color->r,color->g,color->b));
}
}else{ // アマゾン、ストロンガー、スカイライダー、スーパー1
for(uint8_t i=0;i<=4;i++){ pixels.setPixelColor(i, pixels.Color(color->r,color->g,color->b));
}
for(uint8_t i=6;i<=rider;i++){ pixels.setPixelColor(i, pixels.Color(color->r,color->g,color->b));
}
}
}

void led_base_pattern_rider_only(struct color_rgb *color, uint8_t rider_code){
// 特定のライダーのみを点灯させ、他は消灯させる。
// これのみタッチ処理と関連して呼び出されるため、rider_codeを各LEDの番号に対応させる必要がある
uint8_t rider = 0;
if(CODE_059_RIDER1_1971 <= rider_code && rider_code <= CODE_063_X_1974){ rider = rider_code - 59; }else if(CODE_064_AMAZON_1974 <= rider_code && rider_code <= CODE_067_SUPER1_1980){ rider = rider_code - 58; }else{ rider = LED_ZX; } inc_dim_start_time = 0; pixels.setPixelColor(rider, pixels.Color(color->r,color->g,color->b));
for(uint8_t i=0;i TOUCH_INTERVAL_MS){
for(uint8_t i;i

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (7件)

  • おー、なんか私の名前がいっぱい載ってる!ちょっと嬉しいです。

    私は子供が遊んでいた為、通常動作の維持プラスアルファにこだわりましたが突き詰めた赤外線での制御はエグいですね。ジクウドライバーがバシュバシュ切り替わるのは凄い通り越してちょっと引くレベルですw

    凄い物を見せて頂きありがとうございました。ちょっとでもお役に立てて嬉しいです。
    さすがにこの作品は真似できませんw

    • かっぱ次郎 様

      いえいえ、こちらこそありがとうございます。今回のライドウォッチは、絵を描いてくれた方と、次郎様のアイデアがあってこそ、たくさんの人に驚きかつ楽しんで頂けたのだと思っています。おそらく次郎様の赤外線通信方式なしでも形にはできたたと思いますが、その場合は単に音声が鳴るだけで、「なるほど、すごいね」程度で終わってしまっていたと思います。やっぱり視覚的に大きく変わっていくというのはすごくインパクトあるなと、今回改めて思いました。

  • 5Vのprominiを使っているのですが、そうするとフルカラーシリアルテープが真っ白にただ光り続けるだけで制御が効きません。
    どうしたらいいですか

    • うーん、情報が少なすぎて回答に困りますが。。。

      少なくとも光っているということは、5VとGNDの接続はうまくいっているのだと思います。となると、まず疑うのは、残るコントロール用の配線がきちんと接続されているかどうか。それも正しく配線されているということであれば、あとはもうプログラムのどこかにミスがあるということだと思います。ただ、稀にLEDの方が壊れているケースもあるかもしれないので、プログラミングも絶対に合っているはずということであれば、もう一つ用意して確かめてみてもよいかもしれません。

  • hidaka_hirojiさんのブログにもあるフルカラーリングのスケッチを試したところ
    それも同じ現象に陥ってしまいました。
    ですが、3.3Vで流すと綺麗に光ってくれます。
    自分のスケッチでも同様です。

  • そして、neopixelのライブラリにあるスケッチも試しましたが5vでもしっかり動きました。

    • 返信が遅くなってしまい申し訳ありません。またすみません、長らく5VのArduino Pro Miniを使っていないこともあって、原因がわかりません。。。一律5Vで動かないならまだしも、サンプルの方では5Vで動くいうのが不可解で、原因の切り分けができないのです。申し訳ありません。

コメントする

目次