ラズパイマウスの前方の距離を測定する

測定原理

 発光素子(LED)から出た光は壁に反射して受光素子(フォトトランジスタ)に到達します。この受光された光の強さは距離が遠くなるにつれて弱くなることを利用して距離を測定します。

 この部分の回路図は

回路を知る
 4つあるうちの一つの回路。左側がLEDを点灯させる回路。右側が光の検出回路。RAS17とAD0に繋がっていることが分かります。
 LEDのRAS17~20はP2コネクタのそれぞれ7,11,13,15に繋がっています。
 4つのセンサーからの信号はAD0~AD3に入力されます。このICを制御するのはSPI(Serial Peripheral InterfaceModule)というプロトコルで行います。GPIO11、MISO、MOSI、GPIO8の信号で制御されているのが分かります。
GPIO11は23pin、MISOは21pin、MOSIは19pin、GPIO8は24pinに繋がっています。
ここで用いているRaspberryPiDotNetライブラリにはmcp3208を制御するクラスはありませんが、mcp3008を制御するクラスがあります。この違いはmcs3208は12bit精度でmcs3008は10bit精度の違いだけですので、クラスはそのまま使えます。

メインだけでとにかく動かしてみる

 クラスを作らずに動作確認をしてみます。

メインプログラム
        public static void Main (string[] args)
        {
          GPIOMem[] LED = new GPIOMem[4];
          LED[0] = new GPIOMem (GPIOPins.V2_Pin_P1_07);
          LED[1] = new GPIOMem (GPIOPins.V2_Pin_P1_11);
          LED[2] = new GPIOMem (GPIOPins.V2_Pin_P1_13);
          LED[3] = new GPIOMem (GPIOPins.V2_Pin_P1_15);
          for (int i = 0; i < LED.Length; i++) 
              LED [i].PinDirection = GPIODirection.Out;

          GPIOMem SPICLK = new GPIOMem (GPIOPins.V2_Pin_P1_23);
          SPICLK.PinDirection = GPIODirection.Out;
          GPIOMem SPIMISO = new GPIOMem (GPIOPins.V2_Pin_P1_21);
          SPIMISO.PinDirection = GPIODirection.In;
          GPIOMem SPIMOSI = new GPIOMem (GPIOPins.V2_Pin_P1_19);
          SPIMOSI.PinDirection = GPIODirection.Out;
          GPIOMem SPICS = new GPIOMem (GPIOPins.V2_Pin_P1_24);
          SPICS.PinDirection = GPIODirection.Out;

          double read_adc = 0.0;
          MCP3008 mcp3208;

          while (true) {
            for (int adcnum = 0; adcnum < 4; adcnum++) {
              LED [adcnum].Write (true);
              Thread.Sleep (10);
              mcp3208 = new MCP3008 (adcnum, SPICLK, SPIMOSI, SPIMISO, SPICS);
              read_adc = mcp3208.AnalogToDigital;
              Thread.Sleep (300);
              LED [adcnum].Write (false);
              double millivolts = (Convert.ToDouble (read_adc) / 4096.0) * 3.3;
              Console.Write ("{0}ch{1,6:f3}, ", adcnum, millivolts);
            }
            Console.WriteLine ();
          }
        }
 1 
 2 
 3 GPIOMemの配列を作る
 4 ピン制御のオブジェクトを作る
 5 
 6 
 7 
 8 
 9 出力に設定する
10 
11 クロックのオブジェクト
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 ADコンバータのオブジェクト
28 
29 
30 
31 
32 
33 
34 
35 
36 


ラズパイのADコンバータのクラス

各LEDを光らせ、反射光のレベルをADコンバータで測定するクラスを作ります。
ADコンバータのクラス
  public class ADcon
  {
    static GPIOMem[] LED = new GPIOMem[4];
    static GPIOMem SPICLK = new GPIOMem (GPIOPins.V2_Pin_P1_23);
    static GPIOMem SPIMISO = new GPIOMem (GPIOPins.V2_Pin_P1_21);
    static GPIOMem SPIMOSI = new GPIOMem (GPIOPins.V2_Pin_P1_19);
    static GPIOMem SPICS = new GPIOMem (GPIOPins.V2_Pin_P1_24);
    public static double[] distance = new double[4];

    public ADcon()
    {
      LED[0] = new GPIOMem (GPIOPins.V2_Pin_P1_07);
      LED[1] = new GPIOMem (GPIOPins.V2_Pin_P1_11);
      LED[2] = new GPIOMem (GPIOPins.V2_Pin_P1_13);
      LED[3] = new GPIOMem (GPIOPins.V2_Pin_P1_15);
      for (int i = 0; i < LED.Length; i++) 
        LED [i].PinDirection = GPIODirection.Out;
      SPICLK.PinDirection = GPIODirection.Out;
      SPIMISO.PinDirection = GPIODirection.In;
      SPIMOSI.PinDirection = GPIODirection.Out;
      SPICS.PinDirection = GPIODirection.Out;
    }

    public static void adGet(object state)
    {
      MCP3008 mcp3208;
      for (int adcnum = 0; adcnum < LED.Length; adcnum++) {
        LED [adcnum].Write (true);
        Thread.Sleep (10);
        mcp3208 = new MCP3008 (adcnum, SPICLK, SPIMOSI,
                               SPIMISO, SPICS);
        distance[adcnum] = mcp3208.AnalogToDigital;
        LED [adcnum].Write (false);
      }
    }
  }

 1 
 2 
 3 LEDを入れる配列を作る
 4 制御信号オブジェクトを作る
 5 
 6 
 7 
 8 測定データを入れる配列
 9 
10 コンストラクタ
11 
12 LEDのオブジェクトを作る
13 
14 
15 
16 
17 LEDを出力に設定
18 各制御信号の入出力の設定
19 
20 
21 
22 
23 
24 各ADコンバータの値を読み取る
25 
26 ADコンバータのクラス
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 


距離を測定する



距離測定メインプログラム
    public static void Main(string[] args)
    {
      new ADcon ();
      // 一定間隔ごとに呼び出すメソッドをTimerCallbackとして登録
      TimerCallback timerCallback
                  = new TimerCallback(ADcon.adGet);
      // 100milli秒ごとにtimerCallbackメソッドを呼び出す
      new Timer(timerCallback, null, 0, 100);
      while (true) {
        Thread.Sleep (500);
        for (int i = 0; i < ADcon.distance.Length; i++) {
          double millivolts = (ADcon.distance [i] / 4096.0) * 3.3 * 1000;
          Console.Write ("{0}ch{1,6:f1},{2} ", i, millivolts, ADcon.distance [i]);  
        }
        Console.WriteLine ();
      }
    }
 1 
 2 
 3 ADコンバータのオブジェクトを作る
 4 
 5 コールバックの登録
 6 
 7 
 8 タイマーで定期的に測定する
 9 
10 
11 測定結果を表示する
12 
13 
14 
15 
16 
17