2018-07-30

Raspberry Pi3を使ったリアル波形描画(3) Qt + QCustomPlot で静止グラフを描いてみる

Qt(キュート)とは何か。簡単に解説する。

【出典】
https://ja.wikipedia.org/wiki/Qt
https://www.sra.co.jp/qt/point/

Qt([kjuːt] キュート)とは、クロスプラットフォームアプリケーションフレームワークである。The Qt Company(英語版)とQt Project(英語版)によって開発されている。キュー・ティーと発音されることもあるが公式にはキュートである。
GUIツールキットとして広く知られているQtであるが、コンソールツールやサーバのような非GUIプログラムでも広く使用されている。

ライセンスには商用版とオープンソース版があり、現在のオープンソース版のライセンスはLGPLおよびGPLである。商用版を購入するとQt商用ライセンス(Qt Commercial License)でソフトウェアを開発することができる。LGPL版は、2009年3月にリリースされたQt 4.5から提供され始めた。これによりQtは営利企業にとってもより使いやすいライブラリーとなった。

QtはC++で開発されており、単独のソースコードによりX Window System(Linux、UNIX等)、Windows、macOS、組み込みシステムといった様々なプラットフォーム上で稼働するアプリケーションの開発が可能である。またコミュニティーにより多言語のバインディングが開発されており、JavaからQtを利用できるようにしたQt Jambi、さらにQtをRuby、Python、Perl、C#などから利用できるようにしたオープンソースのAPIが存在する。

このように開発が容易であり高速、スタイリッシュなQtはライセンスが多様なこともあり、KDEを始めとするオープンソースのアプリケーションに限らず、商業アプリケーションでの採用例も多く様々な分野で使用されている。

【開発元】
トロールテック (1991-2008)
ノキア (2008-2011)
ディジア(英語版) (2012-2014)
Qt Project(英語版) (2011-現在)

Qtを使用している主なソフトウェア

  • Autodesk Maya 2011 - 3DCGソフト
  • Avidemux - 動画編集ソフト
  • FreeCAD - CADソフト
  • Google Earth - 地球儀ソフト
  • KDE - デスクトップ環境
  • Muse - シーケンサ
  • MuseScore - 楽譜編集プログラム
  • Nuke - デジタル合成ソフト
  • ParaView - データ可視化ソフト
  • QGIS - GISソフト
  • Rosegarden - 楽譜編集プログラム
  • Skype - コミュニケーションソフト
  • モバイルWnn - 日本語入力システム
Google Earth や Skype が Qt で開発されていたとは知らなかった。

【Qt が開発効率を高める点】

  • Qt Creator を使うことで,GUI を直感的に設計することができる。(Visial Basic に似ている)
  • Qt Creator のテキストエディタが優れいて,必要なクラスやメソッドなどを予測入力(先頭の数文字入力すると候補を表示)してくれる。

Qt SIGNAL/SLOTの実践(値の連携)

Qt の重要な機能として SIGNAL/SLOT の機能がある。まずは、実際にどんなことができるのかやってみよう。

Qt Creator でQt ウィジェットアプリケーションのプロジェクトを作成する。





【下線部を入力する。】

#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QSpinBox *spin = new QSpinBox();
    QDial *dial = new QDial();

    spin->setGeometry(200, 200, 100, 20);   // X座標,Y座標,横の長さ,縦の長さ
    dial->setGeometry(200, 300, 100,100);   // X座標,Y座標,横の長さ,縦の長さ

    spin->show();
    dial->show();

    return a.exec();
}

実行すると下記のように表示される。ダイアルとスピンボックス値は連動していない。


スピンボックスとダイアルの値を SIGNAL/SLOT で連携させる

下線部を追加する。スピンボックスの値が変化したら,ダイアルの値をセットし,ダイアルの値が変化したら,スピンボックスの値をセットするように,SIGNAL/SLOTをつなげる。

#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QSpinBox *spin = new QSpinBox();
    QDial *dial = new QDial();

    QObject::connect(spin, SIGNAL(valueChanged(int)), dial, SLOT(setValue(int)));
    QObject::connect(dial, SIGNAL(valueChanged(int)), spin, SLOT(setValue(int)));

    spin->setGeometry(200, 200, 100, 20);   // X座標,Y座標,横の長さ,縦の長さ
    dial->setGeometry(200, 300, 100,100);   // X座標,Y座標,横の長さ,縦の長さ

    spin->show();
    dial->show();

    return a.exec();
}

これを実行すると,スピンボックスとダイアルが連動するようになる。
別々のオブジェクトが Qt の SIGNAL/SLOT のしくみでつながった例。

Qt のSIGNALとSLOTのしくみを理解する


SIGNALとSLOT
SIGNALとSLOTは、オブジェクト間の通信に使用されます。 SIGNALとSLOTのメカニズムはQtの中心的な機能であり、おそらく他のフレームワークが提供する機能と最も異なる部分です。 SIGNALとSLOTはQtのメタオブジェクトシステムによって可能になります。

前書き
GUIプログラミングでは、1つのウィジェットを変更すると、別のウィジェットに通知されることがよくあります。 より一般的には、あらゆる種類のオブジェクトがお互いに通信できるようにしたいと考えています。 たとえば、ユーザーが閉じるボタンをクリックすると、おそらくウィンドウのclose()関数が呼び出されます。

他のツールキットはコールバックを使用してこの種の通信を実現します。 コールバックは関数へのポインターなので、処理関数が何らかのイベントについて通知するようにするには、別の関数へのポインター(コールバック)を処理関数に渡します。 処理関数は、必要に応じてコールバックを呼び出します。 このメソッドを使用した正常なフレームワークは存在しますが、コールバックは直感的ではなく、コールバック引数の型の正確さを保証する上で問題が発生する可能性があります。

SIGNALとSLOT
Qtでは、コールバック手法の代わりにSIGNALとSLOTを使用します。 特定のイベントが発生すると、SIGNALが出力されます。 Qtのウィジェットにはあらかじめ定義されたSIGNALがたくさんありますが、ウィジェットをサブクラス化して独自のSIGNALを追加することができます。 SLOTは、特定のSIGNALに応答して呼び出される関数です。 Qtのウィジェットにはあらかじめ定義されたSLOTが多数ありますが、ウィジェットをサブクラス化して独自のSLOTを追加することで、関心のあるSIGNALを扱うことができます。


