ラズパイ5でラジコンを作ります。
その備忘録
ちなみに電子工作的ものはほぼやったことがない状態からのスタートです。
必要なものとか
名称 | 個数 | 参考価格 | 購入先 |
---|---|---|---|
Raspberry Pi 5 8GB | 1 | 14,960 | 秋月電子通商 |
Raspberry Pi 5用公式ケース(黒) | 1 | 1,700 | 秋月電子通商 |
ブレッドボード BB-801 | 1 | 220 | 秋月電子通商 |
DRV8835使用ステッピング&DCモータードライバーモジュール | 1 | 550 | 秋月電子通商 |
楽しい工作シリーズ No.97 ツインモーターギヤーボックス | 1 | 680 | ヨドバシ |
楽しい工作シリーズ No.98 ユニバーサルプレートセット | 1 | 356 | ヨドバシ |
楽しい工作シリーズ No.229 32mm径 スプロケット&クローラーセット | 1 | 357 | ヨドバシ |
KIOXIA microSD 128GB UHS-I Class10 KLMEA128G | 1 | 1,150 | Amazon |
エレコム モバイルバッテリー 15W 5000mAh 5V 3A Type-C USB-A EC-C12WH | 1 | 1,690 | Amazon |
ジャンパーワイヤー 20cm オス メス | 1 | 799 | Amazon |
電池ケース(単3×3個用) | 1 | 358 | Amazon |
はんだごてセット | 1 | ? | 家にあったやつ |
USBケーブル Type-C | 1 | ? | 家にあったやつ |
単3電池 SANYO eneloop | 3 | ? | 家にあったやつ |
プレステ4コントローラー1 | 1 | ? | 家にあったやつ |
Bluetoothスピーカー | 1 | ? | 家にあったやつ |
小汚い木片2 | 1 | ? | 家にあったやつ |
合計 | 22,820 |
インストール
Raspberry Pi Imagerを利用します。
https://www.raspberrypi.com/software/
Raspberry Pi Imagerを起動して以下を選択します。
Raspberry Pi OS (Other) > Raspberry Pi OS Lite (64-bit)
Debian Bookworm のデスクトップなしですね
進めていって、設定をカスタマイズします。
設定を編集するボタンを押下
- SSHの有効化
- ユーザー名
- パスワード
必要に応じてほか項目も設定してください。
僕の環境ではWifiも設定したので、ラズパイにSDカード指して電源コードを入れれば起動、接続できます。
モニタは接続しません。
すべてSSH経由で行います。
# IPアドレスはお使いの環境に合わせてください。
$ ssh pi@192.168.0.131
インストール後
sshでログインし以下の感じで環境を作っています。
やらなくても問題ないものがほとんどですが、Python仮想環境は作っておかないとだめな気がします。
$ echo -e "set nocompatible\nset backspace=indent,eol,start" > ~/.vimrc
$ sudo cp ~/.vimrc /root/
$ sudo apt update
$ sudo apt upgrade
$ sudo apt install python3-pip
$ python3 -m venv --system-site-packages ~/.py_venv/default
$ cp .bashrc .bashrc.bak
$ sed -i "s/#alias ll='ls -l'/alias ll='ls -l'/" .bashrc
$ echo -e '\n# python venv\nexport VIRTUAL_ENV_DISABLE_PROMPT=1\nsource ~/.py_venv/default/bin/activate' >> .bashrc
$ sudo reboot
プレステ4コントローラーをBluetoothで接続
pyPS4Controller
を利用します。
$ pip3 install pyPS4Controller
bluetoothctl
を使って接続します。
ちなみにds4drv
を利用してコントローラーを接続するのは非推奨のようです。
デュアルショック4はSHARE + PSボタン
長押しでペアリングモード (白点滅) になります。
$ bluetoothctl
[bluetooth]# scan on
### Wireless Controller を探す ###
[bluetooth]# scan off
[bluetooth]# pair **:**:**:**:**:**
### ペアリングする際に yes の入力が必要の場合もあります ###
[bluetooth]# trust **:**:**:**:**:**
[bluetooth]# connect **:**:**:**:**:**
[bluetooth]# quit
ちなみに2回目以降は以下で接続できます。
$ bluetoothctl -- connect **:**:**:**:**:**
接続確認用のpythonを作成します。
$ vi ds4test1.py
内容を確認する
from pyPS4Controller.controller import Controller
class MyController(Controller):
def __init__(self, **kwargs):
Controller.__init__(self, **kwargs)
controller = MyController(interface="/dev/input/js0", connecting_using_ds4drv=False)
controller.listen()
$ python3 ds4test1.py
コントローラーをガチャガチャしてなんか表示されればOKだと思います。
スピーカーをBluetoothで接続
スピーカーと書きましたが手持ちになかったので骨伝導イヤホン (Shokz OpenMove) です!
スピーカーをBluetoothで使えるようにする場合、必要なライブラリがあるのでインストールします。
pair
とtrust
はできるのですがconnect
できませんでした。
$ sudo apt install pulseaudio pulseaudio-module-bluetooth
$ pulseaudio --start
$ bluetoothctl
[bluetooth]# scan on
### 僕の環境では OpenMove by Shokz でしたがお使いのスピーカーを探してください ###
[bluetooth]# scan off
[bluetooth]# pair ++:++:++:++:++:++
### ペアリングする際に yes の入力が必要の場合もあります ###
[bluetooth]# trust ++:++:++:++:++:++
[bluetooth]# connect ++:++:++:++:++:++
### 接続されるとプロンプトが変わる ###
[OpenMove by Shokz]# quit
$ aplay /usr/share/sounds/alsa/Front_Center.wav
出ない場合再起動後もう一度aplay
を試してみてください。
$ sudo reboot
実際の運用ではpython pygame.mixer
を利用し再生します。
$ pip3 install pygame
なにか適当な音源 (mp3等) を用意してください。
$ vi soundtest1.py
内容を確認する
import pygame.mixer
import time
pygame.mixer.init()
pygame.mixer.music.load("適当な音源")
pygame.mixer.music.play(-1)
time.sleep(10)
pygame.mixer.music.stop()
$ python3 soundtest1.py
スピーカーから音が出ればOKです。
GPIO ピンマッピング
準備として以下をはんだごてでくっつけます。

