0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラズパイ5でラジコンを作る

Last updated at Posted at 2024-09-06

ラズパイ5でラジコンを作ります。

radicon.jpg

その備忘録
ちなみに電子工作的ものはほぼやったことがない状態からのスタートです。

必要なものとか

名称 個数 参考価格 購入先
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
内容を確認する
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で使えるようにする場合、必要なライブラリがあるのでインストールします。
pairtrustはできるのですが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
内容を確認する
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 ピンマッピング

準備として以下をはんだごてでくっつけます。

  1. DRV8835使用ステッピング&DCモータードライバーモジュール
  2. モーターとジャンパーワイヤー x 23
  3. 電池ボックスとジャンパーワイヤー3

汚い

以下のコマンドでラズパイのハードウェア情報?を見ることができます。

$ 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
内容を確認する
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
内容を確認する
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
内容を確認する
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とか見たことがあったのでいけるんじゃないのかな程度でやってみました。
結果、動いたし曲がりました。
で、今に至ります。

  1. ドリフト気味

  2. 買い足すのが面倒で工作したため、、
    楽しい工作シリーズ No.157 ユニバーサルプレート (2枚セット) がよかったかなとか
    https://www.tamiya.com/japan/products/70157/index.html
    楽しい工作シリーズ No.253 ユニバーサルピラーセットも欲しかったなとか
    https://www.tamiya.com/japan/products/70253/index.html

  3. ジャンパーワイヤーは片側を切って利用 2

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?