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

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

ただいまの
回答率

88.80%

|ラズパイ|C++|での実行高速化について

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,093

P5_USER

score 70

いつもお世話になっています。

前提・実現したいこと

最終目標はループ内処理の高速化です。
(現在は1ループ65[ms]です。これを、40[ms]ぐらいにまで速めたいです。達成できなくても、極力早くできれば良いと思っています。)

Raspberry-PiとNAVIO2で9軸センサ・GPS・温度・高度を取得しています。
コーディングはC++11で行っています。

ジャイロセンサは温度によってドリフトしてしまうらしいので、
温度を取得し2次処理でドリフト補正をしたいのですが、
温度(と高度)を取得するために、usleep(10000);
つまり、10ミリ秒(×2)待機しなければなりません。
(試しに、値を下げてみたところ確からしくない値を吐きました。)

1ループに占める処理のうち、温度(と高度)が一番ボトルネックになっていますが、
待機時間を変えるわけにもいきません。

そこで、処理の高速化のためにコンパイルオプションを変えて(-o0→-o2)みたりしたのですが、ループ内処理時間は変わりませんでした。

他にも何かできることはあるでしょうか。
もう腹をくくってマルチスレッドの処理をすべきでしょうか。

該当のソースコード

公式が出している例題コードを殆ど切り貼りしただけなので、
C++のコードは余り高速化検討の参考にならないかもしれませんが、
MakeFileとともに以下に示します。

(追記)
ヘッダファイルのURLを明記します。
https://github.com/emlid/Navio2/tree/master/C%2B%2B/Navio

#include "Common/MPU9250.h"
#include "Navio2/LSM9DS1.h"
#include <Common/MS5611.h>
#include <Common/Ublox.h>
#include "Common/Util.h"
#include <unistd.h>
#include <string>
#include <memory>
#include <stdio.h>
#include <Navio2/Led_Navio2.h>
#include <Navio+/Led_Navio.h>
#include <time.h>
#include <chrono>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

unsigned char getStrLength(char *Str)
{
    unsigned char i = 0;
    while(Str[i] != 0x00)
    {
        i++;
    }
    return i-1;
}

