【リハビリ×デジタルアート】圧センサーで簡単!打ち上げ花火をArduino & Pythonで作ろう!

Arduino 機器制作




圧センサーで打ち上げ花火

花火が下から打ち上がり、一定の高さに達したら「ひまわり」のような螺旋パターンで花火が爆発するコード例です。圧センサーでなくとも、他のセンサーでも実施可能です。

【ポイント】

  • ロケットフェーズ:画面下部から上昇する花火の玉を表現します。
  • 爆発フェーズ:ロケットが一定の高さに達すると、黄金角(約137.5°)を利用した螺旋パターンでパーティクルを生成し、ひまわりのような花火の形にします。

リハビリ場面での想定

例1:シンプルにプロジェクターなど使用し、レクリエーションなどで活用

壁などにセンサーを仕掛けることで、前方リーチの訓練になる。

例2:拍手などの音を拾い、その数値の変化で花火をあげる場合は、タイミングや周囲との協調の促進などの練習となる。

例3:力を鍛えたい部分の出力などを数値として拾うことで、視覚的フィードバックとなる。

アイデア次第で様々な場面に活かすことが可能です。



Arduino側の設定

センサー(例:アナログ入力A0)からの値が一定の閾値(ここでは500を例示)を超えた場合に「TRIGGER」を送信するコードです。

 

Arduinoコード

// 圧センサー用のピン設定(A0を使用)
int sensorPin = A0;  
int threshold = 500;  // 圧力の閾値(適宜調整してください)

void setup() {
  Serial.begin(9600);  // シリアル通信を開始
}

void loop() {
  int sensorValue = analogRead(sensorPin);  // センサーの値を読み取る
  Serial.println(sensorValue);  // センサー値をシリアルモニタに出力(デバッグ用)

  // センサーの値が閾値を超えたら "TRIGGER" を送信
  if (sensorValue > threshold) {
    Serial.println("TRIGGER");
    delay(1000);  // トリガー後、1秒待機して多重送信を防止
  }
  
  delay(100);  // 少し待機してから再度読み取り
}




Python側の設定

Pythonコード

import serial
import pygame
import sys
import random
import math

# --- シリアル通信の設定 ---
SERIAL_PORT = 'COM3'  # 環境に合わせて変更してください
BAUD_RATE = 9600

try:
    ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
except Exception as e:
    print(f"シリアルポート {SERIAL_PORT} に接続できませんでした: {e}")
    sys.exit()

# --- Pygameの初期設定 ---
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Sunflower Fireworks")
clock = pygame.time.Clock()

# 背景画像の読み込み(なければ黒背景)
try:
    background = pygame.image.load("background.jpg").convert()
    background = pygame.transform.scale(background, (WIDTH, HEIGHT))
except Exception as e:
    print("背景画像が見つかりません。背景は黒になります。")
    background = None

# --- Fireworkクラス(ロケットとひまわり爆発) ---
class Firework:
    def __init__(self, x, target_y):
        self.x = x
        self.y = HEIGHT  # ロケットは画面下部から発射
        self.target_y = target_y  # 爆発する高さ
        self.vy = -8  # 上向きの初速度
        self.exploded = False
        self.particles = []  # 爆発後のパーティクルリスト
    
    def update(self):
        if not self.exploded:
            # ロケット上昇フェーズ
            self.y += self.vy
            if self.y <= self.target_y: self.explode() else: # 爆発パーティクルの更新 for p in self.particles: p[0] += p[2] # x座標更新 p[1] += p[3] # y座標更新 p[3] += 0.05 # ゆるやかな重力効果(y方向) p[4] -= 0.05 # パーティクルのサイズが徐々に減少 self.particles = [p for p in self.particles if p[4] > 0]
    
    def explode(self):
        self.exploded = True
        num_particles = 150  # パーティクル数(調整可能)
        golden_angle = math.radians(137.5)
        # 黄金角を利用したひまわりパターンの生成
        for i in range(num_particles):
            angle = i * golden_angle
            # パーティクルの速度は sqrt(i) に比例(調整可能)
            speed = 3 + (math.sqrt(i) * 0.2)
            vx = speed * math.cos(angle)
            vy = speed * math.sin(angle)
            size = random.randint(4, 8)  # 初期サイズ(調整可能)
            self.particles.append([self.x, self.y, vx, vy, size])
    
    def draw(self, surface):
        if not self.exploded:
            # 上昇中のロケットを小さな白い円で描画
            pygame.draw.circle(surface, (255, 255, 255), (int(self.x), int(self.y)), 3)
        else:
            # 爆発パーティクルの描画(ランダムな色)
            for p in self.particles:
                color = (255, random.randint(100, 255), random.randint(100, 255))
                pygame.draw.circle(surface, color, (int(p[0]), int(p[1])), int(p[4]))

