Arduinoについてある程度知識がある方は「ライブラリの作成」からどうぞ
まとめて外部ファイルを利用したい場合は「まとめて外部ファイルを利用する場合」からどうぞ
Arduinoとライブラリ
Arduinoのスケッチ(プログラム)を作成する際、いろいろな機能を追加する場合があります。こうした機能を提供するプログラムの塊を「ライブラリ」と呼びます。こうしたライブラリはいろいろな種類のものが提供されており、必要に応じて追加することができます(図1,2)。
こうしたライブラリはC/C++で書かれており、Arduinoのスケッチ(拡張子.ino)とは少し異なります。これらライブラリのプログラムをインクルードしてやることで利用可能となります。
一方で自分自身でこうしたプログラムを書くことができれば、ライブラリとして登録し、いつでも呼び出して使うことが可能となるわけです。また、一旦作成してしまえば以降C/C++であることを意識せずにArduinoのプログラムとして利用することができます。
それではこれからライブラリの作成方法を見ていきましょう。
ライブラリの作成
ライブラリを自作する際には、C/C++のプログラムを用意する必要があります。C/C++はヘッダファイル(拡張子.h)と対応するソースファイル(拡張子.cpp)からなります。(稀にヘッダファイルのみの場合なんかもあったりします。)
まずはヘッダファイルを作成しましょう。ヘッダファイルには対応するソースファイルの情報を記載します。このヘッダファイルをインクルードすることでソースファイルの中のプログラムをどのように利用するかがコンパイラ(プログラムのテキストファイルを実際のソフトウェアにする部分)に伝わり、利用することができるようになります。より正確に言うとヘッダファイルには変数や関数、クラスなどの宣言が書かれています。
試しに簡単な関数をいくつか用意したテスト用ライブラリを作ってみます。まずはスケッチを作成し、library_test.inoとします。
それではヘッダファイル、ソースファイルを用意します。ArduinoIDEの右上「…」のボタンを押し、”新しいタブ”を選択します。(図3)
図4のようなウインドウが表示されたら、名前を入力してOKを押します。今回はTestLib1.hという名前にします。同様に対応するソースファイルであるTestLib1.cppも作成します。
このとき気をつけなくてはいけないのは「インクルードガード」と呼ばれる部分です。ヘッダファイルは通常いくつかのファイルでインクルードされます。しかし、一つのヘッダファイルがひとつのプログラムで複数回読み込まれ宣言部分が何度も利用され、同じ変数や関数、クラスが多重で宣言されるのは問題となります。そのため全体で一度だけインクルードされるようにする仕組みがあります、それがインクルードガードです。
ではヘッダファイルにインクルードガード部分を記述します。TestLib1.hに次のように記述します。
#ifndef TestLib1_h
#define TestLib1_h
#endif
TestLib1_hのところは他のファイルを作成した際には(ファイル名)_hのように置き換えると良いでしょう。また最後の#endifを忘れないように注意です。この処理の意味は「プリプロセッサによってTestLib1_hが一度でも定義されていればこのヘッダファイルの中身を無視、定義されていなければTestLib1_hを定義し、ヘッダファイルの中身を展開する」といったものですが、特に意識しなくてもこういうもの、と覚えておくだけでも問題ありません。
続いてヘッダファイルの中身を記述します。簡単なクラスとメソッドだけ定義しておきます。今回はクラスTestLib1とメソッドtestMethod1()を定義します。
#ifndef TestLib1_h
#define TestLib1_h
class TestLib1{
public:
TestLib1();
~TestLib1();
int testMethod1();
};
#endif
続いてソースファイルを作成します。ソースファイルではTestLib1.hをインクルードします。またtestMethod1()は定数3を返すメソッドにしておきます。(この辺りはC++のプログラムの記法になりますので、詳細は省きます)
#include "TestLib1.h"
TestLib1::TestLib1(){
}
TestLib1::~TestLib1(){
}
int TestLib1::testMethod1(){
return 3;
}
ここまで来たら後はArduinoスケッチからこれらを利用します。Arduinoのスケッチlibrary_test.inoに次のように記述します。
#include "TestLib1.h"
TestLib1 tlib1;
void setup() {
Serial.begin(9600);
}
void loop() {
int value = tlib1.testMethod1();
Serial.println(value);
delay(1000);
}
このプログラムでは作成したTestLib1.hをインクルードし、作成したクラスTestLib1のインスタンスを作成しています。あとは結果を見るためシリアル通信をスタートしています。シリアル通信ではクラスTestLib1のtestMethod1()を呼び出しその値を1秒(1000ms)ごとに出力し続けます。
では実際にこのプログラムをArduinoに書き込み、シリアルモニタで見てみましょう(図6,7)。シリアルモニタには”3″が出力されています。
無事、自作ライブラリが完成しました!
まとめるとArduinoの自作ライブラリを作成する際は、
- C/C++形式でヘッダファイルとソースファイルを用意する
- ファイルの中身の実装
- メインのスケッチからインクルード
です。
さらに別のファイルを作成して利用することも可能です。例えばもう一つずつヘッダファイル、ソースファイルを作成し(TestLib2.h, TestLib2.cpp)、TestLib1.cppで利用することも可能です。試しにTestLib2.h, TestLib2.cppにはTestLib2というクラスを定義し、testMethod2()というメソッドを用意します。testMethod2()は単に”5″を返すメソッドです。
各ファイルを次のように記述します。
#ifndef TestLib2_h
#define TestLib2_h
class TestLib2{
public:
TestLib2();
~TestLib2();
int testMethod2();
};
#endif
#include "TestLib2.h"
TestLib2::TestLib2(){
}
TestLib2::~TestLib2(){
}
int TestLib2::testMethod2(){
return 5;
}
クラスTestLib1ではTestLib2をインクルードし、新たにメソッドtestMethod3()、フィールドとしてTestLib2のインスタンスを用意します。testMethod3()はtestMethod1()とtestMethod2()を足した整数を返すので、常に3+5=8を返すはずです。
#ifndef TestLib1_h
#define TestLib1_h
#include "TestLib2.h"
class TestLib1{
public:
TestLib1();
~TestLib1();
int testMethod1();
int testMethod3();
TestLib2 tlib2;
};
#endif
#include "TestLib1.h"
TestLib1::TestLib1(){
}
TestLib1::~TestLib1(){
}
int TestLib1::testMethod1(){
return 3;
}
int TestLib1::testMethod3(){
return testMethod1() + tlib2.testMethod2();
}
スケッチの方はこれまでtestMethod1()を利用していたところをtestMethod3()として、同様に出力してみます。
#include "TestLib1.h"
TestLib1 tlib1;
void setup() {
Serial.begin(9600);
}
void loop() {
int value = tlib1.testMethod3();
Serial.println(value);
delay(1000);
}
結果は図8のようになりました。testMethod3()の戻り値である8が1秒おきに表示されます。
このように複数のライブラリファイルを連携させることも可能です。
まとめて外部ファイルを利用する場合
これまではライブラリ化するプログラムもまとめてArduino IDE上で作成していましたが、外部から複数のファイルをまとめて取り込んで、ライブラリとして利用することも可能です。その場合は直接すべてのファイルをスケッチファイルと同一のディレクトリに置くのでも良いのですが、zipファイルでまとめてしまうことも可能です。
まずはこれまで作成したファイルであるTestLib1.h, TestLib1.cpp, TestLib2.h, TestLib2.cppをTestLib1というディレクトリの直下にすべて置くこととします(図9)。このディレクトリTestLib1をzipファイルとして圧縮します。今回はTestLib1.zipとします。
また、今回はlibrary_zip_test.inoというスケッチを作成します。メニューから”スケッチ→ライブラリをインクルード→.ZIP形式のライブラリをインストール…”を選択します(図10)。ファイル選択で先ほど作成したTestLib1.zipを選択します。
これでライブラリのインストールは完了です。それではlibrary_zip_test.inoからTestLib1を利用してみます。library_zip_test.inoを以下のように記述します。先程のlibrary_test.inoとほぼ同様です。
#include "TestLib1.h"
TestLib1 tlib1;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(tlib1.testMethod3());
delay(1000);
}
これでシリアルモニタでtestMethod3()の戻り値である8が1秒おきに出力されるはずです。
今回ライブラリをインストールしたことにより、Arduinoのスケッチが保存されるディレクトリと同じディレクトリにlibrariesという名前のディレクトリが作成されているはずです。作成したライブラリファイルはその中に置かれています(図11)。
加えて以降は”スケッチ→ライブラリをインクルード”からTestLib1が選択可能となっています(図12)。
以上まとめると
- 利用する外部ファイルを用意する
- ディレクトリを作成し、外部ファイルをすべて入れる
- 作成したディレクトリをzipファイルとして圧縮
- Arduino IDEからzipファイルを選択し、インストール
となります。
さらに作り込むには…
今回の手順でArduinoで外部ライブラリが利用可能となりますが、より詳しく設定したり、配布する場合はkeywords.txtやlibrary.propertiesといったファイルを用意する必要があります。
更に深掘りして自分なりのライブラリを作成する場合は以下が参考になります。
https://docs.arduino.cc/learn/contributions/arduino-creating-library-guide
またライブラリはC/C++で記述されるため、より作り込むためにはC/C++の知識が必須となります。