//=============================================================================
int main(int argc, char *argv[])
{
    double sendData[34];

    #pragma region IMU

    // case mpu
    auto sensor_mpu = unique_ptr<InertialSensor>{ new MPU9250() };

    // case lsm
    auto sensor_lsm = unique_ptr <InertialSensor>{ new LSM9DS1() };

    sensor_mpu->initialize();
    sensor_lsm->initialize();

    float ax_mpu, ay_mpu, az_mpu;
    float gx_mpu, gy_mpu, gz_mpu;
    float mx_mpu, my_mpu, mz_mpu;
    float ax_lsm, ay_lsm, az_lsm;
    float gx_lsm, gy_lsm, gz_lsm;
    float mx_lsm, my_lsm, mz_lsm;

    #pragma endregion IMU

    #pragma region GPS

    // This vector is used to store location data, decoded from ubx messages.
    // After you decode at least one message successfully, the information is stored in vector
    // in a way described in function decodeMessage(vector<double>& data) of class UBXParser(see ublox.h)
    vector<double> pos_data;

    // create ublox class instance
    Ublox gps;

    #pragma endregion GPS

    #pragma region Barometer

    MS5611 barometer;

    barometer.initialize();

    #pragma endregion Barometer

    #pragma region LED

    auto led = unique_ptr <Led>{ new Led_Navio2()};
    led->initialize();

    #pragma endregion LED

    #pragma region Time
    chrono::system_clock::time_point start, end;
    float smpu = 0.0;
    float old_mpu = 0.0;
    float slsm = 0.0;
    float old_lsm = 0.0;
    float dt_mpu, dt_lsm;
    start = chrono::system_clock::now();
    #pragma endregion Time

    #pragma region UDP

    int sock;
    struct sockaddr_in addr;
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(60000);
    addr.sin_addr.s_addr = inet_addr("192.168.24.13");

    #pragma endregion


//-------------------------------------------------------------------------

    while(1) {
        #pragma region IMU

        sensor_mpu->update();
        sensor_lsm->update();

        sensor_mpu->read_accelerometer(&ax_mpu, &ay_mpu, &az_mpu);
        sensor_lsm->read_accelerometer(&ax_lsm, &ay_lsm, &az_lsm);

        sensor_mpu->read_gyroscope(&gx_mpu, &gy_mpu, &gz_mpu);
        sensor_lsm->read_gyroscope(&gx_lsm, &gy_lsm, &gz_lsm);

        sensor_mpu->read_magnetometer(&mx_mpu, &my_mpu, &mz_mpu);
        sensor_lsm->read_magnetometer(&mx_lsm, &my_lsm, &mz_lsm);

        sendData[0] = ax_mpu;
        sendData[1] = ay_mpu;
        sendData[2] = az_mpu;
        sendData[3] = gx_mpu;
        sendData[4] = gy_mpu;
        sendData[5] = gz_mpu;
        sendData[6] = mx_mpu;
        sendData[7] = my_mpu;
        sendData[8] = mz_mpu;
        sendData[9] = ax_lsm;
        sendData[10] = ay_lsm;
        sendData[11] = az_lsm;
        sendData[12] = gx_lsm;
        sendData[13] = gy_lsm;
        sendData[14] = gz_lsm;
        sendData[15] = mx_lsm;
        sendData[16] = my_lsm;
        sendData[17] = mz_lsm;

        #pragma endregion IMU

        #pragma region Time
        end = chrono::system_clock::now();

        dt_mpu = chrono::duration_cast <chrono::milliseconds> (end - start).count();
        dt_lsm = chrono::duration_cast <chrono::milliseconds> (end - start).count();

        start = chrono::system_clock::now();

        sendData[18] = dt_mpu;
        sendData[19] = dt_lsm;
        sendData[20] = 0;//year
        sendData[21] = 0;//month
        sendData[22] = 0;//day
        sendData[23] = 0;//hour
        sendData[24] = 0;//min
        sendData[25] = 0;//sec

        #pragma endregion

        #pragma region GPS

        if (gps.decodeSingleMessage(Ublox::NAV_POSLLH, pos_data) == 1)
        {
            sendData[26] = pos_data[0];//fix
            sendData[27] = pos_data[1];//Lon
            sendData[28] = pos_data[2];//Lat
            sendData[29] = pos_data[3];//height
            sendData[30] = pos_data[4];//hMSL
            sendData[31] = pos_data[5];//hAcc
            sendData[32] = pos_data[6];//vAcc
            sendData[33] = pos_data[7];//gSpeed

            switch ((int)pos_data[0]) {
            case 0x00:
                led -> setColor(Colors::Black);
                break;

            case 0x01:
                led -> setColor(Colors::Red);
                break;

            case 0x02:
                led -> setColor(Colors::Yellow);
                break;

            case 0x03:
                led -> setColor(Colors::Green);
                break;

            case 0x04:
                led -> setColor(Colors::Blue);
                break;

            case 0x05:
                led -> setColor(Colors::Magenta);
                break;

            default:
                led -> setColor(Colors::White);
                break;
            }
        }
        else
        {
            sendData[26] = 0;//fix
            sendData[27] = 0;//Lon
            sendData[28] = 0;//Lat
            sendData[29] = 0;//height
            sendData[30] = 0;//hMSL
            sendData[31] = 0;//hAcc
            sendData[32] = 0;//vAcc
            sendData[33] = 0;//gSpeed

            led -> setColor(Colors::Red);

        }

        #pragma endregion GPS

        #pragma region Barometer

        barometer.refreshPressure();
        usleep(10000); // Waiting for pressure data ready
        // usleep(9000); // Waiting for pressure data ready
        barometer.readPressure();

        barometer.refreshTemperature();
        usleep(10000); // Waiting for temperature data ready
        // usleep(9000); // Waiting for temperature data ready
        barometer.readTemperature();

        barometer.calculatePressureAndTemperature();

        sendData[34] = (double)barometer.getTemperature();
        sendData[35] = (double)barometer.getPressure();

        #pragma endregion Barometer

        #pragma region UDP

        char send_num_str[400];
        sprintf(send_num_str
        , "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n"
        , sendData[0]
        , sendData[1]
        , sendData[2]
        , sendData[3]
        , sendData[4]
        , sendData[5]
        , sendData[6]
        , sendData[7]
        , sendData[8]
        , sendData[9]
        , sendData[10]
        , sendData[11]
        , sendData[12]
        , sendData[13]
        , sendData[14]
        , sendData[15]
        , sendData[16]
        , sendData[17]
        , sendData[18]
        , sendData[19]
        , sendData[20]
        , sendData[21]
        , sendData[22]
        , sendData[23]
        , sendData[24]
        , sendData[25]
        , sendData[26]
        , sendData[27]
        , sendData[28]
        , sendData[29]
        , sendData[30]
        , sendData[31]
        , sendData[32]
        , sendData[33]
        , sendData[34]
        , sendData[35]);

        sendto(sock, send_num_str, strlen(send_num_str), 0, (struct sockaddr *)&addr, sizeof(addr));

        #pragma endregion
    }
    return 0;
}
CXX ?= g++
CFLAGS=-c -g -o2 -ggdb -Wall
NAVIO = ../../Navio
INCLUDES = -I ../../Navio

