前回作成した音声合成やら、レゴやら、何やらを組み合わせて「おしゃべりラジコンカー」を作成したときのメモです。
主な材料、環境
ハード: Raspberry Pi 3 model B、Raspberry Pi Build HAT、F710ワイヤレス ゲームパッド 、レゴ、 ラズパイを固定するメイカープレート(3Dプリンタ出力)、バッテリー、バッテリーとBuild HATをつなぐケーブル 、USBオーディオ変換アダプタ、スピーカー
OS: Raspberry Pi OS (32bit)
レゴ組み立て方メモ
ラズパイ周りの組み立て
次にモーター周りの組み立て
組み合わせる
モーターの補強部品を用意
横と下にくっつける
次にボール関連を用意
これもくっつける
車輪と補強部品を用意
車輪と前の補強をくっつけて
後ろの補強もくっつけたら、完成
Build HATとモーターの接続
ポート | 接続するモーター |
---|---|
A | 右車輪用 Lアンギュラーモーター |
B | 左車輪用 Lアンギュラーモーター |
ゲームパッドでの動かし方
ボタン | 内容 |
---|---|
左アナログスティック | 上下で左車輪回転 |
右アナログスティック | 上下で右車輪回転 |
ボタン | ボイス5再生 |
ボタン | ボイス6再生 |
ボタン | ボイス7再生 |
プログラム
voice_car.pyという名前でラズパイ上に保存して実行。
from io import BytesIO import os import pygame from buildhat import Motor, Hat from gtts import gTTS from pydub import AudioSegment from pygame.locals import * import simpleaudio def create_audio_segment(text, speed=2.0): fp = BytesIO() gTTS(text=text, lang='ja').write_to_fp(fp) fp.seek(0) return AudioSegment.from_file(fp, format="mp3").speedup(playback_speed=speed, chunk_size=50, crossfade=0) def play_audio_segment(seg): simpleaudio.play_buffer( seg.raw_data, num_channels=seg.channels, bytes_per_sample=seg.sample_width, sample_rate=seg.frame_rate ) def get_joy_axes_data(): axis_lx = round(joy.get_axis(0), 3) axis_ly = round(joy.get_axis(1), 3) axis_rx = round(joy.get_axis(3), 3) axis_ry = round(joy.get_axis(4), 3) hat_x = joy.get_hat(0)[0] hat_y = joy.get_hat(0)[1] axes_data = { "L": (axis_lx, axis_ly), "R": (axis_rx, axis_ry), "HAT_X": hat_x, "HAT_Y": hat_y, } print(axes_data) return axis_lx, axis_ly, axis_rx, axis_ry, hat_x, hat_y def init_motor(motor): motor.release = False motor.set_default_speed(100) motor.plimit(1.0) motor.bias(0.5) def get_state(axis_ly, axis_ry): if axis_ly < -0.5 and axis_ry < -0.5: return 1 if axis_ly > 0.5 and axis_ry > 0.5: return 2 if axis_ly < -0.5 and axis_ry > 0.5: return 3 if axis_ly > 0.5 and axis_ry < -0.5: return 4 return 0 os.environ["SDL_VIDEODRIVER"] = "dummy" pygame.init() pygame.joystick.init() joy = pygame.joystick.Joystick(0) joy.init() # 左側のモーターを基準にするので、反対側のモーターは回転方向を反転 rotation_correction_l = 1 rotation_correction_r = -1 hat = Hat() print('Hat voltage = %f' % hat.get_vin()) motor_r = Motor('A') motor_l = Motor('B') init_motor(motor_r) init_motor(motor_l) print('setup audio segment ...') audio_segment_1 = create_audio_segment('全速前進') audio_segment_2 = create_audio_segment('バックします') audio_segment_3 = create_audio_segment('右折します', speed=1.5) audio_segment_4 = create_audio_segment('左折します', speed=1.5) audio_segment_5 = create_audio_segment('どいてくださーい') audio_segment_6 = create_audio_segment('ひいちゃいますよ?') audio_segment_7 = create_audio_segment('安全運転中です!') print('done') old_state = 0 while True: pygame.time.wait(30) for e in pygame.event.get(): if e.type == pygame.locals.JOYAXISMOTION or e.type == pygame.locals.JOYHATMOTION: (axis_lx, axis_ly, axis_rx, axis_ry, hat_x, hat_y) = get_joy_axes_data() if -0.3 <= axis_ly <= 0.3: motor_l.stop() else: motor_l.start(speed=100 * axis_ly * rotation_correction_l) if -0.3 <= axis_ry <= 0.3: motor_r.stop() else: motor_r.start(speed=100 * axis_ry * rotation_correction_r) state = get_state(axis_ly, axis_ry) if old_state != state: if state == 1: play_audio_segment(audio_segment_1) if state == 2: play_audio_segment(audio_segment_2) if state == 3: play_audio_segment(audio_segment_3) if state == 4: play_audio_segment(audio_segment_4) old_state = state if e.type == pygame.locals.JOYBUTTONDOWN: print('BUTTON %d DOWN' % e.button) if e.button == 0: play_audio_segment(audio_segment_5) if e.button == 1: play_audio_segment(audio_segment_6) if e.button == 2: play_audio_segment(audio_segment_7) elif e.type == pygame.locals.JOYBUTTONUP: print('BUTTON %d UP ' % e.button)