SIGNALと SLOTのメカニズムはタイプセーフです。SIGNALのシグネチャは、受信SLOTのシグネチャと一致する必要があります。 (実際には、余分な引数を無視することができるため、SIGNALは受け取ったSIGNALよりも短いシグネチャを持つ可能性があります)。シグネチャは互換性があるため、コンパイラは関数のポインタベースの構文を使用するときに型の不一致を検出するのに役立ちます。 文字列ベースのSIGNALおよびSLOT構文は、実行時に型の不一致を検出します。 SIGNALとSLOTは緩やかに結合されています。SIGNALを送信するクラスは、どのSLOTがSIGNALを受信するかを知らず、また気にもしません。 QtのSIGNALとSLOTの仕組みにより、SIGNALをSLOTに接続すると、適切なタイミングでSIGNALのパラメータでSLOTが呼び出されます。 SIGNALとSLOTは任意の種類の任意の数の引数を取ることができます。 彼らは完全にタイプセーフです。

QObjectまたはそのサブクラス(例えばQWidget )の1つを継承するすべてのクラスは、SIGNALとSLOTを含むことができます。 SIGNALは、他のオブジェクトにとって興味深い方法で状態を変更したときにオブジェクトによって放出されます。 これはすべてオブジェクトが通信するためのものです。 それは、何かがそれが放出するSIGNALを受信しているかどうかを知らない、または気にしない。 これは真の情報カプセル化であり、オブジェクトをソフトウェアコンポーネントとして使用できることを保証します。

SLOTはSIGNALを受信するために使用できますが、通常のメンバー機能でもあります。 オブジェクトがSIGNALを受信するかどうかをオブジェクトが知らないように、SLOTはSIGNALが接続されているかどうかを知りません。 これにより、本当に独立したコンポーネントをQtで作成できるようになります。

単一のSLOTに多くのSIGNALを接続することができ、SIGNALは必要な数のSLOTに接続することができます。 SIGNALを別のSIGNALに直接接続することも可能です。 (これは、最初のSIGNALが放射されるたびにすぐに2番目のSIGNALを放射します)。

SIGNALとSLOTが一緒になって、強力なコンポーネントプログラミングメカニズムを構成します。

SIGNAL
SIGNALは、オブジェクトの内部状態が何らかの方法で変化したときに、オブジェクトのクライアントまたは所有者にとって興味深い可能性のあるオブジェクトによって放出されます。 SIGNALはパブリック・アクセス関数であり、どこからでも送出することができますが、SIGNALとそのサブクラスを定義するクラスからのみ送出することをお勧めします。

SIGNALが放射されると、SIGNALに接続されたSLOTは通常、通常の関数呼び出しと同様にすぐに実行されます。 これが起こると、SIGNALとSLOTのメカニズムは、どのGUIイベントループからも完全に独立しています。 emit文に続くコードの実行は、すべてのSLOTが戻ったときに行われます。 キューに入れられた接続を使用する場合は、状況が少し異なります 。 そのような場合、 emitキーワードに続くコードは直ちに続き、SLOTは後で実行されます。

複数のSLOTが1つのSIGNALに接続されている場合、SIGNALが発信されたときに、接続されている順にSLOTが順次実行されます。

SIGNALはmocによって自動的に生成され、 .cppファイルに実装してはいけません。 彼らは決して戻り値の型を持つことはできません(つまりvoid使用しvoid )。

注記:私たちの経験によれば、SIGNALやSLOTは特別なタイプを使用しないと再利用可能です。 QScrollBar :: valueChanged ()が仮想QScrollBar :: Rangeなどの特殊な型を使用する場合、QScrollBar専用に設計されたSLOTにのみ接続できます。 異なる入力ウィジェットを一緒に接続することは不可能です。

SLOT
SLOTに接続されたSIGNALが放射されると、SLOTが呼び出されます。 SLOTは通常のC ++関数であり、通常呼び出すことができます。 その唯一の特殊な特徴は、SIGNALをそれらに接続できることです。

SLOTは通常のメンバ関数なので、直接呼び出されると通常のC ++の規則に従います。 しかし、SLOTとして、SIGNALSLOT接続を介して、アクセスレベルに関係なく、どのコンポーネントからでも呼び出すことができます。 これは、任意のクラスのインスタンスから発信されたSIGNALが、無関係のクラスのインスタンスでプライベートSLOTを呼び出させる可能性があることを意味します。

仮想SLOTを定義することもできますが、実際には非常に便利です。

コールバックと比較して、SIGNALとSLOTは、柔軟性が向上しているため、わずかに遅くなりますが、実際のアプリケーションの違いは重要ではありません。 一般に、いくつかのSLOTに接続されたSIGNALを放射することは、非仮想関数呼び出しを使用して、受信機を直接呼び出すよりも約10倍遅くなります。 これは、すべての接続を安全に反復する(つまり、後続の受信者が放出中に破棄されていないことを確認する)ために、接続オブジェクトの位置を特定するために必要なオーバーヘッドであり、パラメータを一般的な方法でマーシャルするために必要です。 10の非仮想関数呼び出しは多くのように聞こえるかもしれませんが、例えば、 new操作やdelete操作よりもはるかに少ないオーバーヘッドです。 シーンの背後にある文字列、ベクトルまたはリスト操作をnewまたはdeleteとすぐに、SIGNALとSLOTのオーバヘッドは、完全な関数呼び出しコストのごくわずかな部分しか原因としません。 SLOT内でシステムコールを行うたびにも同じことが言えます。 10以上の関数を間接的に呼び出すことができます。 SIGNALとSLOTのメカニズムのシンプルさと柔軟性は、ユーザーに気づかないほどのオーバーヘッドの価値があります。

signalsやslotsと呼ばれる変数を定義する他のライブラリは、Qtベースのアプリケーションとともにコンパイルされると、コンパイラの警告とエラーを引き起こす可能性があることに注意してください。 この問題を解決するには、問題のあるプリプロセッサシンボルを#undefします。

