IoT対応ソーラートラッカー:Arduinoによるスマートエネルギー管理
部品と材料
| 部品 | 数量 | 備考 |
|---|---|---|
| Arduino Mega 2560 | 1 | |
| Ethernetシールド(Wiznet W5100) | 1 | Arduino用 |
| SG90マイクロサーボモーター | 2 | |
| LDR(光依存抵抗)5MΩ | 4 | GL5528相当 |
| DHT22温湿度センサー | 1 | |
| 小型ソーラーパネル | 1 | 115×85mm、1.6W、最大6V出力 |
| 抵抗 330Ω | 4 | LDR用分圧回路 |
| 抵抗 10Ω(スルーホール) | 2 | 電圧/電流測定用分圧 |
| 抵抗 220Ω | 1 | LED用 |
| 5mm赤色LED | 1 | 動作モード表示用 |
使用するアプリ・オンラインサービス
- myDevices Cayenne(IoTプラットフォーム)
- Arduino IDE
プロジェクト概要
本プロジェクトは、二軸ソーラートラッカーシステムを監視・制御するための、シンプルかつ低コストなIoTソリューションを提示します。
システム構成
図1に示す通り、本システムはLDRセンサーで太陽の位置(光強度)を検出し、Arduino Megaがデータを処理して2つのサーボモーター(SM1:左右、SM2:上下)を駆動し、PVパネルを太陽に向けます。同時に、PV電圧・電流、温度、湿度のデータも取得し、Ethernetシールド経由でクラウド(Cayenne)へ送信。ユーザーはスマホやPCのダッシュボードでリアルタイムにそれらを可視化できます。
手動モードでは、ダッシュボードのスライダーからサーボ角度を直接指示可能。また、閾値到達時にはSMS/メールでアラート通知も飛ばせます。

ハードウェア設計
図2はハードウェア構成を示します。主要構成要素は以下の通りです。
- PVパネル:115×85mm、1.6W、最大6V出力
- サーボモーター:左右用(MG996R、PWMピン5)、上下用(SG90、PWMピン6)の2軸制御
- LDRセンサー×4:パネル四隅に配置、アナログピンA0〜A3接続。330Ω直列抵抗で分圧回路を構成し、10bit ADC(0〜1023)でデジタル値化
- DHT22:温度-40〜80℃(±0.5℃)、湿度0〜100%(±2%)、デジタルピン2接続
- PV電圧/電流測定:10Ω×2直列の分圧回路で負荷兼用、アナログピンA4へ出力
- モード表示LED:デジタルピン3、自動/手動を表示
- Arduino Mega + Ethernetシールド(W5100):RJ45でルーター/PCと接続、TCP/UDPスタック内蔵

ソフトウェア設計
a. Arduino IDE
C/C++ベースの統合開発環境で、USB経由でスケッチを書き込みます。本プロジェクトの全制御ロジックはArduino Mega上で動作します。
b. myDevices Cayenne
MQTTプロトコル(TCP/IPベースのPub/Sub)を用いてデバイスとクラウドを接続するIoTプラットフォーム。Arduino側ではCayenneMQTTEthernetライブラリを使用し、認証情報(ユーザー名、パスワード、クライアントID)をダッシュボードから取得してCayenne.begin()で接続確立。センサー用にCAYENNE_OUT(VIRTUAL_CHANNEL)、アクチュエーター用にCAYENNE_IN(VIRTUAL_CHANNEL)を定義し、Cayenne.loop()で定期実行します。バーチャルチャネルは物理ピンに依存せず、ウィジェットとセンサー/アクチュエーターを紐付ける論理チャネルです。
c. 組み込みソフトウェア設計
二つの動作モードを持ちます:
- 手動モード:ダッシュボードのボタンがOFF時。ユーザーがスライダーで左右/上下サーボを直接操作。
Cayenne.loop()でセンサーデータも送信継続。 - 自動モード:ボタンON時。図4のアルゴリズムで太陽追尾を実行。
- 左右(垂直軸):左側2つと右側2つのLDR平均値を比較。差が閾値(±10)以内なら停止、左が大きければ時計回り、右が大きければ反時計回りに回転。
- 上下(水平軸):上側2つと下側2つの平均値で同様に制御。
- 自動モード中も
Cayenne.loop()でデータ送信継続。

