派生クラスを使ってオリジナルイルミネーションを作成する

ALEDクラスの派生クラスを作成することで、オリジナル模様とアニメーションを描写する方法について解説しました。この方法だと、比較的少ないコードでALEDクラス標準機能では対応できないようなイルミネーションを実現できます。

本記事はArduino互換機「CG-CustomARGB」を使ったアドレサブルRGBプログラミングチュートリアルの一部です。

更新日 : 2020年5月19日

ALEDクラスの標準機能で実現できない時は

これまでのチュートリアル記事で解説した通り、ALEDクラスに実装されている機能を使えば様々なイルミネーションを作成することが可能です。しかし、標準の機能だけでは実現できないようなイルミネーションを作成したいケースもあると思います。

こういった場合におすすめなのが、ALEDクラスの派生クラスを作成する方法です。

派生クラスとは

派生クラスとはC++言語に備わっている機能で、既存のクラスを元に新しい別のクラス(派生クラス)を作ることができます。派生クラスは元のクラスの機能を全て引き継いでいるのですが、引き継いだ機能の一部を自由に書き換えたり、新しい機能を追加することができます。

派生クラスのイメージ

派生クラスを作るメリット

派生クラスを使うと、既存のALEDクラスの機能を全て引き継ぐことができます。これには、データをデバイスに送信する機能、模様にあわせて色を計算する機能、アニメーションする機能などが含まれます。変更、追加したい箇所だけコードを書けばよいので、ゼロから新たにプログラミングするよりもはるかに楽でしょう。例えば、自分オリジナルの模様に変更し、アニメーションについては引き継いだ機能をそのまま利用する、といった具合です。

派生クラスを作成してオリジナル模様を描写するスケッチ「Derived」

実際にスケッチを用いて、派生クラスでオリジナル模様を描写する方法を解説していきます。

まず、前提として今回使うCORSAIR製LL140 RGBについて説明しておきます。このファンは、内周部に4個、外周部に12個のLEDを搭載しており、以下の番号の順番に配置されています。そのため、このファンに通常の虹色模様(赤から開始し、色相が360°変化するグラデーション)を描写すると以下のように、内周部と外周部の色が異なります。

LL140 RGBに通常のグラデーション模様を描写

今回は、派生クラスを作成し、draw関数を書き換える(オーバーライド)ことで、以下のように内周部と外周部が同じ色になるようなオリジナル模様を描写させたいと思います。

LL140 RGBに派生クラスを使ってオリジナル模様を描写

実際にこのオリジナル模様を描写したスケッチが以下です。

LEDの配置はお使いのデバイスによって異なるので、このスケッチを実行しても必ずしも上記画像、動画のようにはならないことに注意して下さい。

Derivedスケッチ解説

3-4行目
// ALEDクラスの派生クラスLL140を作成
class LL140 : public ALED {
...
};

ここでALEDクラスから派生したLL140というクラスを作成しています。クラス名は自由に付けて構いません。{}内に変更する機能や追加する機能を記述していきます。

5行目
  using ALED::ALED; // コンストラクタ等を引き継ぐ

ALEDクラスのコンストラクタ(初期化処理や引数)を引き継ぐことを明示しています。多くの場合、あまり気にせず同じように記述するとよいでしょう。

9行目
  void draw() {
    // 中身は自由にコーディング可能
    ...
  }

ここではdraw関数の内容を変更しています。既に存在するものと同じ名前の関数を定義すると、内容が上書き(オーバーライド)されます。

draw関数はpatternなどのメンバ変数に沿って模様をバッファーに格納した後、sendLedDataでデバイスへ送信する役割を担っています。これを変更することで、オリジナルの模様に変更することができます。一方、アニメーションの際にもdraw関数が使われているので、アニメーション時の模様も変更されます。

中身は自由にコーディング可能で制限は無いのですが、可能であればpos, color, colorPatternメンバ変数を使用するようにします。そうすると、アニメーションにも対応できるからです。詳細はaled.hのコードを参照して下さい。

11-13行目
    // 今回はCORSAIR製LL140の中心と外周に同じグラデーションを描写する
    loadGradBase(color, colorPattern, pos, 100.0f, val, 0, 4); // 中心4個のLED
    loadGradBase(color, colorPattern, pos - 16.66f, 100.0f, val, 4, 12);  // 外周12個のLED

ゼロから模様を計算するコードを書いても良いのですが、今回はALEDクラス既存のloadGradBase関数を使用しました。この関数は最後と最後から2番目の引数を指定することで、対象のLEDを絞れるように設計されています。

12行目で0番から4個のLED(内周)に、13行目で4番から12個のLED(外周)にそれぞれグラデーションを描写するようにしています。13行目で pos – 16.66f としているのは内周と外周で色の位置を合わせるためです。LL140 RGBのLED配置画像を参照して下さい。

15行目
    sendLedData();  // デバイスにLEDデータを送信

デバイスにデータを送信する命令です。これは元のALEDクラスにおいてdraw関数がこの役割も担っているため必要になります。詳細はaled.hのコードを参照して下さい。

19-21行目
// 定義したLL140クラス型から、実際に使用するためのll140を作成 (インスタンス化)
// オーバーライドした部分以外はALEDクラスの機能を引き継ぐ
LL140 ll140(CH1 | CH2 | CH3 | CH4 | CH5, 16);