Qt Creator で SIGNAL SLOTを使ってみる

Qt Creator で新しいプロジェクトを作成する。
Qtコンソールアプリケーションを選択する。

プロジェクト名とプロジェクトパスを設定する。

プロジェクト名の例:SignalSlot4
パスの例:C:\Qt\Projects\SignalSlot



プロジェクトファイルと main.cpp が生成される。

ソースファイルに 新しい ヘッダと cpp ファイルを追加する。Sources のフォルダを右クリックして 「新しいファイルを追加」を選択する。

C++ クラスを選択する。

クラス名を Counter とし,基底クラスを QObject にする。次へ。

counter.h と counter.cpp が追加された。

counter.h を修正する。下線が追加した行。

#ifndef COUNTER_H
#define COUNTER_H

#include

class Counter : public QObject
{
    Q_OBJECT
public:
    explicit Counter(QObject *parent = nullptr);
    
    int value();

signals:
    void valueChanged(int newValue);

public slots:
    void setValue(int value);
    
private:
    int m_value;
};

#endif // COUNTER_H

int value()の value にカーソルを合わせ右クリック→リファクタリング→counter.cpp に定義を追加を選択


counter.cpp にて 下記下線部を追記する。

#include "counter.h"

Counter::Counter(QObject *parent) : QObject(parent)
{
    m_value = 0;
}

int Counter::value()
{
    return m_value;
}

counter.h に戻って,setValue() にカーソルを合わせ右クリック→リファクタリング→counter.cpp に定義を追加を選択する。


counter.cpp にて 下記下線部を追記する。

#include "counter.h"

Counter::Counter(QObject *parent) : QObject(parent)
{
    m_value = 0;
}

int Counter::value()
{
    return m_value;
}

void Counter::setValue(int value)
{
    if (value != m_value){
        m_value = value;
        emit valueChanged(value);
    }
}

main.cpp に移って 下記,下線部を追記する。

#include
#include "counter.h"
#include "stdio.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Counter x, y;
    QObject::connect(&x, &Counter::valueChanged, &y, &Counter::setValue);

    x.setValue(12);     // x.value() == 12, y.value() == 12

    printf("x:%3d, y:%3d \n\n", x.value(), y.value());

    y.setValue(48);     // x.value() == 12, y.value() == 48

    printf("x:%3d, y:%3d \n\n", x.value(), y.value());


    return a.exec();
}

コンパイルして,正常終了することを確認する。(下記 かなづちのアイコンを押す)

緑の三角キーを押してプログラムを実行してみる。


プログラムの動きを図で確認してみる。

下記の SIGNAL/SLOT の設定により,Counter クラスオブジェクト x の setValue が呼ばれ,値が変わると valueChanged()が emit され,Counter クラスオブジェクト y の setValue が呼ばれて値が設定される。

    QObject::connect(&x, &Counter::valueChanged, &y, &Counter::setValue);

Counter クラスオブジェクト y の setValue が呼ばれても,SIGNAL/ SLOT でつながっていないので,x.value() の値は変わらない。
下記を追加すれば,x.value() の値も変わるようになる。

    QObject::connect(&y, &Counter::valueChanged, &a, &Counter::setValue);

Qt の SIGNAL/SLOT のしくみがだいたい分かっただろうか。SIGNAL/SLOT は QtCreator で作成した ボタンが押されたときのイベントで動作する ソフトウェアにするために頻繁に使用する。

以下で紹介するグラフ描画でももちろん使うので、どんなしくみでイベントが伝達されるのかをよく理解しておくとよい。

波形描画を行うために Qt に QCustomPlot を追加する

QCustomplot はグラフ描画のための無償提供されているツールで,qcustomplot.h と qcustomplot.cpp をプロジェクトに追加して,Qt Creator のプロジェクト設定に QT += core gui printsupport を追加すればよい。

他にもQtでグラフ描画する方法はあるらしいが、一番簡単そうだったのが QCustomplot を使う方法だった。

↓QCustomPlotダウンロードサイト
http://www.qcustomplot.com/index.php/download

QCustomplot でグラフを描いてみる

QCustomplot でグラフ描画を行うには、下記の動画のとおりにやってみるとよい。(英語だが非常に丁寧で分かりやすい)。

この動画の通りにやってみると Qt Creator の使い方も学ぶことができる。



今回は、ここまで。

2018-07-07

Raspberry Pi3を使ったリアル波形描画(2) 開発環境を整える

今回は開発環境の準備について解説する。

【用意するもの】
Raspberry Pi3 Model B(LCDディスプレイは別でも込みでもよいので用意する)
  • Micro SD カード(キットに含まれている場合もある)
  • 電源コードやHDMIケーブル、USBマウス、キーボードなと(キットで購入してもよい)
  • Windows PC(OS は7か10)