d. IoT監視アプリケーション開発
(i) ハードウェアとCayenneのインターフェース
- Cayenne myDevicesでアカウント作成・ログイン
- 「Bring Your Own Things」からMQTT認証情報を取得
- 認証情報をスケッチに記述し、コンパイル・書き込み後、シリアルモニタで接続ログ確認
- デバイスがオンラインになるとダッシュボードに自動表示
- 「Add new → Device/Widget → Custom Widgets」で各センサー/アクチュエーターのウィジェットを作成(チャネル番号はコードと一致させる)。センサーは「Value」、モード切替は「Button」、サーボは「Slider」ウィジェットを使用

(ii) アラート機能の設定
「Add new → Trigger」でイベントとアクションを定義。例:温度が閾値到達でメール通知など。SMS/メール/両方、または指定アクション実行が可能。

プロトタイプ
図12は分解/組立状態のプロトタイプ。パネルは上下サーボ片側と反対側ベアリングで支持し、スムーズな水平回転を確保。LDRは四隅の筒内に配置し、パネルが太陽に垂直でない場合は少なくとも1つのLDRが影を受け、光量差が生じる仕組み。図13は完成したシステム全体像です。

詳細な実験結果については、以下の論文を参照してください:
https://link.springer.com/chapter/10.1007%2F978-3-030-64565-6_4
組み込みコード
/***************************************************************
* PROJECT: IoT based solar tracker system / the embedded software
* Aboubakr El Hammoumi / aboubakr.elhammoumi@usmba.ac.ma
***************************************************************/
#define CAYENNE_PRINT Serial
#include
#include
#include
#define DHTTYPE DHT22
#define DHTPIN 2
DHT dht(DHTPIN, DHTTYPE);
// MQTT認証情報(実際にはダッシュボードから取得したものに置き換え)
char username[] = "498d2d00-afe2-11ea-883c-638d8ce4c23d";
char password[] = "ab4a8f92d94033c01f6e18ce1d8a84d8c304c9c4";
char clientID[] = "17798a40-b968-11ea-93bf-d33a96695544";
Servo servo_x; // 上下サーボ
int servoh = 0;
int servohLimitHigh = 170;
int servohLimitLow = 10;
Servo servo_z; // 左右サーボ
int servov = 0;
int servovLimitHigh = 170;
int servovLimitLow = 10;
int topl, topr, botl, botr;
int threshold_value = 10;
float Vout;
void setup() {
Serial.begin(9600);
Cayenne.begin(username, password, clientID);
servo_x.attach(5);
servo_z.attach(6);
dht.begin();
pinMode(3, OUTPUT);
digitalWrite(3, LOW);
}
void loop() {
// LDR読み取り(ピン番号は実装に合わせて調整)
topr = analogRead(A2);
topl = analogRead(A3);
botl = analogRead(A4);
botr = analogRead(A5);
// PV電圧測定(A1ピン、分圧比考慮)
Vout = (analogRead(A1) * 5.0) / 1023;
Serial.println(" Manual-mode");
Cayenne.loop();
if (digitalRead(3) == HIGH) { // LED=HIGH → 自動モード
Serial.println(" Automatic-mode");
servoh = servo_x.read();
servov = servo_z.read();
int avgtop = (topr + topl) / 2;
int avgbot = (botr + botl) / 2;
int avgright = (topr + botr) / 2;
int avgleft = (topl + botl) / 2;
int diffhori = avgtop - avgbot; // 水平軸(上下)差分
int diffverti = avgleft - avgright; // 垂直軸(左右)差分
/* 水平軸(上下)追尾 */
if (abs(diffhori) <= threshold_value) {
servo_x.write(servoh); // 停止
} else {
if (diffhori > threshold_value) {
Serial.println(" x - 2 ");
servo_x.write(servoh - 2); // 時計回り
if (servoh > servohLimitHigh) servoh = servohLimitHigh;
delay(10);
} else {
servo_x.write(servoh + 2); // 反時計回り
if (servoh < servohLimitLow) servoh = servohLimitLow;
delay(10);
}
}
/* 垂直軸(左右)追尾 */
if (abs(diffverti) <= threshold_value) {
servo_z.write(servov); // 停止
} else {
if (diffverti > threshold_value) {
servo_z.write(servov - 2); // 時計回り
if (servov > servovLimitHigh) servov = servovLimitHigh;
delay(10);
} else {
servo_z.write(servov + 2); // 反時計回り
if (servov < servovLimitLow) servov = servovLimitLow;
delay(10);
}
}
}
}
// --- Cayenne コールバック関数 ---
// モード切替ボタン(チャネル8)→ LEDピン3
CAYENNE_IN(8) {
int value = getValue.asInt();
CAYENNE_LOG("Channel %d, pin %d, value %d", 8, 3, value);
digitalWrite(3, value);
}
// 上下サーボ手動制御(チャネル7)
CAYENNE_IN(7) {
if (digitalRead(3) == HIGH) {
// 自動モード時は無視
} else {
servo_x.write(getValue.asDouble() * 180);
}
}
// 左右サーボ手動制御(チャネル6)
CAYENNE_IN(6) {
if (digitalRead(3) == HIGH) {
// 自動モード時は無視
} else {
servo_z.write(getValue.asDouble() * 180);
}
}
// センサー送信(CAYENNE_OUT)
CAYENNE_OUT(0) { // 電流
float current = Vout / 10;
Cayenne.virtualWrite(0, current);
Serial.print("Current: "); Serial.println(current);
}
CAYENNE_OUT(1) { // 電圧
float voltage = Vout * 2;
Cayenne.virtualWrite(1, voltage);
Serial.print("Voltage: "); Serial.println(voltage);
}
CAYENNE_OUT(2) { Cayenne.virtualWrite(2, topr); } // LDR右上
CAYENNE_OUT(3) { Cayenne.virtualWrite(3, topl); } // LDR左上
CAYENNE_OUT(4) { Cayenne.virtualWrite(4, botl); } // LDR左下
CAYENNE_OUT(5) { Cayenne.virtualWrite(5, botr); } // LDR右下
CAYENNE_OUT(10) { // 電力
float power = (Vout * 2 * Vout) / 10;
Cayenne.virtualWrite(10, power);
Serial.print("Power: "); Serial.println(power);
}
CAYENNE_OUT(11) { // 温度
float t = dht.readTemperature();
Cayenne.virtualWrite(11, t, TYPE_TEMPERATURE, UNIT_CELSIUS);
Serial.print("temperature: "); Serial.println(t);
}
CAYENNE_OUT(12) { // 湿度
float h = dht.readHumidity();
Cayenne.virtualWrite(12, h);
Serial.print(" humidity: "); Serial.println(h);
}
回路図
製造プロセス
- ソーラートラッカー V2.0 – 高度なDIYソーラーパネル追尾システム
- インダストリアルIoTで成長を掴む:コスト削減を超えた収益創出へ
- IoT実践者を駆動するもの:業界リーダーからの洞察
- 1000万デバイス接続達成:Bosch IoT Suiteの歴史的成長
- ブロックチェーン×IoT:安全で分散型のデータ交換を実現
- IoT環境のセキュリティ確保:主要な脅威と戦略的ソリューション - パート2
- IoTセキュリティの未来志向:より安全なつながる世界への専門家戦略
- モノのインターネットへの投資:成長と価値の解き放ち
- IoTの真の進化を辿る:バズワードの先にある歴史
- IoT:データの波を制してビジネス変革を実現する
- IoTが直面する5つの主要課題:セキュリティ、規制、互換性、帯域幅、顧客期待