以下のコマンドでラズパイのハードウェア情報?を見ることができます。
$ pinout
Description : Raspberry Pi 5B rev 1.0
Revision : d04170
SoC : BCM2712
RAM : 8GB
Storage : MicroSD
USB ports : 4 (of which 2 USB3)
Ethernet ports : 1 (1000Mbps max. speed)
Wi-fi : True
Bluetooth : True
以下略
ブレッドボード上でつなぎました。
ラズパイからみたDCモータードライバーモジュールとの接続です。
| ---- | --- Raspberry pi 5 --- | ---- |
| VCC | 3V3 (1) (2) 5V | |
| | GPIO2 (3) (4) 5V | |
| | GPIO3 (5) (6) GND | GND |
| | GPIO4 (7) (8) GPIO14 | |
| | GND (9) (10) GPIO15 | |
| | GPIO17 (11) (12) GPIO18 | |
| | GPIO27 (13) (14) GND | |
| | GPIO22 (15) (16) GPIO23 | |
| | 3V3 (17) (18) GPIO24 | |
| | GPIO10 (19) (20) GND | |
| | GPIO9 (21) (22) GPIO25 | |
| | GPIO11 (23) (24) GPIO8 | |
| | GND (25) (26) GPIO7 | |
| | GPIO0 (27) (28) GPIO1 | |
| | GPIO5 (29) (30) GND | |
| | GPIO6 (31) (32) GPIO12 | |
| | GPIO13 (33) (34) GND | MODE |
| AIN1 | GPIO19 (35) (36) GPIO16 | AIN2 |
| BIN1 | GPIO26 (37) (38) GPIO20 | BIN2 |
| | GND (39) (40) GPIO21 | |
電池ボックスからみたDCモータードライバーモジュールとの接続です。
| -- | -- Battery Box -- | --- |
| VM | PLUS MINUS | GND |
DCモータードライバーモジュールから見た接続です。
以下のように記述します。
RP: ラズパイ
ML: モーター左
MR: モーター右
BB: 電池ボックス
| -------------- | -- Module -- | ---------- |
| BB:+ | VM VCC | RP:3V3 |
| ML | AOUT1 MODE | RP:GND(34) |
| ML | AOUT2 AIN1 | RP:GPIO19 |
| MR | BOUT1 AIN2 | RP:GPIO16 |
| MR | BOUT2 BIN1 | RP:GPIO26 |
| RP:GND(6) BB:- | GND BIN2 | RP:GPIO20 |
ここまで接続できたらモーターが動くはずです。
gpiozero
というライブラリを利用しテストします。
$ vi gpiotest.py
内容を確認する
from gpiozero import Motor
from time import sleep
PIN_AIN1 = 19
PIN_AIN2 = 16
PIN_BIN1 = 26
PIN_BIN2 = 20
motor_left = Motor(PIN_AIN1, PIN_AIN2)
motor_right = Motor(PIN_BIN2, PIN_BIN1)
print("forward")
motor_left.forward(0.8)
motor_right.forward(0.8)
sleep(1)
print("stop")
motor_left.stop()
motor_right.stop()
# 電池ボックスのスイッチを入れてから実行
$ python3 gpiotest.py
左右のモーターが動けばOKです。
最終調整
部品など組み付けて完成させます。
プログラムは、コントローラーで動かして、音を出して、みたいな感じを完成にしてます。
下画像は以下を組み立てたもの (モーターは外してます)
- 楽しい工作シリーズ No.97 ツインモーターギヤーボックス
- 楽しい工作シリーズ No.98 ユニバーサルプレートセット
- 楽しい工作シリーズ No.229 32mm径 スプロケット&クローラーセット