【参考書籍】
  • これ1冊でできる! ラズベリー・パイ 超入門 改訂第4版 (Raspberry Piをまったく始めて触る場合あったほうがよい)
  • 入門 Qt 4 プログラミング (Qt を使いこなしたい場合に必要)
  • 基礎からしっかり学ぶC++の教科書 (C++未経験者の場合)

  • Windows の環境を整える

    Qtの環境を構築するにはこちらの記事『(Windows)Qtの開発環境を構築(Qtのインストール)』を参照して欲しい。(インターネット環境だと多くの有益な記事を参照できるのでありがたい)

    Visual Studio 2017 Community版はこちらのサイトからダウンロードできる。
    ※Visial Studio 2017 Community版 をインストールするには数時間かかる場合があるので注意が必要。

     vs_Community.exe を実行する。左記のメニューが表示されるまで 5~10分くらい。

    左記のメニューを選択しインストールする。
    インストールが完了するまで約1時間かかる。

    ※Visual Studio 2017 Community版 は試用ならば一ヶ月使える。Microsoft のIDを取得(無料で個人で作成することは可能)してログインすれば,ずっと使い続けることができる。

    次に Qt の Windows版をインストールする。Qtには有料版と無料版があり、無料版はLGPLのライセンスによる使用制限があるが、今回のアプリ作成には無償版で十分に対応が可能。

    基本,こちらのサイトのインストール手順に従う。Raspberry Pi3には Qt 4.x をインストールするが、Windows版では Qt 4.x のインストールはもうできないので、Qt 5.x をインストールする。(互換性はあるので問題はない)

    Qt はパスに日本語が含まれるとコンパイルが上手くいかないので,インストール先は C:\Qt などのフォルダにインストールし,その配下で作業すること。

    下記は Qt 5.10.0 を Windows 7 のPC にインストールしたときのコンポーネントの選択例

    <選択が必須なコンポーネント>

    • Qt Creator 4.6.0-rc1
    • Qt 5.10.0
      • MSVC 2017 64-bit
      • MinGW 5.3.0 32bit
    • Tools
      • MinGW 5.3.0

    なお,Qt はインストール後も Qt Maintanance Tool を使って,コンポーネントの追加,削除,更新を行うことができる。


    Windows 7 64bit にインストールした Qt の「ビルドと実行」の設定内容。

    ビルドと実行で、コンパイラを CとC++ ともに MinGW 32bit を設定する。










    Raspberry Pi3 へQt をインストールする

    Raspberry Pi3にRaspbianをインストールする。この手順については入門書を参照するか、インターネットで探す。基本はwww.raspberrypi.org のダウンロードサイトからNOOBSをダウンロードし、フォーマットしたSDカードにコピーして、インストールする。

    Qt の最新バージョンは Qt 5.10 だが,Raspberry Pi向けの install イメージが配布されていないため,確実にインストール可能な Qt 4.8 をインストールする。(Qt 5.x のソースを Raspberry Pi上でコンパイルする方法も Web上で示されているが上手くいかなかった。)

    Qt 4.8 インストール手順(※参考リンク

    ① Raspberry Pi3上のコマンドラインから Qt4関連のソフトウェアをインストールする。
    -------------------------------------
    sudo apt-get install qt4-dev-tools
    sudo apt-get install qtcreator
    sudo apt-get install gcc
    sudo apt-get install xterm
    sudo apt-get install git-core
    -------------------------------------

    ②QTCreatorを起動してgccのコンパイラーを追加する。
    Tools/Options >ビルドと実行 > コンパイラ > 追加 > (GCCを選択)
    また、コンパイラのパスの参照で/usr/bin/arm-linux-gnueabihf-gcc-6に設定・適用する。(C++ も C も gcc 6 を設定する)

    左記はC++ のコンパイラを手動でgcc 6 に設定した様子。

    ③QTCreatorのビルドキットを設定する。

    Tools/Options >ビルドと実行 > キット>コンパイラをGCCに選択・適用する。






    ④ Qt Creator で新規プロジェクトを作成し,空の状態でコンパイル,実行してエラーがないことを確認する。


    その他 Qt に関する使用手順の解説はこちら




    今回のシステムのデモ動画(5インチLCDで動かしたもの)はこちら

    クロスプラットフォーム開発環境について

    大規模で複雑化したソフトウェアをゼロから開発するのは無理がある。Windows ベースのリッチなGUI(Graphic User Interface)を実現するには,グラフィックライブラリやソフトウェア開発のプラットフォームが必要で、開発の大部分をWindows PC上で行い,実装は Raspberry Pi などのターゲットボードにというスタイルが効率がよい。

    一般にはWindows と Linux , Mac OS では GUI に互換性がない。

    しかし、Qt は Windows , Linux, Mac OS などの OS,プラットフォームに依存することなく,GUI アプリケーションソフトウェアを構築することができる。

    Qt はライセンス条件を満たせば,無償で利用することが可能。

    Qt(キュート)について知りたい場合は商用のライセンスを提供している SRA のサイトを見るとよい。マルチプラットフォーム開発の有効性などが解説されている。

    Qtでできること

    • WindowベースのGUI をQt Creator を使って,簡単に設計できる。
    • Qt Creator で作成した 部品をアクセス(例えばクリック)したときに起動するソフトウェアを書くのが簡単。
    • 複数のソフトウェア(例えば,アナログ信号の取り込みと波形の描画)を並行して動作させるマルチスレッドを実現できる。
    ただし、Qt は C++で書かれており,C++ を理解していなければ,Qt を使いこなすことはできない。

    プログラミング言語の系譜についてはこちらを参照してほしい。

    Qt を使わないと 自力では難しいこと

    • マルチスレッド処理
      • 複数のスレッドをmsオーダーで正確に起動させることは難しい。
      • スレッド間の同期や連携,データの受け渡しが Qt がないと難しい。
    • 波形描画
      • リアル波形描画は Qt に Customplot を追加することで比較的簡単に実現することができる。
    • GUI と C++ アプリとの連携
      • GUI と C++ アプリを連携させる方法は通常 OS に依存するが,Qt を使えば,OSの違いを意識することなく,連携させることができる。

    Microsoft Visual Basic でもあらかじめ用意された各種のGUIパーツを配置して、それらのプロパティが変更されたり、マウスでクリックされたりするなどイベントが発生した場合の処理を記述してゆくことでアプリケーションプログラムを作成することができが、それは Windows OS上だけのことだ。

    しかし、Qt はそれと同等のことを OSに関係なく(Windows, Linux, Mac OS)できる。また、GUIのイベントの発生から、イベントをトリガーにして指定したメソッドへキックするしくみは、Qt でコンパイルする過程の中に隠蔽されるため、アプリケーションの作成者は特定のボタンがクリックされたときに飛んでくるので、該当するメソッド(関数)の中身を書くだけでよい。

    mainwindow.h に構築された関数定義の例

    private slots:
        // Run/Stop ボタンを押された時の処理
        void on_pbt_run_clicked();
        // 波形タイプボタンを押された時の処理
        void on_pbt_wavetype_clicked();
        // 電源ノイズフィルターボタンが押された時の処理
        void on_pbt_ac_line_filter_clicked();
        // ドリフトフリーフィルタボタンが押された時の処理
        void on_pbt_drift_free_filter_clicked();
        // ハイカットフィルタボタンが押されたときの処理
        void on_pbt_hicut_filter_clicked();
        // 表示感度ボタンが押された時の処理
        void on_pbt_displaygain_clicked();
        // 入力ソースボタンが押されたときの処理
        void on_pbt_input_type_clicked();
        // 周波数スピンボックスの値が変化したときの処理
        void on_doubleSpinBox_frequency_valueChanged(double arg1);

    Qt のこのしくみは Signal/Slot の関係を使っており、その概要については、以降の記事で説明したい。(各種 Qt の解説書にも詳しく書かれている)

    現在の Window GUIベースのアプリケーションソフトウェアでは、Window とボタンやダイアログ、テキスト表示領域、ダイヤルやスライダーなどのGUI部品から発生するイベントを受けて、何らかの処理を行い、その結果をまたGUI部品に反映させるといったやり取りの積み重ねとなる。

    また、そういったユーザインタフェースを伴うイベントの背後で、ファイルの入出力や定期的なインターバル割り込みイベントなどを処理する。

    これらのシステム上の役割を3つのレイヤーで表現したのが、左記のクラス図となる。

    一番上のレイヤーは ユーザーインターフェースを担う部分で Presentation Layer となる。

    ユーザーが直接インタフェースする部分であるため、この部分の見た目の良さが商品の付加価値となる。また、時代や商品のラインナップによって、変わりやすい、または、変えることで違いをだす部分である。

    Presentation Layer を構成するソフトウェア部品は環境が変わる(ディスプレイやプラットフォームが変わる、GUI部品の追加要求があるなど)ことを前提に、汎用的なGUIライブラリが使えるとよい。今回はそれが Qt となる。

    なお、プレゼンテーションレイヤーは付加価値にはなるが、また、外から丸見えなため真似されやすい部分でもある。だから、組織のコア・コンピタンスにはなりにくい。商品の付加価値にはなるが、真似されないソフトウェア資産にはなりにくいので、GUIライブラリやツールを使ってさっさとかたづけたい領域である。

    一番下のレイヤーは Data Source Layer で、データを取り込んだり、格納したりする役割を担っている。最近の機器は IoTのキーワードが示すように、ネットワークやポータブルメディアの I/F を持ち、それらの機能があるのが当たり前になりつつある。

    Raspberry Pi にも最初から LANや WiFi, Bluetooth , USB, SDのハードウェアI/Fが付いており、ドライバや関連ライブラリも用意されている。

    このレイヤーも必ず実装はしないといけない部分だが、汎用的なI/F とそれを扱うソフトウェアであるため、真似されないソフトウェア資産にはなりにくい。

    なお、今回の事例ではアナログ信号を取り入れるため、その部分のハードウェア、ソフトウェアはコア資産となりうる。信号の取り込み後は、多くの場合、デジタルフィルタなどの二次処理を行う。

    それらの二次処理は検証を行う必要があり、検証のたびにいちいちアナログ信号をA/D変換していたのでは効率が悪い。

    よって、取り込んだアナログ信号をA/D変換したデータは Data Source Layer を使って、ファイルの保存したり、アナログ信号の代わりにsin波や、疑似データを入力に使ったりしたい。

    それをC++の派生を使って実現しているのが、このクラス図となる。入力のI/Fは同じで、いろいろな入力クラスを派生させており、それを切り替えることで シミュレーションでデジタルフィルタの効き具合を確認したのち、アナログ信号をA/D変換したときにも期待された効果が出ているかどうかを確認することができる。

    このようなフレームワークが出来上がっていれば、いちいち実機を使わずとも、シミュレーション環境でかなりの検証作業を行うことができる。

    そして、もっとも重要なのが真ん中の Domain Layer となる。ドメインレイヤーは、そのドメインに特化したソフトウェア資産を配置する。

    ここでは黄色のスレッドとタイマーのクラスを置いた。これらのクラスは Qt にライブラリで提供されているもので、定期的な割り込みを発生させて、インターバル処理を行うために必要だった。リアルタイムな波形処理を行うためには必要なしくみだが、ドメインに特化した機能とも言える。

    そして、緑のクラスがこのシステムのコア資産となる部分だ。電源ノイズフィルタや、ドリフトフリーフィルタ、ハイカットフィルタは、信号処理の二次処理として必要なフィルタだが、そこにノウハウがある。だからこそ、今回の教育素材ではスケルトン(I/Fだけが用意されており、中が空)にしてある。そこはがんばって作成して欲しい。

    心拍を検出するクラスもコア資産だ。その部分の性能を高めるには、多くのデータを通してみて最適なアルゴリズムを検証する必要があるだろう。それを実現することができれば、他社に真似できないコア・コンピタンスになる。

    この3つのレイヤーのうち Domain Layer はもっとも寿命が長く、組織の利益の源泉になる資産である。

    一方、Presentation Layer と  Data Source Layer に配置されたソフトウェアは、商品の付加価値としては必要で、それがないと競争には勝てないのだが、時代や環境、ユーザーの要求とともにどんどん変わっていく宿命もある。

    変化に対応が可能である必要があるということだ。ユーザーインターフェースは時代とととにリッチになっていくので、GUI部分のソフトウェアは効率よく開発できる環境を持っていたい。そのためには、GUIライブラリが必要であり、今ではGUIライブラリの多くはオブジェクト指向言語で提供されている。

    データの入出力も同様にLAN, WiFi, Bluetooth, USB, SD などの I/Fが当たり前になっている現状では、それらのI/Fを必要に応じて使いこなせるプラットフォームが欲しい。

    組込みソフトウェアアーキテクトが意識すべきは、この3つのレイヤーの役割、寿命、ソフトウェア資産としての価値の違いである。

    その違いに応じて、必要なソフトウェア開発環境を用意し、効率がよく、かつ、商品群としての価値を最大に高めるアーキテクチャを用意する。

    それができれば、デスマーチではなく、ユーザーに満足してもらえるクリエイティブな商品開発ができると思う。

    P.S.

    永年組込みソフトウェアを開発してきたエンジニアが描くモデルで,実現する機能がクラスやパッケージになっているものをよく見かける。例えば,デバイスドライバとか,システム制御とか,データライブラリといったクラスが並んでいると,何がコアコンピタンスとなりうるソフトウェアの再利用資産なのか分かりにくい。

    今はそんなに規模が大きくなくても,いずれ訪れるソフトウェアの大規模化を想定して早いうちから組織的に重要となる再利用資産は何か,どれかを見極めておいた方がいい。

    そのためにはクラスやパッケージを責務で分割して,その再利用資産が手足として使用するストレージやUIのI/Fは時代とともに変わりゆくものだとして設計する。

    それができるようになると上記の 3 Layer にクラスやパッケージを分類することができるようになる。

    ※この記事に紹介した レイアードアーキテクチャについて、より深く知りたい方は『リアルタイムOSから出発して 組込みソフトエンジニアを極める』の3章 再利用の壁を越える をお読みください。

    2018-07-01

    Raspberry Pi3を使ったリアル波形描画(1) イントロダクション

    書籍『リアルタイムOSから出発して組込みソフトエンジニアを極める』の改装版を2016年5月にリリースしてから、この手の専門書にしてはそこそこ売れているようだ。

    2006年3月のこの本の初版を出版して以来、ずっと売れ行きをウォッチしているが、12年経った今の方がコンスタントに売れているような気がする。

    「それはなぜか?」とずっと自問自答している。10年前はまだ組込みソフトウェアの開発規模はそれほど大きくなく、本の需要もそれほどなかったが、2020年を目前とした現在では、組込みソフトもゼロから作るようなこともなく、組込みソフトウェアの開発者も不足してきており、ソフトウェアの再利用を行わないと立ちゆかなくなってきたというのが、今この本が売れている理由ではないかと考えている。


    この本が、他の本と違う点は、商品のビジネスモデルと組込みソフトウェアのアーキテクチャやソフトウェア技術を絡めて語っているところだと思う。ビジネスを成功させるためのソフトウェアアーキテクチャとは何かについて語っているつもりだ。

    簡単に言えば、組込みソフトウェアの製品を効率良く開発し、利益を高めるために必要な技術や考え方は何かを Step by Step で説明している。(最近は聞くことが少なくなった MOT:Management Of Technologyを意識しているつもり。)

    この本では 電子レジスターの商品群を想定して解説をしているのだけれども、ここ最近、この本を読んでくれている読者向けに、実物を使ってこの本に書いてあることを実践的に学ぶ教材があるといいなと考えるようになった。

    そんな折、Raspberry Pi3 が6000円くらいで手に入り、OSが Linuxベースではあるが(Linux は基本的にマルチタスクOSでリアルタイムOSではない) Qt(キュート:オープンソース版は無償)の開発環境を使うと、安価な学習環境を構築できることが分かった。

    そこで、この特集記事「Raspberry Pi3を使ったリアル波形描画」では、『リアルタイムOSから出発して組込みソフトエンジニアを極める』を実践的に理解するための教材(Qtを使い、Windows と Raspberry Pi のマルチプラットフォームで開発する教材)を紹介しながら、組込みソフトウェアの製品を効率良く開発し、利益を高めるために必要な技術や考え方を説明しようと思う。

    組込み機器のものづくりで必要な技術・スキルとは?

    ところで、技術系のソフトウェア研修を永年やってきて、ものづくりに必要な目に見えにくいスキルがあるなと感じる。それはものづくりを始めるにあたって「いける」かどうかが分かる、または「いける」かどうかを直感で感じる能力のことだ。別な言い方をするとものづくりを始める前に実現可能性があるかどうか、ものづくりを実現するために最も重要な要素やボトルネックを見分ける能力だ。それが出来る素養があることがものづくりのアーキテクトの素養があるかないかの違いだと思う。

    チームのメンバー全員が持っている必要はないが、アーキテクトとしての素養を持ったスキルを持った者がチームに一人はいないと製品開発が実現しない。

    アーキテクトの素養があるものは20人に1人と言われる。実際それくらいの割合だと感じる。アーキテクトの素養を持った者がいないチームで標準的な製品開発のプロセスを頭からなめさせると、ドキュメントは出来てきても、「もの」ができない。

    別な言い方をすると、アーキテクトのいないチームはフィージビリティスタディ※1 をしないまま、何も恐れることなく製品開発に突入しようとする。

    ※1 フィージビリティスタディ(feasibility study):プロジェクトの実現可能性を事前に調査・検討することで、「実行可能性調査」「企業化調査」「投資調査」「採算性調査」とも呼ばれる。

    組込みソフトウェア製品の場合、多くの場合は現在販売している製品があり、その製品の派生機種や後継機種を開発することが多いだろう。

    だから、フィージビリティスタディはすでに終わっている、技術的なかなめとなる部分はもう分かっていることが多い。左図の左側の調査研究の中のコンセプト開発・研究試作の部分だ。

    ただし、現行製品があるからといってコアな技術が資産化されているかどうかは分からない。ソースコードがあるからといって再利用可能な状態になっているとは限らないし、具体的なノウハウは1人の技術者の頭の中だけにあるかもしれない。

    自分達の組織のコアな技術が何かを知るには、Raspberry Pi のような汎用プラットフォームをまだドメイン知識のないエンジニアに渡し、それで売り物の製品相当のものを作れるかどうか試してみると分かる。

    今はインターネットでかなりの情報を収集できるから、未知の技術であっても大抵のことは調査できる。CQ出版のトラ技やインタフェースのバックナンバーなんかも有効な情報源だ。しかし、そういった情報を駆使しても、ドメイン知識のない技術者が製品相当のものを作れるとは限らない。

    そして、それを試したときに、どんなに優秀なソフトウェアエンジニアであってもどうしてても、実現できない機能や性能があれば、それがあなたの組織のコア・コンピタンス(「競合他社を圧倒的に上まわるレベルの能力」「競合他社に真似できない核となる能力」)だ。

    もちろん、コア・コンピタンスがメカやエレキのこともあるだろ。その場合、メカやエレキの技術が特許で守られていたり、流出しないように保護できていれば他社にまねされることもなくしばらくは安泰だ。

    ただ、今の時代、メカ・エレキだけがコア・コンピタンスであり、ソフトウェアは付帯機能だというケースは少なくなってきており、メカ・エレキ・ソフトの複合的な資産がコア・コンピタンスになっていることが多いと思う。

    そこで今回の特集記事では、メカ・エレキの機能や性能はあらかじめ提供されるという前提にして、ソフトウェアのコア資産を同構築していけばいいのかにフォーカスを当てて話を進めたいと思う。

    商品開発の実現可能性を嗅ぎ分ける能力を養うには?

    インターネットの情報でマネできる機能や性能は競争優位要因にはならない。真似できないコアな技術があってこそ、ビジネスで成功できる。汎用のソフトウェア資産を組み合わせただけではビジネスで優位に立つことはできない。

    リアルタイム性能の部分が競争優位要因になることはあるが、それだけでは苦しいだろう。リアルタイムとソフトウェア資産とビジネスを意識した再利用を実践してこそ、競争に勝てる商品になる。

    さて、新しい製品、これまでになかったサービスを実現しようとするとき、また、製品の内部を知り尽くしていた技術者がいなくなってしまい、既存システムのアーキテクチャが分からなくなってしまった場合、経験のない新たなメンバーで製品開発を実現させないといけない。

    そんなとき、自分は、何かを作ろうと思ったときに「実現可能性」について確信がないと、ものつくりに着手するのが怖いという感覚がる。せっかく、やり始めたのにやっぱり出来なかったという結果にはなりたくない。前述のアーキテクトの素養というやつだ。

    自分を成長させるためには失敗も必要だが、やはり成功体験を積み重ねる必要がある。時間には限りがあるし、ものづくりの成功はエンジニアとしてのモチベーションを高め、技術やスキルの吸収を加速する。『問題解決能力(Problem Solving Skills):自ら考え行動する力』の記事で書いたが、「問題解決キッズ」の成長スピードは「評論家くん」に比べて22倍速い。ようするに、問題を解決し、製品開発の成功を重ねるとものすごいスピードで成長する。(アーキテクトの素養が身につくと成長するスピードも格段に上がる。)

    それを繰り返すと、開発を着手する前に「実現可能性」の確証といいうか「いけそうだ」というあたり感がないとイヤだと感じるようになる。そして、そういった感覚を研ぎ澄ませていくと、「その製品やシステムを開発するために必要なコアな技術は何か」を探る能力が高まる。

    市販品を見るときにも、この製品のコア技術は何かをカタログから探ったり、分解記事をくまなく精査するようになる。

    そして、そういった感覚が研ぎ澄まされていくと、コアな技術はなんとしても習得したいと思うようになる。コア技術と汎用技術があったら、真っ先にコア技術を学びたいと思い、その後製品実現のために汎用技術を学ぼうと思う。

    この感覚はどんな簡単なものでもいいのだが、やはりものづくりの経験を積み重ねないと醸成されない。

    だから、既存のアプリを利用する経験しかないと、「これはどうやって実現しているのだろうか」という視点が育たない。

    そういった人たちを集めて、「さあ、何か作ってごらん」といってもなかなか難しい。プログラミングの研修にしても演習課題を繰り返すだけでなく、自分の考えで何かの目的を達成するプログラムを作るという経験を積み重ねさせる必要がある。

    OJTで与えられた仕様についてプログラミングしたり、変更の依頼を実装したりすることだけやっていると、その経験はなかなかできない。

    アーキテクトを養成するための研修教材が必要だと感じる。そういったこともあって、今回Raspberry Piを使ったリアル波形描画の教材を作ってみようと思った。

    今の世の中、生まれたときから便利なものだらけで、使う側に圧倒的に時間を使う若い世代には、ものづくりには不利かのかなあと思うところもある。

    でも、別な見方をすると Raspberry Pi のような安価でいろいろなことができるソフトウェア開発のプラットフォームも簡単に手に入る世の中になった。

    また、Raspberry Pi を使った開発環境も無償で、開発に関する情報もインターネットから入手できるようになった。

    ものをつくりたいというモチベーションがあるポテンシャルの高い人材なら、自力で実力を身につけることができる世の中になったとも言える。

    リアルタイムOSから出発して組込みソフトエンジニアを極める』がそこそこ売れているということは、そういった人材が少数だがいて、どうすればソフトウェアアーキテクトとしてのスキルを高めたいともがいているのではないだろうか。

    そういった人たちに、手を動かしながら学べる教材コンテンツを提供したいと思う。

    『リアルタイムOSから出発して組込みソフトエンジニアを極める』を振り返る

    リアルタイムOSから出発して組込みソフトエンジニアを極める』の概要は、初版を作成したときに気合いを入れて作った『組込みソフトエンジニアを極める(外伝)』を見てもらうと分かりやすい。(本を読んで「外伝」を見ていない人は、是非、登場人物5人の日記をザッピングしてもらうと面白いと思う)

    この本では「リアルタイムシステム」を開発するためのソフトウェア技術と、リアルタイムシステム上で開発効率を高めたり、再利用性を高めるための「オブジェクト思考設計」の技術を 組田鉄男という主人公の成長とともに説明している。

    技術的には、第一章の時間分割のハードルで、リアルタイムOSを使った設計技術を、第二章 の機能分割のハードルで、オブジェクト思考設計の技術を紹介し、第三章の再利用の壁で、商品群を開発する際のビジネスを成功するために必要なソフトウェアの再利用技術を紹介している。

    この教育コンテンツでは、「リアルタイム制約」「オブジェクト指向設計」「ビジネス成功のためのソフトウェア再利用」という3つの要件を、Raspberry Pi3 を使って疑似体験することを目的としている。

    今後、この特集記事の完結に時間がどれくらいかかるか分からないが、1年以内には完結させたいと考えている。

    この特集記事を読み続けるとよい人

    • C言語は書けるけれど,C++はまだやったことがなくC言語との違いや特徴を実機ベースで実感したい人
    • オブジェクト思考設計の必要性を感覚的に掴みたい人
    • 組込みソフトウェア開発の経験は長いが,オブジェクト思考設計に踏み出せないでいる人
    • 製品のソフトウェア規模が100万行を超えてきて,開発効率が上がらなくて困っている人
    • 『組込みソフトウェアエンジニアを極める』を読んだけれども,上手くいく実感が湧かない人
    • 競合力の高いソフトウェア製品の商品群を展開したい人。
    • 理論より実践でソフトウェアの再利用や効率的開発を学びたい人。
    • 未来の組込みソフトウェアエンジニアを育てたい人

    前提条件

    • ハードウェアプラットフォームに Raspberry Pi3 を使用する。
    • Raspberry Pi の OS はLinux Raspbian を使用する。
    • ソフトウェア開発の言語は C++ を使用する。
    • GUI 及び統合開発環境は Qt 5.10(Raspberry Pi上では Qt 4.8)を使用する。
    • Windows と Raspberry Pi のマルチプラットフォーム開発を行う。

     アナログアンプ、アナログフィルタ、A/D変換器の設計はしません。そのI/Fまでは設計するのでその部分は自作してください。
     デジタルフィルタや二次処理の部分はスケルトン(インタフェースは提供するが、実装コードは空の状態で紹介する)で提供します。

    つくるもの

    • A/D変換器でアナログ波形をRaspberry Pi3に取り込んで、ディスプレイに波形を表示させるソフトウェアを作成する。
    • 単にソフトウェアを実装するのではなく、「ビジネス成功のためのソフトウェア再利用」という観点で、ソフトウェアのアーキテクチャを考えながら設計を進める。
    こちらはPC上で波形表示を行ったデモ画像


    こちらは 5インチのLCD上で波形表示を行ったデモ画像



    完成したWindowsプラットフォームアプリ(Windows 上で動作する exe + QtのDLL。Raspberry Pi3上でも動作することは確認済み)をダウンロードしてご自分のPCで動かしてみたい方は次の手順でご依頼ください。

    【注意点】
    • Windows 7 と 10で動作することは確認しています。
    • Qt のプロジェクトファイルやソースコードは今の段階では公開していません。本特集記事を進めていく過程で公開方法を考えます。
    • 本アプリは心電図をRaspberry Pi3に取り込み、心拍数を計測することを想定した教材ですが、デジタルフィルタの中身は空(スケルトン)になっています。また、心拍の計測アルゴリズム等も教育用に簡易的に作成したもので実用に耐えうるものではありません。
    • 本当に心電図計測を行うためにはアルゴリズムの設計やデジタルフィルタの設計が必要です。
    • 本教材は、そういったアルゴリズムやデジタルフィルタのインタフェースを定め、カプセル化するとデバッグ効率や再利用性が高まり、ビジネスを成功に導くことができることを学ぶことを目的としています。
    • 本教材は再配布や有償セミナ等への二次利用はできません。(公共の教育機関の方が教材として使用されたい場合は個別にご相談ください。)
    • 圧縮ファイルとパスワードを受け取った方は、本注意点について許諾したことになります。
    【完成形を確認する Windowsアプリの入手方法】

    次のメールアドレスに件名:パスワード送信希望 と書いてメールをお送りください。(”パスワード送信希望”というキーワードが件名に含まれていないと返信されません。
    メールアドレス:CriticalSoftwareConsulting[あっとまーく]gmail.com

    折り返し、ファイルのダウンロード URL と パスワードをお送りします。
    なお、ファイルは パスワード付きのZIPファイルで約20Mバイトあります。

    本教育教材システムのクラス図
    P.S.

    CPUの性能が上がり、カラー液晶や有機ELが安価に手に入るようになった現在では、GUIのソフトウェアをゼロから作り上げるなど考えられないし、やはりWindowsやLinuxマシン上で表示の出来を確認して、そのままそのソースコードを実機で動かすことができれば開発効率が上がる。

    そういった開発環境を Qt は用意してくれる。ちょっとしたソフトウェアの exe を作成するだけでも容量が大きくなる(実際今回のアプリも20Mバイトだった)のが玉にきずだが、そこはマルチプラットフォーム開発ができるのだからがまんしたい。

    C++で提供されているQt の豊富なライブラリや機能を使っていると、なぜC言語ではなく、オブジェクト指向言語であるC++が必要なのかがよく分かる。

    再利用可能なライブラリをサクサク使い、どうやって実現しているのかよく分からなくてもやりたいことが実現できる、それこそがオブジェクト指向言語を使う理由だ。

    同様に、自分達が作ったソフトウェアを再利用して開発効率を高めたいのなら、C言語では難しいと思う。オブジェクト指向言語を使ってI/Fを定め、実現方法は隠蔽して、ソフトウェア資産を構築していかないと、ソフトウェアの採用の効率は上がらない。ちなみに、オブジェクト指向言語を使ったからといっても、再利用可能な資産になるとは限らない。

    その点をこの特集記事では解説していきたいと思っている。

    デモ動画を見てもらうとわかるが、波形をリアルタイムに右から左に流す(ムービング)の波形表示は LCDとLCDドライバとCPUのリソースでC言語でゼロから作ったら気が遠くなるような時間がかかる。

    それが QtQCustomPlotのライブラリ(無償)を使うと、簡単にPC上で実現でき、そのソースをそのまま Raspberry Pi3上で HDMI の I/Fを持つディスプレイで再現させることができる。

    Linux で正確なタイマー割り込みを発生させるかどうかちょっと不安だったが、なんとか大きなジッターなしに実現できた。

    感覚的には数ヶ月もかかる組込みソフトウェアシステムの開発が開発期間を数日で実現できた感じだ。実際にはRaspberry Pi、Qt、QCustomPlot 等を使うのが始めてだったので、それらを使いこなせるようになるには数ヶ月かかったが、実際に動くものが出来たときに、「これが、オブジェクト思考言語やオブジェクト思考設計を使う根拠になる」と思った。

    組込みではないけれども『猫でも分からないオブジェクト指向入門』を読むと、過去から現在に至るまでに、どうしてオブジェクト思考設計が必要になってきたのかが理解できる。

    永年C言語を使い続けてきて、いまさらC++やオブジェクト指向設計はハードルが高いと思っている方は、この特集記事を読み進んでもらって、オブジェクト思考設計とソフトウェアの再利用資産を使って効率よく組込みソフトウェアが開発できることを実感してもらいたい。