はじめに
ひょんな事から,Intel Edison Kit for Arduinoを入手したので,ちょっと遊んでみました.
ArduinoスケッチはEdisonで走ってるLinuxの一プロセスとして動いています.それならば,センサーの読み取りなどはArduinoに任せて,高度な処理(インターネットへの接続やWebサーバとか)はEdisonに任せようとか思うわけです.ちょうど,Intel Developer Zoneに
Efficient communication between Arduino* and Linux native processes
という記事があったので,紹介します.元記事がかなり丁寧でサンプルコードがあるので,ぜひ目を通してください.
なお,Edisonと書いてる部分をGalileoに読み替えても可.
3行で
- ArduinoはLinux上のプロセスとして動いている
- データのやりとりは,プロセス間でメモリ領域を共有することで行う(unixシステムコール使う)
- pthread使って,排他制御と値の変更の通知をする
以下,要約
ArduinoスケッチとEdisonで次の基準をみたすような通信をしたい
- ディスクへの書き込みをしない(diskの消耗を減らす,パフォーマンスの改善)
- イベントによってトリガーされる(定期的に読みに行ったりしない)
データのやりとり
ArduinoスケッチはLinuxで動くプロセスにすぎない.Linuxにおけるプロセス間通信の方法はいくつかあるが,この記事では「メモリ領域の共有」を利用している(memory mapped IPCって日本語で何て言うの)
排他制御
メモリ領域の共有はできた.しかし,複数のプロセスが同時に読み書きすると大変なことになってしまう.そこで,mutexを使う.この記事ではpthreadを使っている.
Lockはpthread_mutex_lock/pthread_mutex_unlock
でサンドイッチしたらよい.
pthread_mutex_lock(&mutex);
// ここで共有メモリ領域の読み書きをする
pthread_mutex_unlock(&mutex);
通知
条件変数(condition variables)を使えば実現できる.条件変数を使うと,他のスレッドが条件を送信するまで,スレッドの停止する.
例えば,Edison側でLEDのon/offを制御し,実際にGPIOを操作するのはArduinoに任せるといった場合
// Arduinoスケッチ
// dataはEdison側と共有しているとする
struct Data {
bool led_on;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
Data *data;
/*** 中略 ***/
void loop() {
pthread_mutex_lock(&(data->mutex));
pthread_cond_wait(&(data->cond), &(data->mutex)); // 条件が送信されるまで待つ
// フラグによりGPIOの電圧変える
digitalWrite(PIN, data->led_on ? HIGH : LOW);
pthread_mutex_unlock(&mutex);
}
// Edison
// LEDのon/offのフラグを変えたあと,通知をする
pthread_mutex_lock(&(data->mutex));
data->led_on = true;
pthread_mutex_unlock(&(data->mutex));
pthread_cond_signal(&(data->cond)); // 条件の送信
感想
- C++11の
std::mutex
やstd::condition_variable
使うともうちょっとスッキリしそう - Arduinoスケッチでシステムコール呼べるならsocketとかも試してみたい.