画像がチラチラしてみずらいのだ。
しておるのか?
この記事では、Arduino IDEを使ってM5Stackのディスプレイに文字や画像を表示する際のちらつきや、安定した描画を行うための仕組みについて画面制御の方法を確認していきます。
今回は、「lovyan03」さんが公開されているArduino IDE向けのライブラリ「Lovyan GFX」 Libraryを使用します。
「Lovyan GFX」は、Arduino IDE共通で使用でき、かつ様々なディスプレイコントローラに対応されているので、、Arduino対応機器間で同じソースを使いたい場合に有効です。
しかも、ディスプレイへの描画速度を安定化させるための仕組みをいくつか実装されています。
実際に動かして確認してみましょう!
ディスプレイに描画する際に悩むポイント
プログラムで、マイコンなどのディスプレイに文字や画像を描画する際によく悩むのが次のポイントです。
- 画像をつかったアニメーションが難しい。
- なんか画面がチラチラする
こういった、悩みポイントを解消するために使えるのが、「Sprite:スプライト」という仕組みです。
Sprite(スプライト)とは?
簡単に言うと、メモリ内に作成される仮想的な画面です。
ディスプレイに描画する際のdraw系やprint系などの処理もスプライトに対して行うことができます。
ディスプレイに対して直接描画すると、どのタイミングで描画されるのかをコントロールすることは難しく、前述のチラつきなどが発生する原因となります。
そこで、次のようにメモリ内の仮想的な画面であるスプライトに表示内容を描画してから、実際のディスプレイに描画することで、描画のタイミングをコントロールすることができます。
また、スプライトは、スプライトに描画することもできるので、複数のスプライトから1つのスプライトを作成することもできます。
Sprite(スプライト)の使用方法
スプライトをプログラム内で使用するためには、次の処理を記述する必要があります。
インスタンスの生成
lovyanGFXのインスタンス生成と同じようにスプライトもインスタンスを生成する必要があります。
static LGFX_Sprite sprite1(&lcd); // スプライト1を生成(描画先:lcd(ディスプレイ)) static LGFX_Sprite sprite2(&sprite1); // スプライト2を生成(描画先:スプライト1) static LGFX_Sprite sprite3(&sprite1); // スプライト3を生成(描画先:スプライト1)
スプライトの作成
実際に操作するスプライトを作成します。
Setup関数やloop関数内で記述するか、呼び出す関数に記述します。
sprite1.createSprite(100, 100); // スプライト1を(幅:100×高さ:100)で作成
スプライトの削除
sprite1.deleteSprite(); // スプライト1を開放
スプライトはメモリを確保してしまうので、使用しないスプライトは、削除してメモリを解放します。
次章から、悩みポイントの実例と解決方法を紹介していきます。
画像を使ったアニメーションが難しい
ディスプレイ上にセンサーなどの値をわかりやすく表示する場合、画像などを使ったアニメーションが有効ですよね。
画像は準備したけど、画像をどうやって動かしたらいいか。
難しそう。。。
ということはないでしょうか。
でも大丈夫です。
「LovyanGFX」のスプライト機能は、スプライトを自由に回転、拡大・縮小などを行うことができます。
例えば、アナログメーターを作りたい場合、次のように画像を準備し、スプライトを作成します。
ディスプレイ描画までの流れ
- スプライト2として、メーターの背景と、文字を描画します。
- スプライト3として、メーターの針を描画します。
- スプライト2をスプライト1に描画します。この時、スプライト2の縮尺と、描画位置を指定して描画します。
- スプライト3をスプライト1に描画します。この時、スプライト3の縮尺、描画位置に加えて「回転角度」を設定します。回転角度は、センサー値などから計算して求めます。
- スプライト1をディスプレイに描画します。
- 上記の①~⑤を繰り返します。
スプライトの描画関数
関数 | 説明 |
setPivot(x, y); | スプライトの中心点(x, y)を指定します。 初期値は左上(0, 0)です。 例えば、幅:width、高さ:heightのスプライトを中心で回転させたい場合は次のように記載します。 setPivot(width/2, height/2); |
pushRotateZoom(x, y, deg, width, height); | 描画先(スプライトまたはディスプレイ)上の(x, y)の座標にスプライトの中心点を合わせて表示します。 width、heightは、横、縦の比率(倍数)を指定します。 degには、スプライトを表示する際の角度を指定します。 |
pushRotateZoomWithAA(x, y, deg, width, height); | 前述と同じように描画しますが、表示時にアンチエイリアシングを行います。 |
画像の描画関数
図形の描画は、次の関数になります。
この関数は、スプライトを使わない場合も利用可能です。
関数 | 説明 |
pushImage(x, y, width, height, img); | 描画先(スプライトまたはディスプレイ)上の(x, y)の座標に画像の左上を合わせて表示します。 width、heightは、横、縦の比率(倍数)を指定します。 |
図形、文字の描画関数
スプライトへの図形、文字などの描画については、LovyanGFXのディスプレイへの描画と同じものが使用できます。
例えば以下のようになります。
sprite1.pushImage(0, 0, 100, 100, led_screen_img01); // 画像の描画
sprite1.fillRect(0, 0, 150, 50, BLACK); // 回転数表示域を塗りつぶし
sprite1.setTextColor(GREEN, BLACK); // テキストカラーの指定
sprite1.setCursor(10, 5, 7); // カーソル位置とフォントの設定
sprite1.print(rpm_str); // 文字の描画
基本的な描画関数については、次の記事で紹介しています。
すけろく 標準ライブラリでの画面描画はできた。 しかし、M5Stack向けのライブラリなので 汎用性がないな。 げんろく たしかに。 M5StickCや他のAruduino機器でも使えるものが必要[…]
なんか画面がチラチラする
センサーで取得したデータ値をディスプレイに表示する際や、図形や画像を使ってアニメーションさせる場合、draw系や、print系の処理を記述するだけだと画面にチラつきがみられる場合があります。
特にArduino などのloop関数内で繰り返し処理で、実行のたびに表示する内容が変わる場合などに顕著に現れます。
例えば次のようなイメージです。
メーターや数字部分がチカチカしていますよね。
これは、loop関数から呼び出す描画関数内で、draw系やprint系の処理を繰り返しているだけの場合になります。
これをSprite(スプライト)機能を使ってメモリに一度描画してからディスプレイに描画させるとどうなるでしょうか。
ちらつきがなくなり、見やすくなりました。
具体的にどういったことかを見ていきます。
単純な描画の繰り返しの場合
各処理が順番にディスプレイに表示されていくことの繰り返しが発生し、チラつく原因になります。
Sprite(スプライト)を使った描画の場合
メモリ上の仮想画面に一度描画してから、ディスプレイに描画することでチラつきが抑えられます。
編集後記
いかがだったでしょうか。
LovyanGFXのスプライト機能をご紹介しました。
スプライト機能は、スプライトの拡大、縮小、回転が容易に指定できるので、センサー値によるアニメーションなどに有効です。
ぜひ、皆さんもチャレンジしてみてくださいね!
今回の記事は以上になります。
最後までご覧いただきありがとうございました。
これからはじめる方にお勧めの参考図書はこちら!
アイデアをカタチにする! M5Stack入門&実践ガイド | M5Stack&M5StickCではじめるIoT入門 | みんなのM5Stack入門 | ESP32&Arduino 電子工作 プログラミング入門 | みんなのArduino入門 |
確認する | 確認する | 確認する | 確認する | 確認する |
記事内でご紹介した商品はこちら!
M5Stack Core2 開発キット
Arduino、UIFlow、MicroPythonに対応している組み込み開発キットです。
タッチスクリーン、マイク、IMUを使うことができ、従来のM5Stackよりも多機能なモデルです。 バッテリーも搭載しています。一台でいろいろと遊べる機器なのでおススメです!