上で定義(作成)したLL140クラスを実際に使用する準備です。これまでの例ではALEDクラスだったところが新しい派生クラスの名前を指定していることが分かります。書き換えたdrawの部分以外はALEDクラスの機能を引き継いでいるので、チャネルやLED数の指定方法は変わりません。

32-36行目
  ll140.color.hue = 0.0f;
  ll140.color.sat = 100.0f;
  ll140.color.val = 100.0f;
  ll140.colorPattern.hue = 360.0f;
  ll140.posChange = 2.0f;

色やアニメーションパラメータの指定もALEDクラスと変わりません。これはdraw関数でこれらのパラメーターを使用して模様を描写するようなコードを書いたからです。今回は上の画像で示したような虹色でアニメーションするため、colorPattern.hue=360、posChange=2.0としました。

40行目
  ll140.animation(100);  // アニメーション

変更したのはdraw関数なのに、アニメーションする際の模様も変更されていることを不思議に思った方もいるかもしれません。animation関数は、内部ではposなどのパラメーターを少しずつ変えながらdraw関数を繰り返し呼び出すことで、アニメーションさせています。そのため、draw関数の変更がアニメーションにも反映されるのです。

内周と外周を交互に点滅するスケッチ「Derived2」

スケッチ「Derived」では、既存のdraw関数を書き換えることで模様をカスタマイズしていました。

次に、「Derived」スケッチで作成した派生クラスに新しいパラメーター(メンバ変数)を追加して、内周部と外周部のLEDの明るさを独立して制御する方法を解説します。この方法を参考にすれば、新規パラメーターを追加して機能を拡張することが可能になります。

LEDの配置はお使いのデバイスによって異なるので、このスケッチを実行しても必ずしも上記動画のようにはならないことに注意して下さい。

Derived2スケッチ解説

8-10行目
  // 外周LED用の明るさ、アニメーション用メンバ変数を追加
  float val2 = 100.0f;
  float val2Change = 0.0f;

外周部のLEDの明るさを決める新しいパラメーター(メンバ変数) val2と、アニメーション用のval2Changeを追加しています。内周部のLEDについては既存のvalとvalChangeを利用することにします。

実際には、こういったルールや変数名に制限はなく自由にコーディングして構いません。今回はこのようなルールで作成する、ということです。

12-19行目
  // reset関数をオーバーライド
  void reset(bool on = true) {
    ALED::reset(on);  // 継承元のreset関数を呼び出す

    // 新しく追加したメンバ変数を初期化
    val2 = on ? 100.0f : 0.0f;
    val2Change = 0.0f;
  }

ALEDクラスでは、パラメーターに一括でデフォルト値をセットするreset関数があり、インスタンス作成時にも呼ばれるようになっています。新しいパラメーターを追加したので、これらもreset関数に含まれるようにしておきます。既存のパラメーターについては、継承元のALED::resetを呼び出してセットすると簡単です。

なお、パラメーターを手動で設定するのであれば、reset関数を変更しなくても動作に問題はありません。

26行目
    loadGradBase(color, colorPattern, pos - 16.66f, 100.0f, val2, 4, 12);  // 外周12個のLED

draw関数で、外周部のLEDの描写にはval2を使うように変更しています。他は「Derived」スケッチと同じです。

31-39行目
  // animationUpdate関数をオーバーライド
  void animationUpdate() {
    ALED::animationUpdate();  // 継承元のanimationUpdate関数を呼び出す

    // val2Changeに応じてval2を変化させるコードを追加
    val2 += val2Change;
    if (val2 > 100.0f) val2 = 100.0f;
    if (val2 < 0.0f) val2 = 0.0f;
  }

ALEDクラスではアニメーションの際に、color, val, posの値をcolorChange, valChange, posChangeの値に応じて変化させています。実際にその処理を行っているのがanimationUpdate関数です。新しいパラメーター(メンバ変数)を追加したので、これらもanimationUpdate関数に含まれるようにしておきます。既存のパラメーターについては、継承元のALED::animationUpdateを呼び出して処理すると簡単です。

65-79行目
  // 内周点灯
  ll140.valChange = 4.0;
  ll140.animation(50);

  // 内周消灯
  ll140.valChange = -4.0;
  ll140.animation(25);

  // 外周点灯
  ll140.val2Change = 4.0;
  ll140.animation(50);

  // 外周消灯
  ll140.val2Change = -4.0;
  ll140.animation(25);

valChangeを変えることで内周部LEDを、val2Changeを変えることで外周部LEDを点滅させています。

まとめ

ALEDクラスの派生クラスを作成することで、オリジナル模様とアニメーションを描写する方法について解説しました。この方法だと、比較的少ないコードでALEDクラス標準機能では対応できないようなイルミネーションを実現できます。上級者向けの機能ですが、より凝ったイルミネーションの作成の一助となれば幸いです。

Indoor Corgiではソフトウェア開発業務として、オリジナルイルミネーションの開発も承っております。お使いのアドレサブルRGBデバイスにカスタマイズしたイルミネーションを作りたいなどのご要望があれば、indoorcorgi@gmial.comもしくはお問い合わせフォームよりご相談ください。