実験2 サーボモータ


ここで行うこと。


サーボモータは左の写真のようなもので
すでにJ-Botに組み込まれています。


実験2-1 サーボモータを接続する

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

モーターを乾電池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)でモーターのスピードを制御する原理です。
実際には、逆回転ができないと意味が無いので、制御パルス幅のある値より大きい場合と小さい場合で逆回転するように制御します。


サーボモータはパルス幅変調の信号で動きを制御することができます。netduinoMiniは、P12,13,14,15のI/Oピンを用いてこの信号波形をプログラムで作ることができます。この実験ではピンP12を用います。最初にnetduinoMiniは20msの間P12を0V(low)の電圧に設定します。次に1msの間P12を5V(high)の電圧にします。そして、また20msのlowの出力の期間が始まります。そして次は1msと下図のように続いていきます。
パルス列は1msの間highで20msの間lowとなります。これは実験1の音発生に用いた対称のパルス(duty cycle 50%)と異なります。実験1場合、オブジェクトは音発生に典型的に用いられる正弦波をシミュレート(模擬)しています。

この場合、highの時間はサーボモータの動作をコントロールするのに重要な要素で、通常、パルス幅として呼びます。この例では1msのパルス幅で動いています。ある時間lowからhigh(0Vから5V)に行くパルスをポジティブパルスと言います。ネガティブパルスはhighパルスがlowに落ち、静止状態になります。パルス列はdutyとかduty cycleという専門用語で表されます。

重要点
パルス幅はサーボモータをコントロールします。パルス間のlowの時間はサーボモータの機能を損なわないようにするには10msから40msの範囲で使えます。


右のサーボモータはP12、左のサーボモータはP13となっています。
右図のようにP12、P13は専用のソケットがありますからそこに接続してください。左右を間違えたり、挿入する方向を間違えないようにしましょう。コードの色を確認しながら挿入してください。


課題2-1-1

次のプログラムの動作を確認上のし、緑の1100の数字を変えて高速に逆回転するようにしなさい。
ServoMotorクラスは、中身はPWMクラスでありパルス幅変調を行っています。

高スピードで右のサーボモータを動かす
/**
 * 高スピードで右のサーボモータを動かす
 */

namespace BoeBotServo1
{
    public class Program
    {
        public static void Main()
        {
            ServoMotor Rightsv = new ServoMotor(CPU.P12);
            Rightsv.update(1100, 20000);
            Rightsv.start();
            CPU.delay(1000);     /* 1秒間走らせる */
            Rightsv.stop();      /* 止める         */
            Rightsv.Dispose();
        }
    }
}


次に、青のCPU.P12をCPU.P13に変えて高速に正回転、逆回転するようにしてみなさい。

課題2-1-2
下のプログラムで、緑の***部分に課題2-1-1で行った数字を入れて高速に前進させなさい。

両方のサーボを高スピードで動かし、前進させる
/**
 * 両方のサーボを高スピードで動かし、前進させる
 */
namespace BoeBotServo2
{
    public class Program
    {
        public static void Main()
        {
            ServoMotor Rightsv = new ServoMotor(CPU.P12);
            ServoMotor Leftsv  = new ServoMotor(CPU.P13);
            Rightsv.update(*** , 20000);
            Leftsv.update(*** , 20000);
            Rightsv.start();
            Leftsv.start(); 
            CPU.delay(5000);     /* 5秒間走らせる */
            Rightsv.stop();      /* 止める        */
            Leftsv.stop(); 
            Rightsv.Dispose();
            Leftsv.Dispose();
        }
    }
}


課題2-1-3
  1. 高速に後進するようにしなさい。

  2. 両方のサーボが止まる値を求めなさい。
    ヒント:for文とDebug.Printを用いる。
この実験でとにかく、前後に動かすことができました。

課題2-1-4
スピードコントロールするために、サーボモータの特性を測定します。 予想としては次の図のようになるはずです。

