14 直流モーターを動かしてみよう

直流モーターを動かす

BrainPad上部には直流モーターを動かすための出力ピンがあります。これはPWMを用いてモーターのスピードをコントロールすることができます。しかし、回転方向は決まっています。まずは、この原理から勉強していきましょう。

同じ電圧でスピードコントロールする

モーターを動かすほどの電流の電源電圧を変化させるには回路が面倒になるとともに効率が悪くなったりお金がかかったりします。これを克服するには、電源電圧を変えないでモーターの回転速度を変化させる方法を考えることです。
アイデアはコストダウンを起こします。

スピード調節の考え方
モーターと言えば大概の人は子供のころに遊んだマブチモーターをイメージします。実はこれが基本です。
乾電池を一個つなげれば、回転します。二個直列につなげれば高速回転します。三個直列につなげると、さらに高速回転しますが、変な臭いがし始めて壊れるかもしれません。
 今度は乾電池一個よりも遅く回転させるにはどうしたら良いでしょうか?
例えば半分のスピードにするために半分の電圧にすることを考えます。
電圧を下げるために抵抗を直列につなぐと考える人もいるでしょう。使用条件に依存しますが、0.5A流れるとして半分の電圧がモーターにかかるとすると、
2R = 1.5(V)/0.5(A) = 3、 従ってR=1.5Ω、抵抗で消費される電力 P=IV = 0.5*0.75=0.375、従って1.5Ωで1/2Wの抵抗が必要になります。
電流がスピードに比例すると仮定して、3/4のスピードにするには、抵抗値は0.5Ωとなります。
では、連続的にスピードを変えるにはどうするかというと、消費電力が大きい可変抵抗が必要になります。さらにこれをコンピュータでコントロールするには? と考えるとだんだんと複雑になります。従って、大変なことが起こりそうなので、ここでこの延長を考えるのをやめます。

モーターを乾電池1個つなぐ場合を考えます。
  1. 10秒間だけモーターに電流を流します。それなりに回ります。
  2. 次に5秒間だけモーターに電流を流し、後の5秒は流しません。それなりに回り、止まります。
  3. 1秒電流を流し、1秒電流を止めるを10秒間続ける。回ったり止まったりする。
  4. 1/10秒電流を流し、1/10秒電流を止めるを10秒間続ける。動いたり止まったりする暇が無いので、以前より遅く回る。
  5. 30/100秒電流を流し、70/100秒電流を止めるを、繰り返すとさらに遅く回る。
  6. 10/100秒電流を流し、90/100秒電流を止めるを、繰り返すとさらに遅く回る。
  7. 0秒電流を流し、1秒電流を止めるとモーターは止まる。
つまり、電源電圧は同じでも、電流を流す時間でスピードをコントロールすることができることが分かります。これがパルス幅変調(PWM)でモーターのスピードを制御する原理です。
実際には、逆回転ができないと意味が無いので、制御パルス幅のある値より大きい場合と小さい場合で逆回転するように制御します。
 これをハードウェアで行う回路をHブリッジと呼びます。
Hブリッジ
SW1とSW4が閉じ、SW2とSW3が開いていた場合、モーターの+側には電池の+が接続され、モーターの-側には電池の-が接続されて、モーターは正回転します。今度は、SW1とSW4が開き、SW2とSW3が閉じていた場合、モーターの+側には電池の-が接続され、モーターの-側には電池の+が接続されて、モーターは逆回転します。
実際には、HブリッジのスイッチをPWMで高速にON/OFFさせます。これをすべてCPUが行うと大変なので専用IC(集積回路、モータードライバ)を用います。このICにコマンドやデータを送ってモーターの制御を行います。ここでは、この通信にはI2C(アイ スクウェアー シー あるいは アイ ツー シー)のプロトコル(通信規約、通信手順)を用います。
ここでは、このモータードライバとして「DRV8830使用DCモータードライブキット」を用います。

I2Cのデバイスはは7bitのアドレスを持ちます。複数のデバイスを同時に使うには、別のアドレスを付与しなければいけません。ここでは、両方ともオープンの0x64とA0側をLにした0x63の二つのデバイスを用いることにします。


