背景
pygameを使うとゲームパッドの入力を使用できるようです。
ここではdualsenseを使ってSphero boltを操作してみます。
Scratch
Sphero IDEにはゲームパッドを使用する機能は見つかりませんでした。
(もしかするとbluetoothなどでゲームパッドつなげたらドライブモードで使えるのかも)
spheroV2
chatGPT先生と相談しながら作成しました。
12/21と同様に、bluetoothの通信とpygameの並列化が衝突するようだったので、入力内容をqueingして逐次spheroを操作する方式にしました。
import pygame
import sys
import time
import threading
from queue import Queue
from spherov2 import scanner
from spherov2.sphero_edu import SpheroEduAPI
from spherov2.types import Color
# コントローラの入力処理スレッド
def controller_input_process(queue):
pygame.init()
pygame.joystick.init()
if pygame.joystick.get_count() == 0:
print("No controller connected.")
sys.exit()
controller = pygame.joystick.Joystick(0)
controller.init()
print(f"Controller connected: {controller.get_name()}")
# 直前の値を保存する変数
last_speed = None
last_heading_change = None
speed_threshold = 0.1 # スピードの閾値
heading_threshold = 0.2 # 方向変更の閾値
try:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
queue.put(("exit", None))
return
# R2 トリガー値を取得
r2_trigger = controller.get_axis(5) # R2 トリガー
if r2_trigger > speed_threshold:
speed = r2_trigger * 30 # 最大速度を30に制限
else:
speed = 0 # トリガーが離されると停止
# 左スティックの X 軸値を取得
left_stick_x = controller.get_axis(0)
if abs(left_stick_x) > heading_threshold:
heading_change = left_stick_x * 10 # 感度を調整
else:
heading_change = 0
# 速度と方向のどちらかが閾値を超えていて、直前の値と異なる場合のみキューに追加
if (abs(speed - (last_speed or 0)) > speed_threshold or
abs(heading_change - (last_heading_change or 0)) > heading_threshold):
queue.put(("move", (speed, heading_change)))
last_speed = speed
last_heading_change = heading_change
# デバッグ用出力
print(f"R2 (raw): {r2_trigger:.2f}, Speed: {speed:.1f}, Left Stick X: {left_stick_x:.2f}, Heading Change: {heading_change:.2f}")
# フレームレート調整
time.sleep(0.03)
except KeyboardInterrupt:
print("\nController process interrupted by user.")
queue.put(("exit", None))
except Exception as e:
print(f"An error occurred in controller process: {e}")
# Sphero Bolt の制御スレッド
def sphero_control_process(queue):
print("Connecting to Sphero Bolt...")
toy = scanner.find_BOLT()
if toy is None:
print("Failed to connect to Sphero Bolt.")
return
with SpheroEduAPI(toy) as droid:
print("Connected to Bolt.")
droid.reset_aim()
droid.set_stabilization(True)
droid.set_front_led(Color(r=5, g=5, b=5)) # LED を白に設定
speed = 0
heading = 0
try:
while True:
# キューから操作内容を取得
if not queue.empty():
action, data = queue.get()
if action == "exit":
break
elif action == "move":
speed, heading_change = data
heading += heading_change
heading %= 360 # 方向は 0〜360 度に制限
# Sphero Bolt を制御
droid.set_speed(int(speed))
droid.set_heading(int(heading))
# デバッグ用出力
print(f"Speed: {speed:.1f}, Heading Change: {heading_change:.2f}, Heading: {heading:.1f}")
# フレームレート調整
time.sleep(0.03)
except KeyboardInterrupt:
print("\nSphero control process interrupted by user.")
except Exception as e:
print(f"An error occurred in sphero control process: {e}")
# メインスクリプト
if __name__ == "__main__":
queue = Queue()
# コントローラの入力処理スレッドを起動
controller_thread = threading.Thread(target=controller_input_process, args=(queue,))
controller_thread.daemon = True
controller_thread.start()
# Sphero Bolt の制御スレッドを起動
sphero_thread = threading.Thread(target=sphero_control_process, args=(queue,))
sphero_thread.daemon = True
sphero_thread.start()
try:
# メインスレッドでスレッドが終了するのを待つ
while controller_thread.is_alive() and sphero_thread.is_alive():
time.sleep(0.03)
except KeyboardInterrupt:
print("\nMain program interrupted by user.")
finally:
print("Exiting...")
pygame.quit()
実行結果はこちらのようになりました。
残念ながらyawの変更がカクカクになったので、要修正です。
終了後に接続したままになったので、終了の工夫が必要です。
git\spherov2.py\spherov2\test>python BoltTest_ds.py
pygame 2.6.1 (SDL 2.28.4, Python 3.12.7)
Hello from the pygame community. https://www.pygame.org/contribute.html
Connecting to Sphero Bolt...
Controller connected: DualSense Wireless Controller
Connected to Bolt.
R2 (raw): 0.51, Speed: 15.4, Left Stick X: 0.04, Heading Change: 0.00
R2 (raw): 1.00, Speed: 30.0, Left Stick X: 0.04, Heading Change: 0.00
R2 (raw): 0.87, Speed: 26.2, Left Stick X: 0.04, Heading Change: 0.00
Speed: 15.4, Heading Change: 0.00, Heading: 0.0
R2 (raw): -0.24, Speed: 0.0, Left Stick X: 0.04, Heading Change: 0.00
Speed: 30.0, Heading Change: 0.00, Heading: 0.0
Speed: 26.2, Heading Change: 0.00, Heading: 0.0
Speed: 0.0, Heading Change: 0.00, Heading: 0.0
R2 (raw): 0.34, Speed: 10.2, Left Stick X: 0.07, Heading Change: 0.00
R2 (raw): 1.00, Speed: 30.0, Left Stick X: 0.06, Heading Change: 0.00
Speed: 10.2, Heading Change: 0.00, Heading: 0.0
...
R2 (raw): -1.00, Speed: 0.0, Left Stick X: -0.89, Heading Change: -8.90
R2 (raw): -1.00, Speed: 0.0, Left Stick X: 0.15, Heading Change: 0.00
Speed: 0.0, Heading Change: -8.90, Heading: 117.4
Speed: 0.0, Heading Change: 0.00, Heading: 117.4
Main program interrupted by user.
Exiting...
まとめ
pygameを使い、dualsenseを使ってspheroを操作をするプログラミングを実験しました。
左右のパッドで左右のタイヤを動かすようにするとか、一つのパッドで前後左右に動かすとか、工夫すると面白そうです。