車輪には8個の穴があり、その穴には白い紙が貼ってあるようになっています。車輪の車体側にはQTIという名前の光センサがあり、車輪の黒と紙の白の変化で車輪がどのくらい動いたが分かるようになっています。下のプログラムでは3回転にかかる時間を測定しています。
コネクタには、白赤黒の3つの接続があり、黒はグラウンド(0V)、白が電源(+5V)、赤が信号となっている。従って次のプログラムを実行するには赤の信号をP2に接続します。また、左のセンサーの信号はP3に接続します。
注意:コードの色は常識と異なるので配線を間違えないようにすること
配線を間違えるとQTIもロボット自体も壊れる可能性がありますから、慎重に行うこと。
上記写真のように両方とも配線せずに片方ずつ行います。両方とも配線してから間違えると、一気に全部壊れるからです。
さらに、何が間違っているか特定できないからです。従って、何でも少しずつチェックしながら進めていく習慣をつけましょう。

右側のQTIをチェックする
/*
 * LEDはP10につなげる
 * IRの信号(赤)はP2につなげる
 * IRの電源は白
 * IRのグラウンドは黒
 */ 
namespace checkIR
{
    public class Program
    {
        public static void Main()
        {
            OutputPort led = new OutputPort(CPU.P10, false);
            AnalogInput MotorSpin = new AnalogInput(CPU.P2);
            while (true)
            {
                if (MotorSpin.Read() > 1000) led.Write(true);
                else led.Write(false);
            }
        }
    }
}


右側の車輪を手で回すとそれに応じてLEDがチカチカするはずです。しなかった場合は、なんでだろうと考える前に電源を切ること。
間違ったまま電源を入れ続けるとダメージが増えます。 右側のセンサーの正常を確認したら、左側も確認してください。

サーボモータの特性を測定する
namespace BoeBotServoCalibrate
{
    public class Program
    {
        public static void Main()
        {
            AnalogInput RightSpin = new AnalogInput(CPU.P2);
            ServoMotor Rightsv = new ServoMotor(CPU.P12);
            DateTime start = DateTime.Now;          // 回転数測定用
            DateTime rStart = start;                // 回転停止監視用
            TimeSpan diff = start - DateTime.Now;
            Rightsv.update(1300, 20000);
            Rightsv.start();
            int sign = 1;
            for (uint highTime = 1350; highTime <= 1650; highTime += 10)
            {
            next:
                Rightsv.update(highTime, 20000);
                start = DateTime.Now;               
                Boolean rState = false;
                int count = 0; 
                while (count < 24)               // 3回転
                {
                    int rSpin = RightSpin.Read();
                    if (rSpin < 500 && rState)
                    {
                        rStart = DateTime.Now;
                        rState = !rState;
                        count++;
                    }
                    else if (rSpin >700 && !rState)
                    {
                        rState = !rState;
                    }
                    diff = DateTime.Now - rStart;
                    if (diff.Ticks > 100000000L)
                    {
                        Debug.Print(highTime + "\t" + 10000000000L);
                        highTime += 10;
                        Rightsv.update(highTime, 20000);
                        rStart = DateTime.Now;
                        sign = -1;
                        goto next;
                    }
                }
                diff = DateTime.Now - start;
                long sa = diff.Ticks*sign;
                Debug.Print(highTime+"\t"+sa);
            }
            Rightsv.stop();      // 止める
            Rightsv.Dispose();      
        }
    }
}


上記の実験より、サーボーモータへの値対スピードのグラフを描きなさい。
上記の実験は右のサーボモータの特性を測定しています。左側の特性も採りなさい。グラフより最大スピードで、速度を比例的に変えられる点を求めなさい。

エクセルで計測データを二つの列に分離する方法
  1. 文字列を分けたいセルを選択します。
  2. 「データ」をクリックします。
  3. 「区切り位置」をクリックします。
参考:スピードについて
rpm(アールピーエム、revolutions per minute、回転毎分)は、1分間に何回、同じ事象への回帰を繰り返すかを示す周波数の単位のことです。
この実験で採ったデータは3回転にかかる時間で、単位は0.1μ秒です。
3回転 : x(0.1μs) = n 回転 : 60秒
xは測定したデータ、nは求めるrpm。
この式から、各データからrpmを求め、グラフを描く。


実験2-2 基本的なサーボモータのクラス

以前の例題はServoMotorオブジェクトを操作していましたが、これは幾つかの欠点があります。
  1. パルス幅を設定する値を知らないといけないこと。
  2. Boe-Botを前進させる値が、左右で多分異なること。
  3. 左右で停止点が多分異なること。
