7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Nerves】割り込み処理の開始が600usだった

Posted at

はじめに

手元にあったMPU6050(ジャイロ、加速度センサ)をNervesでコントロールして値の読み取りを行ってみました。

MPU6050とは

X-Y-Z軸それぞれの角速度を測定するジャイロセンサと、X-Y-Z軸方向の加速度センサーを持っています。I2CとSPI接続が可能です。
今回は、I2Cで接続して測定データの読み取りを行ってみました。

データの取り込み方法

基本的には次の方法で読み取りを行います。

  • MPU6050のレジスタにサンプリング周期、やどの値を取得するかを設定する
  • 計測されて新しい値がレジスターにセットされると割り込みが発生する
  • 計測結果のレジスターの値を読み取る

I2C

I2Cの読み書きはCircuits.I2Cを使います。
Elixirでi2Cの通信を行う場合、Circuits.I2C一択だとおもいます。詳細はドキュメントや他の記事を参照してください。

実装方法

Circuits.I2Cには指定したPINの値が変化した時(立ち上がり、立下り、両方のどれか指定できる)にメッセージを送信する機能があります。
GenServerと組み合わせる事で、割り込みがあったら、GenserverのHandle関数を呼び出して、データの取り込みを行うという実装がよさそうです。
この方針で実装してみます。

interrupt_hander.ex
defmodule InterruptHandler do
  use GenServer
  alias Circuits.GPIO
  @interrupt_pin 4
  def start_link() do
    GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
  end

  def init(_state) do
    mpu = Mpu6050Lib.new()

    {:ok, gpio} = GPIO.open(@interrupt_pin, :input)

    Mpu6050Lib.initialize(mpu, 1, 6)
    # GPIOピンの変化を監視し、メッセージとして受け取るように設定
    GPIO.set_interrupts(gpio, :rising)
    time = System.system_time(:microsecond)
    Mpu6050Lib.clear_interrupt(mpu)
    {:ok, %{gpio: gpio, mpu: mpu, log: [], log_size: 0, start_time: time}}
  end

  def handle_info({:circuits_gpio, _pin, _timestamp, _value}, state) do
    # データの取り込み処理を行う
    acc = Mpu6050Lib.get_acc(state.mpu)
    gyro = Mpu6050Lib.get_gyro(state.mpu)
    time = System.system_time(:microsecond) - state.start_time
    # データの保存(最初の10000件を保存する)
    new_state =
    cond do
      state.log_size < 10000 ->
        %{state | log: [[acc, gyro, time] |state.log] , log_size: state.log_size + 1}
      true ->
        state
      end
    {:noreply, new_state}
  end
end

動作確認

MPU605を500サンプリング/秒(2ms間隔)で測定をする設定にします。
割り込み信号(CH1)は、測定が完了するとが1となり、データの読み取りを開始すると0になります。

DS1Z_QuickPrint4.png
CH1(黄色)割り込み信号 CH2(水色)I2Cのクロック

想定通り、2msごとにデータの取り込みができていました。

CH1の割り込み発生(1になる)

加速度と角速度の読み取り(それぞれ6byte)を読み取る

2msの間に完了。取りこぼしなくデータを取得できています。

割り込み処理の考察

CH1が1になっている時間が、割り込みが発生してからデータの取り込みを開始するまでの遅延時間となります。この時間は約610usでした。

もう少し長い範囲で測定してみました。
DS1Z_QuickPrint3.png

この測定した範囲でもMax 600us Min 600usでぶれもなく割り込み処理ができている様です。

細かい条件が異なるので一概には比較できないかもしれませんが、Pythonでは、ここまで一定した時間ではなかったです。
この安定した値になるとは、驚きました。
Elixirでは、GILが無い事もこの原因かもしれません。

まとめ

  • GenServerを使い、500サンプリング/秒で安定したデータの取り込みができる事を確認できた
  • C言語で書いた場合の遅延には及びませんが、毎秒100回くらいの処理だったら余裕をもってできそう
  • リアルタイムOSに求められるような性能は無理だが、安定した処理ができそう
  • 通信やファイル保存等を同時に行った場合の影響についても今後確認してみたい
7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?