フリーランスの暇な時に書く技術メモ
Genki Tech

ラズパイとNode.jsでDCモーターをPWM制御してみる

ラズパイとNode.jsでDCモーターをPWM制御してみる

以前の記事では、ポテンショメータから値を取得することが出来ました。

前回の記事では、ラズパイを Web から制御して L チカするところまで出来ました。 今回はポテンショメーター(可変抵抗器)の値を入力して画面に表示するところまで実装したいです。前回の Next.js の Web サイトをベースに追記していくため必要であればそちらもご覧ください…

今回はその値を使用して、PWM制御してDCモーターの回転速度をコントロール、と行きたいところですが、とりあえずLEDの明るさ制御をしてみたいと思います。

Next.jsのバックグラウンドメインループに実装しますのでそのあたりは以下もご覧ください。

最近ラズパイをいじっていて、Web画面をNext.jsで実装しつつ、センサーやモーターを制御するサーバーのバックグラウンド処理を実装したくなりました。案外まとまった情報が無かったので載せてみます。(ラズパイには触れません) server.ts と周辺の実装もtypescript…

PWMでDCモーターの速度コントロールをするとは

ラズパイの出力はON・OFFのデジタルのため、途中の電圧が基本的にありません。そのためONとOFFを超高速で入れ替えつつそれぞれの時間をコントロールすることで中間を表現します。

今回はraspi-pwmと言うライブラリが使いやすそうだったのでインストールします。

npm i -S raspi-pwm

ハードウェア

今回、DCモーターのコントロールに L293D と言う IC を使用します。

DCモーターを直接ラズパイのPWMでコントロールすると、3.3Vが限度ですし、コイルの逆起電力などが発生して良くないです。トランジスタで別で電力を確保しても、逆起電力の回避や回転方向の制御を基盤上で組むのはめんどいので、その辺を請け負ってくれる IC の様です。データシートはこんな感じ。

image-20211008194401196

これが読めれば苦労は無いですが、読めないので色々調べました。

  • Vcc2がモーター用電源。8番に接続します。今回は外部電源で7.4Vを接続。

  • Vcc1はIC電源。ラズパイの5V電源に接続します。

そのほかは、今回モーターは一つしか使わないので左側だけ使用します。

  • 1にはPWM信号を入力。

  • 2と7が、ONーOFF、OFFーON のどちらかの場合に、モーターは右回転したり左回転したりします。

  • 4と5はグランドに接続。(Vcc1のグランドでもいいのかな?よく分からなかったので高電圧側のグランドVcc2に接続)

全体回路はこんな感じ(丁寧に説明する気がなくてすみません)

image-20211008194915018

今回大事なのは、右下のブレッドボードのモータとその上にあるICの配線です。

回転方向制御の端子はどのGPIOにつないでもいいんですが、PWM用のハードウェア制御できるようにGPIO19につないでいます。

DC電源について

今回は試しにラズパイの電源をUSBではなく端子から入力するようにしました。

右上からDC12Vが入り、上下のブレッドボードは上が5.1V、下が7.4Vに調整したものを使用しています。

ラズパイの電源って5V入力だとうまく起動しないので5.1にしています。下の7.4Vはそのうちリポバッテリ―などを使うことを想定してとりあえず7.4にしてあります。

ソフトウェアの実装

以前の記事で書いたメインループの中に以下の実装を行いました。

ポテンショメータの中心を停止状態とし、左右に回すと加速する計算をしています。

import i2c from 'i2c-bus'
import GPIO from 'rpi-gpio';
import { PWM } from 'raspi-pwm';

const DEVICE_NUMBER = 1;
const TARGET_IC_ADDR  = 0x4b;
const TARGET_IC_PORTS  = [0x84,0xc4,0x94,0xd4,0xa4,0xe4,0xb4,0xf4]; // A0~
const PIN_GPIO_5 = 29;
const PIN_GPIO_6 = 31;

// 方向制御用端子指定
GPIO.setup(PIN_GPIO_5, GPIO.DIR_OUT); // GPIO5
GPIO.setup(PIN_GPIO_6, GPIO.DIR_OUT); // GPIO6
// 回転数制御用端子指定
const motor = new PWM('GPIO19');

export class Main{
    meterDevice: i2c.I2CBus;    
    constructor(){
        // デバイスオープン
        this.meterDevice = i2c.openSync(DEVICE_NUMBER);
    }
    // ポテンショメーターから値を読み取り
    readMeter (num: number) {
        // 読み取りポート指定
        var writeBuf = Buffer.from([TARGET_IC_PORTS[num]]);
        this.meterDevice.i2cWriteSync(TARGET_IC_ADDR, writeBuf.length, writeBuf);
        // 読み取り実行
        var readBuf = Buffer.alloc(0x01);
        this.meterDevice.i2cReadSync(TARGET_IC_ADDR, readBuf.length, readBuf);
        return readBuf[0];
    }    
    public Frame() {
        // ポテンショメーター値の読み取り
        const meter = this.readMeter(0);
        // パワーと方向に分解
        const value = meter - 128;
        const power = Math.abs(value / 128.0);
        // パワーをPWMで制御
        motor.write(power * 1.0);
        // 方向をGPIOで制御
        if(value > 10 ){
            GPIO.write(PIN_GPIO_5, false);
            GPIO.write(PIN_GPIO_6, true);
        } else if( value< -10) {
            GPIO.write(PIN_GPIO_5, true);
            GPIO.write(PIN_GPIO_6, false);
        } else {
            GPIO.write(PIN_GPIO_5, false);
            GPIO.write(PIN_GPIO_6, false);
        }
    }
}

結果

いい感じに回転方向と速度制御が出来ました。

そろそろサーボモーターやステッピングモーターにもトライしてみたいです。(サーボはPWMするだけだからパスでもいいかな。。。)