そこで、単純なプログラムはこの辺で終わりにして、サーボモータをコントロールするクラスを作ります。ここで行うのは非常に基本的な版で、だんだんと改良していきます。ですから、これはBoe-Botをいかに簡単にコントロールできるかを示します。
1行めにあるnamespace BoeBotLibはこのプログラムはBoeBotLib名前空間に登録することを意味しています。BoeBotLibはBoe-Botを管理するライブラリ群の名前空間です。
ServoMotorクラスはPWMクラスから継承されています。

車輪サーボをコントロールするクラス
/**
 * 車輪サーボをコントロールするクラス
 * 
 * フリーランニングの車輪サーボに対するPWMサポートを操作する
 * start()で動作を開始し、stop()で停止させる
 */

namespace BoeBotLib
{
    public class BasicWheelServo
    {
        public int forward;
        public int center;
        public int backward;
        public int low;
        public ServoMotor sv;

        /**
         * PWMを用いて車輪サーボコントロール・オブジェクト
         * を設定する。単位はPWMの時間幅の単位である。
         *
         *入力:int pin: PWM信号を発生させるピン(例えば CPU.P12)
         *     int forward: 前進に対するパルス幅
         *     int center : 停止に対するパルス幅
         *     int backward:後進に対するパルス幅
         */
        public BasicWheelServo(Cpu.Pin pin, int forward, int center, int backward, int low)
        {
            sv = new ServoMotor(pin);
            this.forward = forward - center;
            this.center = center;
            this.backward = center - backward;
            this.low = low;
        }

        /**
         * 前進/後進(+/-)に対する車輪スピードを設定する
         *
         * 入力:int percent: 相対スピードのパーセント値
         */
        public void move(int percent)
        {
            // sv.move(percent, forward, center, backward);
            if (percent == 0)
            {
                stop();
            }
            else
            {
                sv.update((uint)(center + ((((percent > 0) ? forward : backward) * percent) / 100)), (uint)low);
                sv.start();

            }
        }
        public void stop()
        {
            sv.stop();
        }
    }
}


問題2-2-1
  1. PWMクラスで使うことのできるメソッドを調べ、その機能を説明しなさい。
    参考:API Reference for .NET Micro Frameworkを調べる。

  2. オブジェクト変数(インスタンス変数)はどれか。

  3. moveメソッドはどのような値でサーボを動かしているか。

  4. ? : の意味は理解しているか。これを例を挙げて説明しなさい。


VisualStudio2010でプロジェクトを作ると自動的にProgram.csが出来ます。メインメソッド名はMain()です。通常ここでオブジェクトを作って実行させますが、分かりやすくするためと、Main()の中で初期設定をするためにオブジェクト上にもう一つmain()を作って、そこで一般の処理するようにします。そのためにpartial classの設定をします。下のプログラムでは初期設定はありません。
BasicWheelServoTest1のメインプログラム
namespace BasicWheelServoTest1
{
    public partial class Program
    {
        public static void Main()
        {
            new Program().main();
        }
    }
}


下のプログラムは、BasicWheelServoクラスを利用する本当のメインプログラムです。このプログラムはmain.csというファイル名で作ってください。
forward,center,backwardは以前にグラフから求めた数字を代入してください。

車輪サーボをコントロールするクラスのテストプログラム
namespace BasicWheelServoTest1
{
    /**
     * 車輪サーボコントロールクラスのテストプログラム
     * 
     * Boe-Botで自由回転車輪に対するPWMサポートを扱う
     * start()で動きを開始し、stop()を用いて停止する。
     */
    public partial class Program
    {
        public void main()
        {
            BasicWheelServo leftWheel =
              new BasicWheelServo(
                      CPU.P13      // pin
                    , ***         // forward
                    , ***         // center
                    , ***         // backward
                    , 20000       // low
                    );
            BasicWheelServo rightWheel =
              new BasicWheelServo(
                      CPU.P12      // pin
                    , ***         // forward
                    , ***         // center
                    , ***         // backward
                    , 20000       // low
                    );

            leftWheel.move(100);
            rightWheel.move(100);

            CPU.delay(1000);   // 1秒間走る

            leftWheel.move(-100);
            rightWheel.move(-100);

            CPU.delay(1000);   // 1秒間走る

            leftWheel.stop();
            rightWheel.stop();
        }
    }
}


問題2-2-2



  1. スピードのグラフより誤差のグラフを求めなさい。

実際の値 - 予想値
誤差[%]=-----------------×100%
予想値
ヒント

実験1へ戻る   実験3へ

実験2終わり