all:
    $(MAKE) -C ../../Navio all
    $(CXX) -std=c++11 $(INCLUDES) AGMGPSBaroUDPdt.cpp -L$(NAVIO) -lnavio -o AGMGPSBaroUDPdt

clean:
    rm -f AGMGPSBaroUDPdt

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

C++11
Raspberry-Pi3 Model B

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+2

こんにちは。

そのような時の原則は、処理時間の長い並列処理してよい処理を並列処理することです。
例えば、sendtoを非同期送信にするなどですね。
もし、refreshPressure()とrefreshTemperature()を同時処理してよいようなら(期待薄ですが可能性はあります)同時に要求して、同時に受け取ることです。(温度補正は1サイクル遅れますが、40~60mSecでの温度変化の影響が微細なら無視してもよいのでは?)
他にも、sensor_mpuとsensor_lsmの各処理で時間がかかるものがあるなら、それらを並列処理化することですね。
サブスレッドを使ったりmutexで排他制御したり等が必要になるでしょうから、かなり慎重な設計が必要ですが効果も高いです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/12 18:27

    そこそこ英文を読まないと分からないのでノーコメントとさせて下さい。

    キャンセル

  • 2019/05/12 18:37

    わかりました。
    色々ありがとうございました。

    キャンセル

  • 2019/05/12 18:48

    やっぱりrefreshPressure()とrefreshTemperature()の並列は無理っぽいですね、見た感じ。
    やるなら気圧と温度を交互に取り続けるスレッドを作ってあげるべきかなと(排他処理大変そう)。

    通信の非同期化はC++erだとboost.asioを真っ先に浮かべてしまうけれど使えるのかな?知らんけど。

    キャンセル

+1

まずはどこで時間をくっているかを計測してみるとよいです、

google 検索して、 "gcc profile" などで検索すると計測方法がみつけることができると思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/12 16:26

    katoyさん

    int i = 0;
    if(i == 100){
    break;
    }
    i++;
    をwhileの中に挟み、MakeFile内に-gpを記述しましたが(-o2は消しました)、
    gmon.outが生成されませんでした。

    参考にしたのは以下URLです。
    http://nenya.cis.ibaraki.ac.jp/TIPS/gprof.html

    キャンセル

+1

温度と高度はそれほど時間変動がないと仮定すると、取得頻度をループ毎から数十ループ毎に1回に減らすことができそうです。すると待ち時間も10ミリ秒→サブミリ秒に抑えることができ、高速化できるのではないでしょうか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/12 16:21

    can110さん

    ありがとうございます。
    int i = 0;

    if(i % 100 == 0){
    センサ値取得
    }
    で40[ms]前後まで短縮出来ました。

    キャンセル

+1

そもそもなんですけど、なんかぐぐって適当に引っかかったMS5611クラスのソースコードと合わないんですが

どこでお使いのものは手にはいりますかね?

やるとしたら温度・高度取得、通信の非同期化でしょうが、どの程度効果が出るかはわからないですね・・・。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/12 16:20

    yumetodoさん

    インクルードファイルの説明が抜けておりました。
    失礼しました。
    以下のURLにあるMS5611.cppとMS5611.hがラズパイで
    使っているコードです。
    https://github.com/emlid/Navio2/tree/master/C%2B%2B/Navio/Common

    キャンセル

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

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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