Arduinoについて

Arduinoはマイコン(micro computer)の一種で、 電子工作の延長で自分の作った回路を制御したり、PCとシリアル通信したりすることができる。 Raspberry piはOSが入っていて色々高級な事ができるが、 これはもっと機械よりの単純な処理が得意。ここではArduinoの種類と、その基本的な使い方を説明する。




Arduinoの種類


Arduinoには種類があり、それぞれで性能が少しずつ異なる。 ここでは、今まで使ったことがあるものについて紹介する。

arduino_uno
写真1 Arduino Uno
arduino_mega
写真2 Arduino Mega
arduino_due
写真3 Arduino Due

さらにArduinoには"シールド"と呼ばれる拡張基板があり、 電子工作で回路を作らなくてもシールドを差すだけで色々できる(参考)。 ArduinoをPLCにするシールドなんかもある(参考)。

Arduinoのプログラミング


Arduinoは買ってすぐに使えるわけではなく、自分でプログラムを書く必要がある。
Arduinoではこのプログラムを"スケッチ"と呼んでいる。
まずはスケッチを書くためのPCを用意し、Arduino IDEというソフトウェアを入れる。 次にArduinoとPCをUSB-B↔USB-Aケーブルでつなぐ。 そうすると、IDE上でポートの設定でArduinoが見つかるので、Arduinoがつながっているポートを選択する。 こうすることでArduinoにスケッチを書き込める。 スケッチの大枠は以下のようになっている。

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

書き方はC言語を踏襲している。 setupの部分はArduinoがONになったとき、resetされたときに呼ばれる処理、loopの部分はarduinoが起動後ここの処理をoffになるまで繰り返す(C言語で言うところのwhile(1){})。

Arduinoのデジタル入力について


Arduinoにはデジタル入出力のためのコネクタが有る。 これに直接電圧を加えることでON/OFFをArduinoに認識させられる。 しかし図1のように電源、スイッチ、入力ピンを直列につないだだけだとスイッチを入れていないときはどこにも繋がっていない状態になり動作が不安定になってしまう。
そこで入力端子に電圧を加えないときは抵抗等に落とすようにするPullupまたはPulldown回路というものを構築する。 以下の図2の回路図がPullupまたはPulldown回路である。

bad_example
図1 直接電圧を印加
pullup_pulldown
図2 Pullup抵抗、Pulldown抵抗

バイナリによる通信


Arduinoを使って他機器と通信する場合基本的には、 シリアル通信をすることが多い。そこで簡単に実装する方法は数値を文字として送る方法だが、 送るデータが増えると通信が遅く、または途切れることが起きてしまう。
ここでは、数値を数値(小数の場合は整数にして)のまま送受信できるバイナリ通信の方法を紹介する。

参考: Arduinoでバイナリ送受信のシリアル通信をするときのパケットの構造
Arduino側にはCOBSというデータ構造を使って通信するPacketSerialという便利なパッケージがあるのでそれをありがたく使わせてもらう。 Arduino IDEでは「スケッチ→ライブラリをインクルード→ライブラリを管理」で 右上の検索バーにPacketSerialと調べるてインストールする。 このライブラリを使う場合は必ずincludeする。

#include <PacketSerial.h>
PacketSerialでシリアル通信を行う場合、スケッチ内では以下のように初期化する。
#include <PacketSerial.h>
PacketSerial packetData;

void setup(){
  Serial.begin(9600, SERIAL_8E1);  // 8bit/packet, even parity, 1 stop bit
  packetData.setStream(&Serial);
  packetData.setPacketHandler(&onPacketReceived); //for receive serial data
}

PacketSerial packetData;はシリアル通信のためのオブジェクトで一番外側の最初に宣言する。
Serial.beginでシリアル通信を設定する。引数で通信のボードレートとオプションを指定できる。 ここでのオプションはSERIAL_8E1としているのは8bitずつのデータで偶数パリティビット(エラー検知用)付き、ストップビットは1bitという意味である(詳しくは別の機会に説明する)。
packetData.setStream(&Serial);で送信の準備ができるが、受信も行いたい場合は次のpacketData.setPacketHandler(&onPacketReceived); を付け足す。onPacketReceivedについては自分で実装する関数(メソッド)の名前なので、別にどんな名前でもいい。

整数データの送信

union共用体というものを作って、送信データの準備をする。 unionの中に送りたいデータ構造(struct{}の中身)を作って、そのデータのbyte数に合わせたuint8_tの配列を作る。
このときcharは8bitなので-128~127または0~256までの整数が使える。それ以上大きい整数は以下の小数を含んだ場合を参考にする。
union sendData {
  struct {
    char data1;
    char data2;
  };
  uint8_t bin[2];
};

以下のようにloop関数内にデータ送信を実装することでloop毎にデータを送信できる。

void loop() {
  delay(1000); // 1s wait
  sendData sdata;
  sdata.data1 = 3;
  sdata.data2 = 12;
  packetData.send(sdata.bin, 2); //send(data, datasize)
}

send()の引数はそれぞれ(データの中身、大きさ(今回は2byte))を入力する。

小数を含んだデータの送信

union共用体を作成するのは同じだがbyte数はfloatで4なのでそれを考慮する。
8bit以上の整数の場合はint(4byte = 32bit)が使える。

union sendData {
  struct {
    float roomtemp;
    float outsidetemp;
  };
  uint8_t bin[4 * 2];
};

送信は整数を送るときと同じだが、データの大きさに注意する。

プログラムの全体(例)

#include <PacketSerial.h>

union sendData {
  struct {
    char intdata;      // 整数データ
    float roomtemp;    // 実数データ
    float outsidetemp; // 実数データ
  };
  uint8_t bin[4 * 2 + 1];
};

PacketSerial packetData;
sendData sdata;

void setup(){
  Serial.begin(9600, SERIAL_8E1);  // 8bit/packet, even parity, 1 stop bit
  packetData.setStream(&Serial);
}
void loop() {
  delay(1000); // 1s wait
  sdata.intdata = 1;
  sdata.roomtemp = 24.5;
  sdata.outsidetemp = 31.1;
  packetData.send(sdata.bin, 4*2+1); //send(data, datasize)
}

データの受信

データの受信では受信用のunion共用体を用意しておくこと、受信用の関数を用意しておくことが重要。

(執筆中)