DrogonとRaspberryPiでLチカ
皆様こんにちは、あるいはこんばんは、みじんこきなこです。
さて今回は、やろうやろうと思っていてやってこなかった、RaspberryPiとDrogon、そしてWiringPiを使ってLチカを行ってみます。
以前の記事でも触れたとおり、C++で書かれたDrogonは、本格的なMVCフレームワークの機能を有しているにもかかわらず、駆動時に消費するハードウェアリソースが非常に少ないため、IoT機器との親和性が非常に高いです。
通常IoT機器というと、エッジ側の低機能な機器を、WWWを介して高機能な制御側システムから制御してやる構成が多いですが、Drogonを用いることで機器制御からHttpResponceまで自己完結するエッジ機器をかんたんに作成することができます。
今回の環境
とりもなおさず今回は、手元にあった機器で以下のような環境で構築を行います。
RaspberryPi 4
UbuntuServer 20.04LTS
RaspberryPiにUbuntu Serverをセットアップする方法は、日本語でも山ほど知識が転がっておりますので、説明はそちらにおまかせします。
GPIOにLEDをつなぐ
RaspberryPiのGPIOは高電圧から保護するための回路が積まれていないので、5Vに繋いだデバイスを引き込みで駆動しないよう注意しましょう。
LEDの繋ぎ方としては二通りあります。
LEDのアノードを3.3V(1pin または 17pin)、カソードを任意のpinに繋いで引き込む
LEDのカソードをGND(6,9,14,20,25,30,34,39いずれか)、アノードを任意のpinに繋いで3.3V出力する
つなぐときは必ずカソード側からつなぐようにしましょう。
また、特に引き込みで行う場合RasberryPiのGPIOの定格電流は0.5mAなので、それ以下になるように抵抗を配置して、過電流から回路を保護しましょう。
WiringPiのインストール
通常 WiringPi は、OSがDebian系であれば apt を使用してインストールすることができます。
ただしこれによってインストールされたパッケージでGPIOを正しく駆動することができるのは、RaspberryPi3までです。
RaspberryPi4以降で使用する場合は、公式の手順に従って以下のようにパッケージをインストールする必要があります。
cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.debsudo
dpkg -i wiringpi-latest.deb
WiringPiのインストールまでできれば、下準備は完了です。
Projectの作成
プロジェクトの作成方法はこちらの記事を参照してください。
Viewの作成
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta name="description" content="DrogonのIoT利用サンプル">
<meta name="keywords" content="Drogon,CSS,MVCフレームワーク,C++,高速">
<meta name="Mizinko-Kinako" content="MKnote">
<meta name="copyright" content="Mizinko-Kinako">
<meta charset="UTF-8">
<title>サンプルLogin</title>
</head>
<body>
<form action="/Blinker/" method="post">
<p>
<label>何回光らせようか?</label>
<input type="text" name="Blink_count" placeholder="光らせたい回数を入れてね!" />
</p>
<p>
<button type="submit">Let's Blink!</button>
</p>
</form>
</body>
</html>
簡易なViewですが、テキストボックスに点灯させたい回数を入力して、Let's Blink!ボタンを推すと、RaspberryPiに接続されたLEDをテキストボックスに入力された回数で明滅させます。
Controllerの作成
コントローラのスキャフォールド作成方法は、こちらの記事を参考にしてください。今回のコントローラの全容はこんな感じ。
Blinker.h
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
class Blinker : public drogon::HttpController<Blinker>
{
public:
METHOD_LIST_BEGIN
METHOD_ADD(Blinker::get, "/", Get); // path is /Blinker/submit
METHOD_ADD(Blinker::doBlink, "/", Post); // path is /Blinker/submit
METHOD_LIST_END
void get(
const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback
);
void doBlink(
const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback
);
};
Blinker.cc
#include "Blinker.h"
#include <wiringPi.h>
void Blinker::get(
const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback
)
{
auto response = drogon::HttpResponse::newHttpViewResponse("Blinker.csp");
callback(response);
}
void Blinker::doBlink(
const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback
)
{
auto ss = std::istringstream(
req->getParameter("Blink_count")
);
auto max_count = 0;
auto response = drogon::HttpResponse::newHttpViewResponse("Blinker.csp");
ss >> max_count;
wiringPiSetupGpio () ;
pinMode (17, OUTPUT) ;
for (auto i = 0; i < max_count; ++i)
{
digitalWrite (17, HIGH) ; delay (500) ;
digitalWrite (17, LOW) ; delay (500) ;
}
digitalWrite (17, LOW) ; delay (500) ;
callback(response);
}
今回はサンプルとして簡易に実行時間の長いループで処理を行っていますが、実用する際にはこのような長期の機器の専有は望ましくありません。特に物理的な実態を持つモータやセンサ類などは、プログラムの実行速度と比べて圧倒的に動作に時間がかかりますので、機器制御部分は適宜スレッドを立てて実行を抜けるなど工夫が必要です。
GetとPost今回はメソッドとしてGetとPostを使用しています。Getでは入力画面を表示させ、PostではHTTPリクエストにセットされてきた明滅カウントを取り出してその回数分ループを回す構成です。
WiringPiの使用
ヘッダをインクルードすることで、WiringPiのライブラリの機能を呼び出すことができるようになります。
#include <wiringPi.h>
Lチカコード
wiringPiSetupGpio () ;
pinMode (17, OUTPUT) ;
for (auto i = 0; i < max_count; ++i)
{
digitalWrite (17, HIGH) ; delay (500) ;
digitalWrite (17, LOW) ; delay (500) ;
}
digitalWrite (17, LOW) ; delay (500) ;
こちらはお決まりのLチコードですね。今回私はGPIOの11pinをアノード、14pinのGNDをカソードに接続して使用しています。
RaspberryPiのGPIOを出力で使用する場合は1pinあたり16mAしか電流を取り出せないので、大出力のLEDの駆動には適宜外部の電源をトランジスタやMOS-FETなどで引き込む、電源回路の接続が必要になります。今回使用したLEDは十分駆動するものなので特に使用していません。
出力Pinの物理的なPin番号は11pinですが、論理的なPin番号は17となっています。
電源線やGND先には内部的な番号が振られているわけではないので、物理的なPin番号と論理的なPin番号は異なってきます。
このあたりは、公式ドキュメントを参照することで確認できます。
Postのレスポンス
auto response = drogon::HttpResponse::newHttpViewResponse("Blinker.csp");
callback(response);
特に凝った作りをせず、入力画面を再度そのままクライアントに返しています。
ステータスコードだけ返すような形にすれば、Postで与えられた回数光らせてステータスを返すだけのAPIに改造することができます。
その場合はnewHttpViewResponseの部分を、newHttpResponseを差し替えてください。
CMakeLists.txtの編集
今回のテーマを選定した大きな理由の一つが、この項目です。
Drogonは予め書かれたCMakeLists.txtによってプロジェクトのビルドルールが定義されていますが、サードパーティの提供するライブラリを使用する場合には、このビルドルールに使用を明示してやる必要があります。
今回使用しているWiringPiも、単純にインストールしただけでは使用できず、ライブラリをビルドルールに追加する必要があります。
以下のように一行をCMakeLists.txtに追加します。
target_link_libraries(${PROJECT_NAME} PRIVATE wiringPi)
ビルド
ビルドの手順はこちらの記事を参照してください。
実行
ビルドしてバイナリを実行したら、ブラウザから以下のアドレスにアクセスしてみましょう。
http://[RaspberryPiのIP]:[自身の設定したポート]/Blinker/
ページが表示されて、回数を入力したあとにボタンをおした際、その回数分LEDが明滅することが確認できれば成功です。
さいごに
今回は、RaspberryPiを使用したGPIOの制御でしたが、例えばGrove base HATを使用しつつboost/pythonなどを使用して高度な制御を組み、高機能なノードをSPAとして構築したダッシュボードのコンポーネントとして使用するだとか、複雑なシステムを構築しなくても電源を入れれば同一ネットワーク上からReadyになるセンサデバイスを、低コストで量産してレイアウト変更が多い工場や物流拠点で使用するなど、様々な応用のきく内容です。
要は普通のRaspberryPiなら一セット数千円、信頼性の高い産業用RaspberryPiでも3,4万円投資するだけで、簡易かつ迅速に旧来の機器をIoT化できてしまいます。
そのようなメリットを生み出せるのも、C++という言語で開発され、高速且つローフットプリントで駆動するDrogonの特性あってのものです。
皆様ももし自社設備のIoT化で予算の獲得に困ったら、この仕組みを試してみてください。
それではよいお年を。