M5StickCで画面上のボールをバウンドさせる

M5StickCにはLCDが付いているので、画面上で図形を動かすようなスケッチを作ることができます。


今回は、M5StickCの画面上で、ボールを自由落下させ、地面に着いた時に跳ね返るようなスケッチを作ってみます。

ひとつひとつのステップごとに、動作確認をしながら、進めていきます。

ボールを自由落下させる

まず最初に、ボールを自由落下させてみます。
F = mg の式で重力を求め、そこからボールの加速度「a」、ボールの速度「v」、ボールの移動距離「x」を求めていきます(画面のサイズが小さいので、それにあわせて数値を補正しています)。
その結果に基づいて、ボール(円)を描画します。
これを一定間隔で繰り返します。

スケッチは以下のとおりです。

#include <M5StickC.h>

float t = 0.0f; // 画面の上端座標
float g = 9.8f; // 重力加速度
float m = 1.0f; // ボールの質量
float r = 10.0f; // ボールの半径
float x = t+r; // ボールの位置(中心座標)
float v = 0.0f; // ボールの速度

void setup() {
  M5.begin();
  M5.Lcd.setRotation(1);
}

void loop() {
  M5.update();
  if(M5.BtnA.wasPressed()) {
    x = r;
    v = 0.0;
  }
  float f = m * g;
  float a = f / m / 10;
  v += a;
  x += v;
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.fillCircle((int)x, 40, (int)r, YELLOW);
  delay(20);
}

結果は以下のとおりです。ボタンAを押すと、ボールが落ちます。

ボールをバウンドさせる

上記のスケッチでは、ボールは落ちていくだけなので、ここでは、ボールが地面に到達したときに、バウンドさせてみます。
ボールが地面に沈み込んだ時に、F = kx の式で、弾性力を考慮します。

スケッチは以下のとおりです。

#include <M5StickC.h>

float t = 0.0f; // 画面の上端座標
float b = 160.0f; // 画面の下端座標
float g = 9.8f; // 重力加速度
float m = 1.0f; // ボールの質量
float r = 10.0f; // ボールの半径
float k = 20.0f; // バネ定数
float x = t+r; // ボールの位置(中心座標)
float v = 0.0f; // ボールの速度

void setup() {
  M5.begin();
  M5.Lcd.setRotation(1);
}

void loop() {
  M5.update();
  if(M5.BtnA.wasPressed()) {
    x = r;
    v = 0.0;
  }
  float f = m * g;
  if(x+r > b) {
    float f2 = k * ((x+r)-b);
    f = f - f2;
  }
  float a = f / m / 10;
  v += a;
  x += v;
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.fillCircle((int)x, 40, (int)r, YELLOW);
  delay(20);
}

結果は以下のとおりで、ボールが地面に到達すると、跳ね返るようになりました。
ただし、ボールの勢いは減衰せず、永遠にバウンドを繰り返します。

ボールのバウンドを減衰させる

上記では、ボールが永遠にバウンドし続けるので、バウンドを減衰させ、最終的には止まるようにしてみます。
弾性力を考慮する時に、同時に F = cv の式で、粘性抵抗も考慮します。

スケッチは以下のとおりです。

#include <M5StickC.h>

float t = 0.0f; // 画面の上端座標
float b = 160.0f; // 画面の下端座標
float g = 9.8f; // 重力加速度
float m = 1.0f; // ボールの質量
float r = 10.0f; // ボールの半径
float k = 20.0f; // バネ定数
float c = 2.0f; // 粘性係数
float x = t+r; // ボールの位置(中心座標)
float v = 0.0f; // ボールの速度

void setup() {
  M5.begin();
  M5.Lcd.setRotation(1);
}

void loop() {
  M5.update();
  if(M5.BtnA.wasPressed()) {
    x = r;
    v = 0.0;
  }
  float f = m * g;
  if(x+r > b) {
    float f2 = k * ((x+r)-b);
    float f3 = c * v;
    f = f - f2 - f3;
  }
  float a = f / m / 10;
  v += a;
  x += v;
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.fillCircle((int)x, 40, (int)r, YELLOW);
  delay(20);
}

結果は以下のとおりです。ボールが地面に到達すると跳ね返りますが、跳ね返るごとに高さが低くなり、最終的には止まるようになりました。

それほど難しい処理はしていませんが、視覚的にも結構おもしろいスケッチを作ることができました。
このような処理を組み合わせることで、色々と、より複雑な描画もできそうです。

なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。


ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。


このサイトで書いている、M5Stackシリーズ(M5Stack、M5StickCなど)に関するブログ記事を、「さとやまノート」という別のブログページに、あらためて整理してまとめました。

他のM5Stackシリーズの記事にも興味のある方は「さとやまノート」をご覧ください。