二つのモーター動作チェックプログラム
    public partial class Program
    {
        private void main()
        {           
            DCMotor leftMotor  = new DCMotor(0x63, CPU.E5, CPU.E6);            
            DCMotor rightMotor = new DCMotor(0x64, CPU.E5, CPU.E6);
            int speed = 30;       // 30%のスピード  
            while (true)
            {
                leftMotor.Move(speed);
                Thread.Sleep(1000);
                leftMotor.Stop();
                Thread.Sleep(1000);
                leftMotor.Move(-speed);
                Thread.Sleep(1000);
                leftMotor.Stop();
                Thread.Sleep(1000);

                rightMotor.Move(speed);
                Thread.Sleep(1000);
                rightMotor.Stop();
                Thread.Sleep(1000);
                rightMotor.Move(-speed);
                Thread.Sleep(1000);
                rightMotor.Stop();
                Thread.Sleep(1000);               
            }
        }
    }
    // DRV8830使用DCモーター
    public class DCMotor
    {
        private static  SoftwareI2CBus motor;
        private byte address;
        private byte dir;
        byte[] buf1 = { 0, 0x49 };
        byte[] buf2 = { 0 };
        byte[] faultClear= {0x01,0x80 };//faultレジスタクリア

        int speed;
        public const byte Stanby  = 0x00;
        public const byte Reverse = 0x02;
        public const byte Normal  = 0x01;
        public const byte Brake   = 0x03;
        private const int maxVoltage = 0x40;    
        int wc, rc; // 書き込みバイト、読み込みバイト数

        public DCMotor(int address,Cpu.Pin SCL, Cpu.Pin SDA)
        {
            this.address = (byte)address; // プルアップ抵抗が必要            
            if(motor==null) 
                motor = new SoftwareI2CBus(SCL, SDA);
        }


        public void Move(int speed)
        {
            byte dir;
            if (speed < 0)
            {
                dir = Reverse;
                speed = -speed;
            }
            else dir = Normal;
            speed = speed * maxVoltage / 100;  // スピードの絶対値のパーセント
            int slow = 0x18;
            motor.WriteRead(address, faultClear, 0, 2, buf2, 0, 1, out wc, out rc);

            if (dir != this.dir)
            {
                buf1[1] = (byte)(slow | Stanby);
                motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
                Thread.Sleep(200);
                buf1[1] = (byte)(slow | Brake);
                motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
                Thread.Sleep(200);
                buf1[1] = (byte)(slow | Stanby);
                motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
                Thread.Sleep(200);
                buf1[1] = (byte)(slow | dir);// 目的の方向へ
                motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
                Thread.Sleep(200);
            }
            buf1[1] = (byte)((speed << 2) | dir);
            motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
            this.dir = dir;
            this.speed = speed;
        }
        public void Stop()
        {
            motor.WriteRead(address, faultClear, 0, 2, buf2, 0, 1, out wc, out rc);
            buf1[1] = (byte)(0x18 | Stanby);
            motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
            Thread.Sleep(200);
            buf1[1] = (byte)((0x18) | Brake);
            motor.WriteRead(address, buf1, 0, 2, buf2, 0, 1, out wc, out rc);
            Thread.Sleep(200);
        }
    }
 1 
 2 
 3 
 4 SCLをE5、SDAをE6に接続
 5 左のモーターのオブジェクト
 6 右のモーターのオブジェクト
 7 
 8 
 9 左のモーターを
10 正回転させる
11 1秒待つ
12 止める
13 1秒待つ
14 逆回転させる
15 1秒待つ
16 止める
17 1秒待つ
18 右のモーターを
19 正回転させる
20 1秒待つ
21 止める
22 1秒待つ
23 逆回転させる
24 1秒待つ
25 止める
26 1秒待つ
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 コントロールレジスタ設定用
37 データ読み取り用
38 FAULTレジスタクリア用
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 コンストラクタ
49 
50 
51 
52 I2Cオブジェクト生成
53 
54 
55 
56 パーセントで動かす
57 
58 
59 マイナスの時は逆回転
60 
61 逆方向にする
62 絶対値にする
63 
64 正方向回転
65 パーセントからの変換
66 
67 エラークリア
68 
69 前回と回転方向が異なる場合
70 
71 
72 スタンバイにする
73 200ms待つ
74 
75 ブレーキをかける
76 200ms待つ
77 
78 スタンバイにする
79 200ms待つ
80 
81 遅く回転させる
82 200ms待つ
83 
84 
85 目的のスピードで回転させる
86 回転方向を記憶させる
87 スピードを記憶させる
88 
89 停止させるメソッド
90 
91 エラークリア
92 
93 スタンバイにする
94 200ms待つ
95 
96 ブレーキをかける
97 200ms待つ
98 
99