質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • Python

    9148questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Linux

    4029questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • Raspberry Pi

    891questions

    Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

正確な時間刻みでセンサの値を取得したい

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 682

ondela

score 2

 前提・実現したいこと

raspberry pi3で加速度センサを作ろうとしています。
OSはlinux 使用言語はpython3です。
使用加速度センサはadxl345で、i2c通信にて接続しています。

 発生している問題・エラーメッセージ

一定間隔(0.01秒刻み)でセンサから値を取得するプログラムを組んでいますが、
たまに大きく刻み時間を外してしまうことがあります。これを解決したいです。

for文内で取得した時刻(time_act)の差分を取ってみると、ほとんど刻みdt(0.01秒)で打刻できていますが、
まれに1秒とか2秒とかになってしまいます。
計測値の取得に時間がかかっているか、あるいは取得している時刻がおかしくなるタイミングがあるかと思っています。

この問題の解決法でなくとも、例えばRTCのようなものを外付けすれば一定刻みでセンサ値取得が可能なるなど、別の視点からの回答でも構いません。
知見をお持ちの方、何卒宜しくお願い致します。

 該当のソースコード

N = 1000000
dt = 0.01
VAL = [[0, 0, 0]]*N
time_all = [[0,0,0,0,0]]*N
time_act = [0]*N
act_dt = [0]*N

dta = 0.0001084814598456673

t1 = time.perf_counter()
for i in range(N):
    tt1 = time.perf_counter()
    VAL[i] =  adxl345.getAxes()
    tt2 = time.perf_counter()
    t2 = dt-(time.perf_counter() - t1) -dta 
    tt3 = time.perf_counter()
    if t2 > dta:
        tt4 = time.perf_counter()
        time.sleep(t2)
    t1 = time.perf_counter()
    tt5 = time.perf_counter()
    time_act[i] = t1
    tt6 = time.perf_counter()
    time_all[i] = [tt2-tt1,tt3-tt2,tt4-tt3,tt5-tt4,tt6-tt5]


※adxl345.getAxes()がセンサから値を取得するコマンドです。
x,y,zの3成分を取得しています。実行時間は概ね0.0001秒くらいなので、for文自体は十分に刻み0.01秒で回せると考えています。

 試したこと

各処理にかかっている時刻を計測しました(tt2-tt1,tt3-tt2など)。
これをグラフ化すると、以下のようになりました。
イメージ説明
縦軸は処理にかかった時間です。ループ1周の時間は0.01秒となってほしいのですが、ある種周期的にそれが崩れています。

 補足情報(FW/ツールのバージョンなど)

python 3.5.3
Raspbian GNU/Linux 9

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

raspberry pi3側で、データ取得/蓄積を考えましょう。
蓄積と言っても 2,3回分で十分と思いますが、、。

一般的なLinixシステムではリアルタイム処理は保証されていません。まあ、設定変更で、結構なリアルタイム処理(0.1秒程度以上も)は可能ですが。さらに、Pythonがインタープリタなので、もっとリアルタイムタイム向きではありません。処理時間を気にするならば、C/C++あたりを検討すべきです。
ただ、raspberry側でリアルタイムデータ取得を行い、それを順次、PC側に送るならば、Pythonでも可能じゃないかと思います。(詳細検討は別途、必要)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/01 21:34

    ありがとうございます。
    pythonはやはり重いのですね。osを搭載しておらず、c言語を扱えるarduinoなどに計測の役割を分割して、確実に計測を行える方針で考えてみます。

    キャンセル

checkベストアンサー

+2

ondelaさん、

どれがうまくいくかわかりませんが、アイデアをあげてみます。

  1. CPUクロックをぱ固定してみる
    echo performance | sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

  2. 実行するCPUを固定してみる。(taskset)

  3. niceで、優先度を上げてみる

  4. 他のタスクをできるだけ実行にしない
    o GUIは使わない(Raspbian Liteベースにしてみる。とか、Buildrootで最小限のシステムをつくる)
    o バックグラウンドで、タスクをできるだけ動かさない (systemd で使わなそうなサービスを切る?)
    o ファイルシステムにアクセスしない(!)
    o ネットワークをつかわない(!?)

  5. リアルタイムカーネルを使う
    他の回答者のみなさまが書かれている通り、ふつうのLinuxではリアルタイム応答の保証はありません。
    が、応答性を通常のカーネルよりよくしたパッチがあり、最近のRaspberyPiのカーネルソースでは、ブランチがあります。
    => 参考

  6. adxl345のデバイスドライバを使う。
    カーネルソースの drivers/input/misc/内に adxl34x*.[ch] にドライバがあるので、参考にして、修正して、使う。
    (具体的な使い方とか、わかりません。。)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/01 21:28

    ありがとうございます。
    このままraspberrypiで計測を行うかは検討しますが、その場合でもある処理はraspberrypiで行わせたいと思っているので、その際の参考にさせて頂きます。

    キャンセル

+1

通常のプログラムループでは正確な時間間隔は実現できません。
これは、バックグランドで、言語(Python)のガベージコレクションが走ってしまう、とか、
OSで、バックグランドでファイルアクセスが始まる、とか、何らかの通信が行われる、とかで、いろんな要因でコードの実行が遅れたり実行時間が長くなったりします

これをどうにかするには、というのは、OSレベルでどーにかしないといけないってことで、なかなか難しい問題となりますね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/01 21:36

    ありがとうございます。
    ご指摘のように、linux搭載のマイコンで正確な時間計測は難しそうなので、少なくとも計測はOS非搭載のマイコンで行う方針で考えてみます。

    キャンセル

+1

すでに回答されている通りで、一般的なLinuxではリアルタイム処理は保証されません。つまり、ユーザー側のプロセスを一定のタイミングでできる保証はありません。いま動いているように見えるのは、たまたまです。
これを解決するにはリアルタイムOSを使うか、加速度センサの値を一定時間ごとに取得して送る処理自体を、OSを乗せない別の組み込みマイコンにやらせるかといった方法があると思います。例えばArduinoなどで加速度センサの値を10msごとに読み込んで、データをラズパイにI2C等で送る方法もあるかと思います

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/01 21:30

    ありがとうございます。
    確実に一定間隔で計測を行っていきたいので、arduino等の使用を検討したいと思います。

    キャンセル

同じタグがついた質問を見る

  • Python

    9148questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Linux

    4029questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • Raspberry Pi

    891questions

    Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。