コントローラ化

### 背景
12/5の記事にようにspheroのboltは傾きを検出することができるようです。

ここでは傾きを検出してwindows上の画面の中を操作するコントローラをboltで作ってみます。

### Scratch
Sphero IDEにはその機能は見つかりませんでした。

### spheroV2
ここでもpygameモジュールを用いました。

https://www.pygame.org/wiki/GettingStarted

chatGPT先生と相談しながら作成しました。
bluetoothの通信とpygameの並列化が衝突するようだったので、入力内容をqueingして逐次描画する方式にしました。

```
import time
from multiprocessing import Queue, Process
from spherov2 import scanner
from spherov2.sphero_edu import SpheroEduAPI
from spherov2.types import Color
from DrawingModule import drawing_process  # 描画モジュールのプロセスをインポート

# メイン関数
def main():
    # 描画プロセスとの通信用キュー
    queue = Queue()

    # 描画プロセスを開始
    drawing_proc = Process(target=drawing_process, args=(queue,))
    drawing_proc.start()

    print("Testing Starting...")
    print("Connecting to Bolt...")
    toy = scanner.find_BOLT()

    if toy is not None:
        print("Connected.")
        with SpheroEduAPI(toy) as droid:
            print("Testing Start...")

            droid.reset_aim()
            droid.set_stabilization(False)
            droid.set_front_led(Color(r=4, g=4, b=4))

            try:
                while True:
                    # Bolt のピッチとロールを取得
                    orient = droid.get_orientation()
                    pitch = orient['pitch']  # 上下方向
                    roll = orient['roll']    # 左右方向

                    # キューにピッチとロールを送信
                    queue.put({"pitch": pitch, "roll": roll})

                    # フレームレートの調整
                    time.sleep(0.1)

            except KeyboardInterrupt:
                print("\nProgram interrupted by user.")
            except Exception as e:
                print(f"An error occurred: {e}")
            finally:
                # 終了メッセージを送信
                queue.put("QUIT")

        print("Testing End.")
    else:
        print("Failed to connect to Sphero.")

    # 描画プロセスの終了を待つ
    drawing_proc.join()

if __name__ == "__main__":
    main()

```

DrawingModule.py
```
import pygame

def drawing_process(queue):
    # Pygame 初期化
    pygame.init()
    WIDTH, HEIGHT = 800, 600
    win = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("Control Circle with Sphero Bolt")

    # 色定義
    WHITE = (255, 255, 255)
    BLUE = (0, 0, 255)

    # 丸の初期位置とサイズ
    circle_x, circle_y = WIDTH // 2, HEIGHT // 2
    circle_radius = 20
    circle_speed = 5

    running = True
    while running:
        # キューからデータを受信
        if not queue.empty():
            data = queue.get()

            # "QUIT" メッセージで終了
            if data == "QUIT":
                running = False
                break

            # ピッチとロールを処理
            pitch = data.get("pitch", 0)
            roll = data.get("roll", 0)

            # 丸の移動量を計算
            if pitch > 5:  # ピッチが正 -> 下方向
                circle_y += circle_speed
            elif pitch < -5:  # ピッチが負 -> 上方向
                circle_y -= circle_speed

            if roll > 5:  # ロールが正 -> 右方向
                circle_x += circle_speed
            elif roll < -5:  # ロールが負 -> 左方向
                circle_x -= circle_speed

            # 画面の境界で丸を止める
            circle_x = max(circle_radius, min(WIDTH - circle_radius, circle_x))
            circle_y = max(circle_radius, min(HEIGHT - circle_radius, circle_y))

        # Pygame 描画処理
        win.fill(WHITE)
        pygame.draw.circle(win, BLUE, (circle_x, circle_y), circle_radius)
        pygame.display.update()

    pygame.quit()

```


実行結果はこちらのようになりました。

つぎのように窓が開き、sphero boltを傾けた方向に丸が移動しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/140c2001-8e55-73dd-89d1-cd3c1b1c38bc.png)

終了時にTracebackが発生しているので、終了命令の手当てする必要がありそうです。
```
git\spherov2.py\spherov2\test>python BoltTest_keyInput.py
pygame 2.6.1 (SDL 2.28.4, Python 3.12.7)
Hello from the pygame community. https://www.pygame.org/contribute.html
Testing Starting...
Connecting to Bolt...
pygame 2.6.1 (SDL 2.28.4, Python 3.12.7)
Hello from the pygame community. https://www.pygame.org/contribute.html
Connected.
Testing Start...
Process Process-1:

Program interrupted by user.
Traceback (most recent call last):
  File "C:\ProgramData\miniforge3\Lib\multiprocessing\process.py", line 314, in _bootstrap
    self.run()
  File "C:\ProgramData\miniforge3\Lib\multiprocessing\process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\nakan\git\spherov2.py\spherov2\test\DrawingModule.py", line 50, in drawing_process
    win.fill(WHITE)
KeyboardInterrupt
Testing End.
```

### まとめ
ジャイロセンサを入力に使ってwindowsの画面上の操作をするプログラミングを実験しました。
spheroV2を使うと応用が広がって楽しそうです。