プログラムの可読性が悪いので一旦以下を置きます。
$ vi MyController.py
内容を確認する
from pyPS4Controller.controller import Controller
class MyController(Controller):
def __init__(self, **kwargs):
Controller.__init__(self, **kwargs)
def on_x_press(self):
pass
def on_x_release(self):
pass
def on_triangle_press(self):
pass
def on_triangle_release(self):
pass
def on_circle_press(self):
pass
def on_circle_release(self):
pass
def on_square_press(self):
pass
def on_square_release(self):
pass
def on_L1_press(self):
pass
def on_L1_release(self):
pass
def on_L2_press(self, value):
pass
def on_L2_release(self):
pass
def on_R1_press(self):
pass
def on_R1_release(self):
pass
def on_R2_press(self, value):
pass
def on_R2_release(self):
pass
def on_up_arrow_press(self):
pass
def on_up_down_arrow_release(self):
pass
def on_down_arrow_press(self):
pass
def on_left_arrow_press(self):
pass
def on_left_right_arrow_release(self):
pass
def on_right_arrow_press(self):
pass
def on_L3_up(self, value):
pass
def on_L3_down(self, value):
pass
def on_L3_left(self, value):
pass
def on_L3_right(self, value):
pass
def on_L3_y_at_rest(self):
pass
def on_L3_x_at_rest(self):
pass
def on_L3_press(self):
pass
def on_L3_release(self):
pass
def on_R3_up(self, value):
pass
def on_R3_down(self, value):
pass
def on_R3_left(self, value):
pass
def on_R3_right(self, value):
pass
def on_R3_y_at_rest(self):
pass
def on_R3_x_at_rest(self):
pass
def on_R3_press(self):
pass
def on_R3_release(self):
pass
def on_options_press(self):
pass
def on_options_release(self):
pass
def on_share_press(self):
pass
def on_share_release(self):
pass
def on_playstation_button_press(self):
pass
def on_playstation_button_release(self):
pass
MyControllerを継承し以下を作成
$ vi ctrl.py
内容を確認する
from MyController import MyController
from gpiozero import Motor
import pygame.mixer
import os
import sys
class Ctrl(MyController):
PIN_AIN1 = 19
PIN_AIN2 = 16
PIN_BIN1 = 26
PIN_BIN2 = 20
BASE_SPEED = 0.3
L3_RESTING = True
R3_RESTING = True
SOUND_DIR = ""
isBacksound = False
motor_left = None
motor_right = None
def __init__(self, **kwargs):
MyController.__init__(self, **kwargs)
self.motor_left = Motor(self.PIN_AIN1, self.PIN_AIN2)
if isinstance(self.motor_left, Motor) == False:
print("Motor left is Not Ready")
sys.exit()
self.motor_right = Motor(self.PIN_BIN2, self.PIN_BIN1)
if isinstance(self.motor_right, Motor) == False:
print("Motor right is Not Ready")
sys.exit()
self.SOUND_DIR = os.path.dirname(__file__) + "/"
pygame.mixer.init()
def _calcSpeed(self, value):
speed = value / 65534 + self.BASE_SPEED
return round(speed, 3)
def on_L3_up(self, value):
if value < -5000:
self.L3_RESTING = False
speed = self._calcSpeed(value * -1)
self.motor_left.forward(speed)
print("Left forward: {}".format(speed))
if self.isBacksound == False:
self.isBacksound = True
pygame.mixer.music.load(self.SOUND_DIR + "sound0.mp3")
pygame.mixer.music.play(-1)
else:
self.on_L3_y_at_rest()
def on_L3_down(self, value):
if value > 5000:
self.L3_RESTING = False
speed = self._calcSpeed(value)
self.motor_left.backward(speed)
print("Left backward: {}".format(speed))
if self.isBacksound == False:
self.isBacksound = True
pygame.mixer.music.load(self.SOUND_DIR + "sound0.mp3")
pygame.mixer.music.play(-1)
else:
self.on_L3_y_at_rest()
def on_L3_y_at_rest(self):
if self.L3_RESTING == False:
self.L3_RESTING = True
print("Left Speed 0")
self.motor_left.stop()
def on_R3_up(self, value):
if value < -5000:
self.R3_RESTING = False
speed = self._calcSpeed(value * -1)
self.motor_right.forward(speed)
print("Right forward: {}".format(speed))
else:
self.on_R3_y_at_rest()
def on_R3_down(self, value):
if value > 5000:
self.R3_RESTING = False
speed = self._calcSpeed(value)
self.motor_right.backward(speed)
print("Right backward: {}".format(speed))
else:
self.on_R3_y_at_rest()
def on_R3_y_at_rest(self):
if self.R3_RESTING == False:
self.R3_RESTING = True
print("Right Speed 0")
self.motor_right.stop()
def on_x_release(self):
self._doSpeak(self.SOUND_DIR + "sound1.mp3")
def on_triangle_release(self):
self._doSpeak(self.SOUND_DIR + "sound2.mp3")
def on_circle_release(self):
self._doSpeak(self.SOUND_DIR + "sound3.mp3")
def on_square_release(self):
self._doSpeak(self.SOUND_DIR + "sound4.mp3")
def _doSpeak(self, path):
self.isBacksound = False
pygame.mixer.music.stop()
pygame.mixer.music.load(path)
pygame.mixer.music.play(1)
controller = Ctrl(interface="/dev/input/js0", connecting_using_ds4drv=False)
controller.listen(timeout=60)
実行する前に音ファイルを置きます。
仮に sound0.mp3
sound1.mp3
sound2.mp3
sound3.mp3
sound4.mp3
として利用しています。
$ python3 ctrl.py
コントローラー、左スティック、右スティック、で前後左右、
マル、バツ、サンカク、シカクで音がなればOKです。
実ははまった点
1. 電力不足
はじめに組んだ際に発生した問題。
実は最初の段階では、単3電池を2つで動かしていました。
ラズパイと電源、モーターを接続しいざスタートしたらモーターから異音が、、
motor_left.forward(0.8) motor_right.forward(0.8)
このあたりかと思って、値を上げたり下げたりしてもだめ、テスターを使って通電確認したりしても問題なし。
その後モーターを一つにしたら動く。
調べてみたらどうも電力が足りない?と考え
- エレクラフトシリーズ No.28 75028 低回転型 130モーター
これを注文し取り付け。
結果的に問題なく動作。
ラジコン本体の組付け、コントローラー接続、スピーカー接続、動いた!
2. パワー不足
低回転型に変えたその後...
動いたのですが、曲がれない。。パワー不足か?
実はこの時点では
- 楽しい工作シリーズ No.150 単3電池ボックス(1本用×2・逆転スイッチ付)
がついていました。
で、なんかムカついたので、やっぱりモーターを最初のやつに戻した上で電池一本増やすことにした。(これが問題あるのかどうかはよくわかりませんw)
合計3Vから4.5Vへ。ただ、エネループなので公称値で3.6Vですかね。 (実測は4Vぐらい出てましたが。。)
ミニ四駆を3.7Vで動かしてるYoutubeとか見たことがあったのでいけるんじゃないのかな程度でやってみました。
結果、動いたし曲がりました。
で、今に至ります。
-
ドリフト気味 ↩
-
買い足すのが面倒で工作したため、、
楽しい工作シリーズ No.157 ユニバーサルプレート (2枚セット) がよかったかなとか
https://www.tamiya.com/japan/products/70157/index.html
楽しい工作シリーズ No.253 ユニバーサルピラーセットも欲しかったなとか
https://www.tamiya.com/japan/products/70253/index.html ↩