fireworks = []

def trigger_firework():
    # ランダムなx座標と、爆発する高さ(上半分)を設定
    x = random.randint(100, WIDTH - 100)
    target_y = random.randint(100, HEIGHT // 2)
    fireworks.append(Firework(x, target_y))

def main():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                ser.close()
                pygame.quit()
                sys.exit()
        
        # 背景描画
        if background:
            screen.blit(background, (0, 0))
        else:
            screen.fill((0, 0, 0))
        
        # Arduinoからのシリアルデータを監視
        if ser.in_waiting:
            try:
                line = ser.readline().decode('utf-8').strip()
            except UnicodeDecodeError:
                line = ""
            if line == "TRIGGER":
                trigger_firework()
        
        # 花火の更新と描画
        for fw in fireworks:
            fw.update()
            fw.draw(screen)
        # 完全に終了した花火はリストから除去
        fireworks[:] = [fw for fw in fireworks if (not fw.exploded) or (fw.particles)]
        
        pygame.display.flip()
        clock.tick(60)  # 60FPS

if __name__ == "__main__":
    main()


 

【コード解説】

  1. Fireworkクラス

    • 花火の玉のフェーズself.y は画面下部から上昇し、target_y に達すると explode() を呼び出して爆発を開始します。
    • 爆発フェーズ:黄金角を用いて150個のパーティクルを生成。各パーティクルは螺旋状の方向に初期速度が与えられ、徐々にサイズが縮小して消えていきます。
  2. trigger_firework() 関数

    • シリアルから「TRIGGER」が受信されると、ランダムな位置と爆発高さで新たな花火を生成します。
  3. main() 関数

    • シリアルデータの監視、背景描画、花火の更新&描画を行い、60FPSでループします。

このコードで、花火は下部から上昇し、一定の高さでひまわりのような螺旋パターンの爆発を行います。必要に応じて数値(速度、パーティクル数、サイズなど)を調整して、お好みの演出にカスタマイズしてください。

 



背景画像はどのようにPCに入れれば良いの?

背景画像ファイル(例:background.jpg)をPythonプログラムで使用するには、以下の手順でPC上に配置してください。

  1. 画像ファイルを準備する

    • 任意の画像編集ソフトやウェブからダウンロードした画像を「background.jpg」などの名前で保存します。
  2. プロジェクトフォルダに配置する

    • Pythonコード(例:fireworks.py)が保存されているフォルダと同じディレクトリに、背景画像ファイルをコピーまたは移動します。
    • 例えば、以下のようなフォルダ構成にします:
      arduino
      MyFireworksProject/
      ├── fireworks.py
      └── background.jpg
  3. ファイルパスの確認

    • コード内では相対パス(例:"background.jpg")で画像を読み込むようにしているため、背景画像がコードファイルと同じフォルダに存在すれば正しく読み込まれます。
    • もし別の場所に配置したい場合は、絶対パスや相対パスを適宜修正してください。

以上の手順で背景画像をPCに取り込み、プログラム内で使用できるようになります。



特集記事

コメント

この記事へのコメントはありません。

TOP