前回作成した音声合成やら、レゴやら、何やらを組み合わせて「おしゃべりラジコンカー」を作成したときのメモです。
主な材料、環境
ハード: 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)