ブラウザから操作可能なラジコンを作る【２】


## 【２】DCモーターをPWMで速度制御

今回はDCモーターを単純にON/OFFするのと
DualSenseにはアナログトリガーがあるので
モーターの回転スピードを調整する制御まで進めます。

<br></br>
## 目次
* [【１】Raspberry pi の、GPIOをTypescriptから操作](https://qiita.com/Yasukosan/items/1bf9480c10de7d69c2a4)
* [【２】DCモーターをPWMで速度制御](https://qiita.com/Yasukosan/items/291c76c10be135fd7595)
* [【３】サーボモーターを制御](https://qiita.com/Yasukosan/items/e81c9c9d0159b32e5893)
* [【４】DualSenseをブラウザに接続](https://qiita.com/Yasukosan/items/bf3a085145db84a48823)
* [【５】DualSenseの情報をRaspberryPiに飛ばす](https://qiita.com/Yasukosan/items/400883be94751966221a)
* [【６】DualSenseのチャタリング？問題対応](https://qiita.com/Yasukosan/items/7e52609699b4b71196ca)
* [【７-１】RaspberryPiから低遅延で映像を飛ばす](https://qiita.com/Yasukosan/items/98426f1ba4dea4c9ec5f)
* [【７-２】RaspberryPiから低遅延で映像を飛ばす](https://qiita.com/Yasukosan/items/2246c8a32602ca77ace9)
* [【８】ThreeJSでVRもどきを作成](https://qiita.com/Yasukosan/items/e15e8fd002cf49e3d04d)
* [【９-１】iPhoneの加速度から頭の向きをVRに反映](https://qiita.com/Yasukosan/items/9b4333770baea4110361)
* [【９-２】スマホVRゴーグル向けデザインに変える](https://qiita.com/Yasukosan/items/7f1bb7a9d95cb76f8117)
* [【１０】ラジコン本体の製作](https://qiita.com/Yasukosan/items/0d37c1df5b5d6c02257b)
* 【１１】パワーアップとバッテリー問題の解決

## モーター
別件で使用していた
タミヤの[ダブルギアボックス（左右独立4速タイプ）](https://www.tamiya.com/japan/products/70168/index.html)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147738/e6eaaf34-a6b0-4433-9982-71d4af2408b6.png"
    width="320"
/>
これのモーターを使用します。

<img
    src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147738/1b7fd854-e83e-4edf-af59-286f4fe97c56.jpeg"
    width="320"
/>
無くても大丈夫！な記事も見かけたので試してみましたが
私の環境ではRaspberryPIが落ちる場合がありましたので
ノイズ対策に、端子の間に10μF程度のコンデンサを挟んだほうが
多分良いです。


<br></br>

## モータードライバー

DCモーターを制御するのに
モータードライバーが必要になります。

<img
    src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147738/7a76f76a-76ab-4c93-8043-4f34ab9b2c5d.png"
    width="320"
/>
初めは、Arduinoに繋いで使用していた余り物の上画像の物
これを使用する予定でしたが
Arduinoのアナログポートでは使えるのですが
RaspberryPIから出力可能なソフトウェアPWMでは速度の変更が出来ない。
という問題が出たので

<img
    src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147738/3533bd8d-e6fd-4093-bb31-1812a45d8caf.png"
    width="320"
/>

イカしたヒートシンクが付いた、こちらを使います。
L298Nが搭載されたモータードライバーです。


<br></br>
## 電源
ここでは、単3乾電池4本を電源として使います。
モーターが回れば何でもいいので
電源は適当に用意してください。

<img
    src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147738/eb3eea2c-ec61-483e-bea8-f2658a0a9628.jpeg"
    width="320"
/>

本件では、4本差しメガネ端子タイプのよくある電池ボックス。
これにAmazonの格安充電式単3乾電池、4本を挿して利用しています。

<br></br>

## RaspberryPIとモータードライバの接続

モータードライバーと、RaspberryPIの接続は
下記のようにしています。
PWMの出力が可能なポートに指定がありますので
利用するRaspberryPIに合わせて調整してください。

|モータードライバー  |RaspberryPI  |
|---|---|
|IN1  |19番ポート  |
|IN2  |26番ポート  |
|ENA  |12番ポート  |
|IN側 12v  |電源の+  |
|IN側 GND  |電源の-  |
|IN側 GND  |RaspberryPIのGND  |
|IN側 5v  |どこにも繋がない！  |
|OUT1  |モーターの+  |
|OUT2  |モーターの-  |

モータードライバーのIN側のGNDに
電源の-とRaspberryPIのGNDを一緒に繋ぐので注意してください。

画像のように、GND部分に2本接続されます。
<img
    src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147738/cc073242-4998-4dcd-9249-f55419511932.jpeg"
    width="320"
/>

モーター回転方向の制御はプログラム側で行うので
OUT側はモーターの極性はどちらでも構いません


<br></br>
## 試験コード

試験用のコードの全体は下記になります。
前回のサービスに、GPIOのポートをそれぞれ割り振り
pwm書き込み用のメソッドを呼ぶことで
DCモーターを制御します。

```javascript
const gpio = require('./gpio.service')

const MotorPorts = {
    MORTOR_1: 19,
    MORTOR_2: 26,
    MORTOR_PWM: 12,
    MORTOR_POWER: 1,
}

// ポート追加
gpio.addPort({port: MotorPorts.MORTOR_1, mode: 'out'})
gpio.addPort({port: MotorPorts.MORTOR_2, mode: 'out'})
gpio.addPort({port: MotorPorts.MORTOR_PWM, mode: 'out'})

await gpio.initGpio()

// 初期値を出力
console.log(gpio.write(MotorPorts.MORTOR_1, 0))
console.log(gpio.write(MotorPorts.MORTOR_2, 0))
console.log(gpio.pwmWrite(MotorPorts.MORTOR_PWM, MotorPorts.MORTOR_POWER))

// パワーの上昇・加工フラグ
let up = true

// モーター駆動開始
while (true) {

    console.log(gpio.write(MotorPorts.MORTOR_1, 0))
    console.log(gpio.write(MotorPorts.MORTOR_2, 1))
    console.log(gpio.pwmWrite(MotorPorts.MORTOR_PWM, MotorPorts.MORTOR_POWER))

    if (up) {
        MotorPorts.MORTOR_POWER += 10

        if (MotorPorts.MORTOR_POWER >= 150) {
            up = false
        }
    } else {
        MotorPorts.MORTOR_POWER -= 10

        if (MotorPorts.MORTOR_POWER <= 1) {
            break
        }
    }

    // 0.5秒待機
    await new Promise((resolve) => setTimeout(resolve, 500))
}

```

<br></br>

## モーター駆動試験

このコードを動かすと
加速 → 減速 → 停止 と動きます。
が、加速時のトルクが足りないので
弾みをつけてやる必要があります。

<iframe width="560" height="315" src="https://www.youtube.com/embed/a6V1MfFkFXo?si=h9zJXDd3NGvy_gq8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

これで、DCモーターを制御出来ましたので
次回は、ハンドル部分のサーボモーターの制御を行います。

<br></br>
<br></br>
# UZAYA
Uzayaでは、多分仕事を求めています。
何かの役に立ちそうでしたら、是非お知らせを。