ハードウェアと連携するソフトウェアを作った
やったこと
- 入力用スイッチ3つ
- 押下中は緑四角を表示
- どれか1つでも押されているとLEDを発光
要求を定義し、実装方法を考えた。
要求1. ハードウェアの変化(入力)を素早く検出する
「他処理を実行中のためボタンの入力検出ができなかった」といったことがないように、ハードウェアの変化検出を別スレッドとして常時動作させるようにした。
要求2. イベント駆動で処理する
スイッチを押して画面を変化させる場合、スイッチを押したというイベントと、画面を変化させるという処理の対応付けが必要になる。イベントなどの状態変化に応じた処理を行う場合、デザインパターンのObserverが有効である。今回はObserverの実装の1つであるQtのシグナル/スロットを利用した。なお、Qtではイベントのことをシグナルと表現している。
開発環境
JetsonでのQt開発開発環境の構築はこちらを参照のこと。
- ホスト(Ubuntu)
- ターゲット(Jetson TX1)
- タクトスイッチ x 3個
- GUI画面
- LED
回路図
絵はラズパイだがJetsonのGPIOポートとして見ること。割当表はこれ。
実装例
ソースコード全体はGithubを参照。
以下のソースコードは説明のために簡略化している。
スイッチの状態監視
Switch
クラスでスイッチの状態監視およびイベント通知を行う。
QThread
を継承させることで、スレッド処理ができるようになる。
run()
内でスイッチの状態を監視し、状態が変化した場合switch_event
シグナルを発生させる。
class Switch : public QThread, public Gpio {
Q_OBJECT
...
protected:
void run();
signals:
void switch_event(Switch::SwitchEvent event);
};
Switch
オブジェクトのコンストラクタにて、start()
を実行する。
start()
を実行すると、run()
が別スレッドとして動作する。
Switch::Switch(int p, Direction d, int v) :
...
{
// start thread
start();
}
run()
ではスイッチの状態を取得し、値に応じてシグナルを発生させる。
スイッチの状態が変化するとswitch_event
シグナルが発生する。
void Switch::run()
{
while(true){
getValue();
if(1 == value){
emit switch_event(SW_PUSH);
} else {
emit switch_event(SW_RELEASE);
}
}
}
イベントに応じた画面制御
connect
関数で、イベント(シグナル)とそれに応じた処理を設定する。
w
オブジェクトは、画面制御を行うMainWindow
オブジェクトである。
以下は、sw1
オブジェクトのswitch_event
シグナルが発生した場合、w
オブジェクトのsw1_event
関数が呼ばれることを意味している。
connect(sw1, SIGNAL(switch_event(Switch::SwitchEvent)), w, SLOT(sw1_event(Switch::SwitchEvent)));
sw1_event
関数では、押されたスイッチのFrameをスタイルシートにより緑色にする処理を行っている。
void MainWindow::sw1_event(Switch::SwitchEvent event)
{
setFrameSWStyleSheet(ui->frame_sw1, event);
checkSWState();
}
checkSWState
関数では、スイッチの状況に応じてLEDの発光/消灯を行うled_event
シグナルを発生させる。
void MainWindow::checkSWState()
{
if(ui->frame_sw1->styleSheet() == "background-color:Green" ||
ui->frame_sw2->styleSheet() == "background-color:Green" ||
ui->frame_sw3->styleSheet() == "background-color:Green" ){
emit led_event(Led::LedEvent::LED_ON);
} else {
emit led_event(Led::LedEvent::LED_OFF);
}
}
LEDの点灯制御
LEDの点灯程度なら一瞬で処理が終わるが、ハードウェア処理に時間がかかる場合は画面制御とは別のスレッドで実行する必要がある。ハードウェア制御を画面制御と同じスレッドで処理する場合、ハードウェア制御が終わるまで画面が固まってしまう。
これを避けるために、QThread
オブジェクトを使用し、LEDの発光制御を行うled
オブジェクトをmoveToThread
でスレッド処理にする。
Led *led = new Led(511, Gpio::OUT);
QThread* th_led = new QThread;
led->moveToThread(th_led);
th_led->start();
w
オブジェクトのled_event
シグナルが発生した場合、led
オブジェクトのled_event
関数が呼ばれるように設定する。
connect(w, SIGNAL(led_event(Led::LedEvent)), led, SLOT(led_event(Led::LedEvent)));
led
オブジェクトのled_event
関数では、状態に応じてLEDの点灯制御を行う。
void Led::led_event(Led::LedEvent event)
{
LED_ON == event ? setValue(1) : setValue(0);
}
補足
Observerパターンの実装は他にもBoost Signal2が有名らしい。QThread
に依存しない設計にしたい場合はこれを使うと良い。
Author And Source
この問題について(ハードウェアと連携するソフトウェアを作った), 我々は、より多くの情報をここで見つけました https://qiita.com/otomon10/items/d11c57926dfa7d40863b著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .