本シリーズでは、このブログで紹介してきた「まずこれ」のシリーズを凝縮して、LabVIEWによるプログラミングはこんな風にできるんだ、ということを比較的すぐに体験できるよう、内容を絞って紹介しています。
また、紹介する画面はLabVIEW Community Editionという、非商用の目的であれば無料で使用できるエディションを使っています。なので、LabVIEWに興味を持ったらCommunity Editionを実際にダウンロード、インストールして触りながらプログラムを作り、LabVIEWの楽しさに触れてもらえればと思います。
第七回目の今回は、前回同様ステートマシンの具体例を扱っていきます。
前回は、LabVIEWで簡単なゲームを作るというものでしたが、今回は「測定を行ってそのデータを保存する」という、また全然毛色の異なるプログラムの例を紹介します。
実際LabVIEWはハードウェアを操作して計測や制御を行うのを得意とするプログラミング言語だったりするので、前回のようなゲームも作れる一方で、「真面目な」プログラムを作る際の参考になるかなと思い波形測定を題材にしました。
やることは違えど、似たような考え方でプログラムを組めるのだなということがわかればいいかなと思います。
なお、前の記事はこちらです。
どんなプログラムにするか
まずは例によってフロントパネルを構成します。どのような機能を付けるかを考えれば、どのような制御器、表示器が必要かというのがおのずと見えてきます。
今回のプログラムでは、以下のような動作をすることを目的にします。
- ユーザーが指定したサンプル数およびサンプリングレートを基に、ノイズが乗った正弦波を測定し、データの保存もできる
- 各操作はボタン押下によって次の操作に移る
- ユーザーは最初にサンプル数とサンプリングレートを指定し、設定完了のボタンを押すとデータ取得の準備に入る
- データ取得の準備中に取得開始のボタンを押すとデータの測定が始まり、グラフに正弦波が表示される。保存ボタンを押している間はデータが保存される
- データの測定中に設定をやり直すボタンが押されるとサンプル数およびサンプリングレートの設定に戻る
- データ測定中に終了ボタンを押すと測定が終了する
- フロントパネル上では、プログラムが今どのような状態かを表すLED(ブール表示器)があり、ユーザーが現在の状態を確認できる
これらの機能を満たす操作画面、フロントパネルはどのようなものになるか。例えば以下のような感じになると思います。
右にある5つのブール制御器のボタン(「設定完了」、「データ取得」、「設定をやり直す」、「データ保存」、「停止ボタン」)はそれぞれのラベルを日本語に書き換えていますが、この中で「データ保存」の機械的動作だけ「Latch Until Released(放されるまでラッチ)」にしていて他は全部「Latch When Released(放したらラッチ)」としています。
なお、お気づきの通り(?)ブールのボタンの種類の豊富さから、今回もまたフロントパネルは「Silver」のスタイルを採用しています。
数値制御器やブールの制御器なども全てSilverで統一した方が見た目がスッキリします。
今回も、最初に完成後の全体動作について紹介します。
プログラムを(初めて)実行する前の状態から、実行を開始させると、「初期化済み」のLEDが光ります。
間髪入れず「設定中」のLEDが光るので、この状態でサンプル数とサンプリングレートを変更します。
設定が終わったら設定完了のボタンを押します。
設定が完了すると「設定中」のLEDが消えて「設定完了」が光り、その後取得開始のボタンを押すことで「データ取得」が光ってグラフにノイズが乗った正弦波(今回の場合にはプログラム的に生成したダミー信号です)が表示されるようになります。
このとき、
- グラフ上に表示されたデータの点数:「サンプル数」として設定した値
- グラフの表示の更新頻度:「サンプリングレート」の逆数に「サンプル数」を掛けた値の秒数
という関係があります。
なので、例えばサンプル数を1000、サンプリングレートを10000としていると、一度にグラフには1000点が表示され、これが0.1秒の頻度で更新されることになります。
データ取得中に保存ボタンを押していると、押している間はそのデータが保存されます。
(押すのを止めないとずっとデータが保存され続けるので注意してください。)
もしデータ取得中に設定をやり直すボタンを押すとサンプル数などの設定変更の状態に戻りますが、停止ボタンを押すとプログラム自体が終了します。
さて、プログラム全体の流れは上記の通りです。
なんとな~く、各状態の流れがいかにもステートマシンチックだな、と感じれた方はもう自力でもプログラム書けそうですね。
まだまだ書けないよ、という方も、以下の説明で一つずつ順を追ってプログラム構築の流れを見てみてください。
必要な状態の種類について
プログラムの要件から考えられる、必要な状態としては以下が挙げられそうです。
- 初期化
- 測定の設定を決める
- 測定を開始させる
- データ取得
- 終了
前回同様、これらの状態をまずは図示してみるとこんな感じでしょうか。
「保存は独立した状態にしなくていいの?」と考えた方がいるかもしれませんが、測定はデータ取得に伴って行われるため、データ取得の状態の中で行わせるようにします。
(本来はデータ取得とデータ保存はまた別の形で分ける方がよりよいプログラムになる場合が多いです。ただしその方法を実現するための「キュー」の操作は少し難易度が高いのでこのシリーズでは扱いません)
もちろん、今回の記事で紹介するプログラムおよびそのプログラムの動きは私が勝手に考えたものなので、考えた私自身の都合のいいように状態を定義しているという点は否めません。
が、実際同様なプログラムを組む際には結局似たような構成のステートマシンを組むことが多いので、まずは「こういう組み方でできるんだな」という一例を知るという感覚で読み進めてください。
それでは、各状態から他の状態へどのように移るかを考えるため、「どの状態からどの状態に移りうるか」を考えていきます。
- 「初期化」状態からは「測定の設定を決める」状態へ移る
- 「測定の設定を決める」状態からは「測定の設定を決める」あるいは「測定を開始させる」状態へ移る
- 「測定を開始させる」状態からは「測定を開始させる」状態あるいは「データ測定」状態へ移る
- 「データ測定」状態からは「データ測定」状態あるいは「測定の設定を決める」あるいは「終了」状態へ移る
- 「終了」状態でプログラムが終了
これまた、図に状態の移り方を書き加えるとこんな感じになると思います。
状態と、どの状態からどの状態へ移るかが決まったら、あとはそれぞれの状態を指定通りにプログラムに落とし込んでいくだけです。
前回は上の図のそれぞれの矢印がどういった状態の時にその移り方をするかについても細かく書きましたが、今回は省略します。
ぜひ自力で考えてみてください。
プログラムの実装
では、プログラムの実装に移ります。
もし、この部分ももう自力でできるよ、という方はぜひチャレンジしてみてください。そして以下で紹介するプログラムと照らし合わせてみてください。
なお、「ノイズが乗った正弦波」は今回プログラムの中でダミー信号として作成するので、私が後で紹介するプログラムの例では以下の関数を使用しています。
おもむろに波形グラフというものを使用していますが、これは以下の図の箇所にあります。数値のデータをグラフとして表示するために使用できます。
すぐ隣に、よく似合たWaveform Chartというものがありますがこちらではなく、Waveform Graphが今回使用するものです(見た目が似ているのですが、使い方が違うもので、今回は適しません)。
また、データの保存については関数パレットの以下の位置にある関数を使って行うことができます。
データ保存の操作自体はWrite Delimited Spreadsheet.viが行いますが、この関数がどこにファイルを生成するかを決めるためのファイルパスの指定のためにFile Constantsの中にある関数を使用します。
これらの関数を組み合わせて以下のようなプログラムを書くことで、1D dataの結果をcsvファイルに保存することができます。
そのため、今回はダミーとして生成した正弦波信号の1次元配列を1D dataとしてみなすことになります。
Build PathもFile I/Oの関数パレットにありますが、データの保存先ファイルパスを相対パスで記述するのに頻繁に使用するものなので、File Constantsとともに使用する方法はぜひ覚えてください。
まだ自力ではできないよ、という方は以下で紹介するそれぞれの状態について見様見真似で書いてみて、それぞれでどのような処理をしているか見てみてください。
まずは初期化です。
数当てゲームの際には明示的に初期化状態を設けていなかったですが、今回はプログラムの今の状態を表すためのLEDがあるので、この状態をリセットするために設けています。
上の方にある二つの数値(オレンジの)は、後の状態で出てくるサンプル数やサンプリングレートを扱うためにここで初期化しています。
次に設定状態です。初期化状態からまず絶対にこの状態にたどり着きます。
ここではサンプル数やサンプリングレートを指定することができ、設定完了のボタンが押されない限りずっと設定状態となります。
LEDの状態としては「設定中」や「設定完了」の部分を操作している点に注意してください。
次に測定待機状態です。
今回のプログラムでは、単にデータ取得のボタンがユーザーによって押されるまで待つだけですが、例えば何か別の処理をトリガにして測定を開始させるために、そのトリガの内容をこの状態の中に記述する、といったこともできます。(今回はデータ取得のボタン押下がトリガになっていると言えます)
データ取得の状態です。
この状態から移る先は、再度データ取得か、設定をやり直すボタン押下による設定状態か停止ボタン押下による終了状態のいずれかです。
選択の関数を使用することで以下のように組む方法があります。
データの保存はデータ保存ボタンがTrueになっているときにのみ処理されます。
また、待機の関数には何やら計算された値が入力されていますが、
サンプリングレートの逆数(Reciprocal)×サンプル数×1000
という処理をしています(待機の関数の指定はミリ秒なので最後に1000を掛けています)。
最後、終了状態です。
特別説明することはあまりなく、Whileループを止めるために条件端子にTrueを配線しているだけです。
自力でできたよという方、全部が全部同じではないかもしれません。でも、どちらが正解かなんてことはなく、プログラムの目的通りに動いていればそれもまた正解だと思います。
こんなとき、どうする?
前回、今回と、経路の違うプログラムの実装について紹介してきました。
数当てゲームとデータ測定、やっていること全然違いますよね?でも、プログラムの構造は、どちらも同じ、ステートマシンなんです。
各状態の処理の内容は全然違うのでそこら辺の書き方は経験が必要ですが、これはあくまで関数の使い方の話で、プログラムの構造が同じだということがわかるということが重要です。
もう何度も書いていますが、ステートマシンを使いこなせるようになれば、かなりいろいろなプログラムが書けるようになります。
そして、ステートマシンは他のプログラムのテンプレートの基礎にもなっていたりします。なので、ステートマシンの構造をしっかり理解するというのは、LabVIEWでプログラムを組むうえでとても大切なことです。
「なんだ、LabVIEWって簡単なんだな」、という感想を持ってもらえればうれしいのですが、ここからさらにどんどんLabVIEWを使ってみようと積極的になってもらうのが一番です。
第一回目で紹介したような、以下の図のような感じに少しでも多くの方がなってくれればいいなと願っています。
ただ、これまでに紹介したステートマシンのプログラム例を基に色々プログラムを作っていくうえでで、今後こんな悩みが出てくると思います。
例えば、「状態」を追加したくなった場合のことを考えます。
処理の追加自体は、ステートマシンであれば、列挙体の項目を増やせば、ケースストラクチャにその項目も反映されるので簡単に増やせる・・・はずなのですが、実はこれをやると、ケースストラクチャのラベルに列挙体の項目名が入らなくなります。
理由は簡単で、これまで使用していた列挙体とは異なる列挙体がシフトレジスタに渡されている部分があるからです。
列挙体を配線していたシフトレジスタに赤い点がついたのは、ここでは「プログラムのどこかで異なる内容の列挙体が配線された」ことを表しています(この赤い点の本来の役割は必ずしも列挙体に対する警告を表すわけではないですが、今回は結果的にこういうことを表しています)。
これ、一つの解決策としては、全ての列挙体を更新することが挙げられます。新しく作った列挙体をコピペして、他の列挙体も全部新しくするということです。
ただし、ある程度大きなステートマシンになると、列挙体の項目数つまりケースストラクチャのケースの数が増え、いたるところに列挙体が使用されるということが起こりえます。
それらすべてを、状態が増えるたびに更新していくのはあまり得策ではありません。やり忘れるものも出てきそうですしね。
他にも、ユーザーが意図した通りの順番で操作を行わない場合にどうすればいいかという問題も挙げられます。
これはステートマシンに限った話ではありませんが、プログラムを作る人が意図したとおりの順番で操作しないユーザーがいた場合、期待した動作をしないことで、期待した結果が得られないということは十分起こりえます。
ここで挙げた2つの問題に遭遇したときにどうするか、というのはちゃんと対策があります。
本シリーズは、LabVIEWの初心者の方が少しでもLabVIEWでプログラムを書くというのはどういう感じかを、基本的だけれど十分強力なステートマシンの考え方に必要な部分に絞って紹介してきました。
その目的としては本記事で終わりなのですが、さらにもっと知りたいという方向けに、次の記事では上で書いた「こんなときどうする」についていくつかの解決方法をお伝えしようと思います。併せて、このシリーズを終えた後にLabVIEWに興味を持った方が次どのように学んでいくかについても少しだけ紹介したいと思います。
ここまで読んでいただきありがとうございました。
コメント