AMG8833によるソーラーパネル太陽追尾装置
概要
AMG8833(サーモパイルアレー8X8)モジュールがあったので、太陽追尾装置を作ってみた。
AMG8833は人体温度等を感知するセンサ(0~80°)で6000℃の太陽の温度、位置は(やはり)検知出来なかったが低い温度データー?が出てくるので低い温度の位置を追うことで(いきあたりばったり)太陽追尾装置をつくってみた。
実際太陽は雲に隠れたりして追尾が不安定になるので、簡易赤道儀と組み合わせ基本は赤道儀を回転させながら追尾し太陽が出てきた時誤差を調整するようにした。
またソーラーで充電しながらバッテリ駆動を目指し,省電力回路を工夫した。
AMG8833太陽温度Data(温度Dataが低いところが太陽の位置)
(注 AMG8833をスペック外で使用し、高価なデバイス破壊など恐れもあり万一実験されるときは自己責任でお願い致します。)
動作
簡易赤道儀を作り東西 南北にサーボで1°ずつ回転できるようにし、ソーラーパネルとAMG8833を赤道儀に組み込む。
東西に回転させるサーボの軸が真南に55℃の高さになるよう赤道儀を設置
①早朝空が白み始めるとALL_OFFSWがONしソーラーパネルを赤道儀の東あたりの日の出方向に向ける。
設定後SLEEPし4分ごとにWAKEUPして1度西に回転しながら日の出を待つ。
②太陽がでてくると東西 南北に微調整し太陽をLOCK_ONした後SLEEPにはいり4分ごとに1度西に回転
③日中もSLEEPし4分ごとにWAKEUPして1度西に回転。この時ずれがあると再度微調整する。
(曇っている場合も同様に早朝から赤道儀に沿って4分ごとに1度西に回転 一度太陽LOCK_ONするとあとは赤道儀で追尾できる)
④日の入りになり赤道儀の西あたりまで回転するとSLEEPのまま停止
⑤空が暗くなるとALL_OFFSWがOFFし早朝まで完全停止。おやすみなさい、ご苦労様でした(-_-)zzz
動作詳細
太陽の位置は8X8サーモパイルで温度データーの一番高いところの位置を計測(実際は失敗)
デバイス指向角は60度で太陽の動きで南北は 南中角55度(北緯35度)+ー23.4度(夏至 冬至)=変化は46.8度=指向角の中に入る。 東~西の変化は180度(日の出~日の入り)=指向角には入らない。従ってサーモパイルを空に向け固定していては東~西の太陽の位置はカバーできない。
この対策としてサーモパイルをソーラーに固定しサーモパイルを常に太陽におよそ向くようにし、向きが少しずれると太陽温度データー位置をサーモパイルの真ん中に来るようにソーラーの向きを正確に太陽に合わせ太陽を追尾する方法にした。これにより日の出~日の入りもサーモパイルを太陽の方向に向かせることが出来、東~西180度変化する太陽追尾を可能とした。
ソーラーパネルの方向の変化は 簡単な太陽赤道儀を作り2つのサーボを直角に固定し南北サーボ:55°✙24°(夏至)~55°-24°(冬至) 東西サーボ:0~180°(日の出~日の入り)向きを変えている。太陽の出ていないときはおよそ赤道儀で動かし、太陽が出ている時サーモパイルで太陽に向け正確に合わせる。
サーモパイルデーターから太陽を追尾する2つのサーボの動きはAruduinoNANOで行っている。
省電力
①FETSWによる電源OFF
夜間は太陽追尾は不要なので、回路アースとバッテリ(ー)の間にFETSWを入れ、FET_Gate(th:1v)にソーラーを接続し 夜間(起電力<1v)はFETSWoffし電力を全く消費しない。
②Sleepによるマイコン停止
夜明けからマイコンで4分ごとにサーボ駆動し赤道儀を1度回転させ太陽と誤差があれば調整する。日の入り後はFETSWoffまで連続sleep。
駆動していない間の4分間はsleepでマイコン停止し電流を25mA(駆動時)から10mA(sleep)に減らしている。(NANOに載っている電源LED 通信LEDも直列抵抗を外し消灯)
時系列
夜 /夜明け 日の出 日の入 夕暮れ / 夜
FETSWON➤ーーーーーーーーーーーーーーーーーーーーーーーーーー➤/OFF
熟睡~~ /sleep4分/1°回転 / 太陽LockOn sleep4分/1°回転 / sleep連続---------- /~~~~熟睡~~
回路図
部品
部品名 | 備考 |
---|---|
AMG8833モジュール | ソフトはAddress:69hに設定 秋月 スイッチサイエンス |
ArduinoNANO | 省電力の為 載っている電源LED 通信LEDの直列抵抗は外して消灯 |
AG90 | ソーラーパネルの向きを動かすサーボ 東西1個 南北1個使用 |
MOSFET_N | L6344 秋月 電源SWとしてVgs(th)1v位(=熟睡の閾値)のものであればよい |
schottky_diod | SD103 秋月 Vfの小さい物であればよい |
ソーラーパネル | 5V 2W |
18650 | Lithium Battery 容量9900mAh AliExpress |
TP4056 | 過充電保護 AliExpress |
MT3608 | DC-DC 出力5Vに調整 AliExpress |
SolarTracker
/*******************************************************************************
// Solar Tracking program using AMG8833 ArduinoNANO
// By Syouwa Taro
*******************************************************************************/
#include <Wire.h>
#define PCTL 0x00
#define RST 0x01+
#define FPSC 0x02
#define INTC 0x03
#define STAT 0x04 //SDA
#define SCLR 0x05 //SCL
#define AVE 0x07
#define INTHL 0x08
#define TTHL 0x0E
#define INT0 0x10
#define T01L 0x80
#define AMG88_ADDR 0x69 // IIC68h:default 69h:jumper address set
//temporaryData to buffer sumtotal
int TMPDAT1[65], TMPDAT2[65], TMPDAT3[65], TMPDATS[65];
int TMPVS[8]; //TemperatureVerticalsum=TMPVS[0]:EEESum ~ TMPVS[7]:WWWWSum
int TMPHSns[8]; //TemperatureHorizontalsum=TMPHSns[0]:NNNSum ~ TMPHS[7]:SSSSSum
int VSminL[3] = {4, 4, 4 }; //サーモセンサ正面 verticalSumax HorizontalAngle ([0]:Servo決定 [1]:Buffer [2]:New = 0:RRRR ~4:center~ 8:LLLL)
int HSnsminL[3] = {4, 4, 4 }; //サーモセンサ正面 HorizontalSumax VerticallAngle ([0]:Servo決定 [1]:Buffer [2]:New = 0:NNNN ~4:center~ 8:SSSS)
int TMPVSmax = 0 ;
int TMPHSnsmax = 0 ;
int VSmin = 3000 ;
int HSnsmin = 3000 ;
int maxmin ;
int nsmaxmin ;
int SA ; //eeprom//= 90 ; // ServoAngle Left 0~40度 SP正面40~50度 Right 50度~90度
int SAns ; //eeprom// = 90 ; // ServoAngle Left 0~40度 SP正面40~50度 Right 50度~90度
#include "avr/sleep.h"
#include "avr/wdt.h"
#include <Servo.h> // Servoライブラリの読み込み
Servo sg90; //Servo myservo; // Servoオブジェクトの宣言
Servo sg90ns; //Servo myservons
const int SV_PINew = 7; // サーボモーター(E~W)をデジタルピン7に
const int SV_PINns = 8; // サーボモーター(N~S)をデジタルピン8に
int PIN_ANALOG_INPUT = A7 ; //solarValue入力をアナログピンA7:SPWV/2024*5=solarVoltage
double SPWV ; //パネル電圧=SPWV/1024*5 =Solar電圧(FETSWon:1.5~1.8V)-DiodeVf
int WakeUpPin = 2; //sleep復帰ピン: 復帰は復帰ピンでなくFETPWoff/on RESETで行う
#include <EEPROM.h> //EEPROM ServoAngle memory=RESETで復帰しないで前の状態からスタート
void setup()
{
Serial.begin(115200);
Wire.begin();
//IIC SCL:A5 SDA:A4 AMG8833(Jumperで変更可能)address 68 69
int fpsc = B00000000;// 1fps
datasend(AMG88_ADDR, FPSC, &fpsc, 1);
int intc = 0x00; // diff interrpt mode, INT output reactive
datasend(AMG88_ADDR, INTC, &intc, 1);
// moving average output mode active
int tmp = 0x50;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
tmp = 0x45;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
tmp = 0x57;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
tmp = 0x20;
datasend(AMG88_ADDR, AVE, &tmp, 1);
tmp = 0x00;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
int sensorTemp[2];
dataread(AMG88_ADDR, TTHL, sensorTemp, 2);
sg90.attach(SV_PINew ); // D7 myservo.attach(SV_PIN, 500, 2400); // サーボの割当(パルス幅500~2400msに指定)
sg90ns.attach(SV_PINns ); // D8 myservo.attach(SV_PIN, 500, 2400); // サーボの割当(パルス幅500~2400msに指定)
//**for Sleep
pinMode(A7, INPUT); //analoginputA7 = solarvolt-diodeVf
pinMode(WakeUpPin, INPUT_PULLUP); //external_wakeupD2pin(不使用NC) SunSet後sleep(sleep解除はFETSWon/off resetで行う Night:FETSWoff~夜明け:FETSWonRESET )
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //解除方法 RESET:Night WDT:Cloudy
//**Recover SA SAns from EEPROM
SAns = EEPROM.read(1); digitalWrite(13,HIGH); sg90ns.write(SAns);digitalWrite(13,LOW); //Recover N/S ServoAngle befoe reset status.
Serial.print("Dawn:WAKEUP FETSWon Return to EAST_TOP ,wait for SunRise!");Serial.print(SPWV/1024*5);Serial.println("V"); delay(5000);
for (SA=EEPROM.read(0); SA<= 140; SA++)//
{
sg90.write(SA);Serial.print("Rev West_END60° to East_TOP140° Now:");Serial.println(SA); delay(500); //夜明け FETSWonでWAKE_UPしEAST_TOP(凡そ-270度)Rotate
}
} // SET UP END
void loop()
{
SPWV = analogRead(A7); //SolarVoltage=-SPWV/1024*5v Dawn: fine morning:4.72V Cloudy: Twighlight: Night:0.0v room:0.4v
// Wire library cannnot contain more than 32 bytes in bufffer
// 2byte per one data
// 2 byte * 16 data * 4 times = 2byte*64point
int sensorData[32];
for (int i = 0; i < 4; i++)
{
// read each 32 bytes
dataread(AMG88_ADDR, T01L + i * 0x20, sensorData, 32);
for (int l = 0 ; l < 16 ; l++)
{
int16_t temporaryData = (sensorData[l * 2 + 1] * 256 ) + sensorData[l * 2];
// E-W Vertical_Line 温度ヒストグラム
//*** TMPDATSUM();*** 温度Datasum 3Frame合計で安定化 3面のDATAを更新
//Serial.print(temporaryData);Serial.print("TMPDAT3");Serial.println(TMPDAT3[i * 16 + l]);
TMPDAT3[i * 16 + l] = TMPDAT2[i * 16 + l]; //2面➦3面
TMPDAT2[i * 16 + l] = TMPDAT1[i * 16 + l]; //1面➦2面
TMPDAT1[i * 16 + l] = temporaryData ; // 新➦1面
TMPDATS[i * 16 + l] = TMPDAT1[i * 16 + l] + TMPDAT2[i * 16 + l] + TMPDAT3[i * 16 + l]; //3面SUM
Serial.print(" ");Serial.print(TMPDATS[i * 16 + l]); if (l == 7) Serial.println("") ;
} //for:I15 END
Serial.println("");
} //for:i3 END = 1frame X 3面 complete
//*** 温度histgram ∑VerticalLineSum (horizontal angle(0 ~ 7) 毎に縦8ブロック合計を計算)
TMPVS[0] = 0; TMPVS[1] = 0; TMPVS[2] = 0; TMPVS[3] = 0; TMPVS[4] = 0; TMPVS[5] = 0; TMPVS[6] = 0; TMPVS[7] = 0;
TMPHSns[0] = 0; TMPHSns[1] = 0; TMPHSns[2] = 0; TMPHSns[3] = 0; TMPHSns[4] = 0; TMPHSns[5] = 0; TMPHSns[6] = 0; TMPHSns[7] = 0;
for (int m = 0 ; m < 8 ; m++) //m= 0 ~ 7:水平方向毎に縦一列温度(足~頭)合計する
{
TMPVS[0] = TMPVS[0]+TMPDATS[0 + m * 8]; //LLLL:sensor左方向温度 :East
TMPHSns[0] = TMPHSns[0]+TMPDATS[0 + m ]; //NNNN
TMPVS[1] = TMPVS[1]+TMPDATS[1 + m * 8]; //LLL
TMPHSns[1] = TMPHSns[1]+TMPDATS[8 + m ]; //NNN
TMPVS[2] = TMPVS[2]+TMPDATS[2 + m * 8]; //LL
TMPHSns[2] = TMPHSns[2]+TMPDATS[16 + m ]; //NN
TMPVS[3] = TMPVS[3]+TMPDATS[3 + m * 8]; //L
TMPHSns[3] = TMPHSns[3]+TMPDATS[24 + m ]; //N
TMPVS[4] = TMPVS[4]+TMPDATS[4 + m * 8]; //:sensor正面方向温度:East~West solarのangleをServoでここがMAXになるように向けてゆく
TMPHSns[4] = TMPHSns[4]+TMPDATS[32 + m ]; //:sensor正面方向温度:North~South solarのangleをServoでここがMAXになるように向けてゆく
TMPVS[5] = TMPVS[5]+TMPDATS[5 + m * 8]; //R
TMPHSns[5] = TMPHSns[5]+TMPDATS[40 + m ]; //S
TMPVS[6] = TMPVS[6]+TMPDATS[6 + m * 8]; //RR
TMPHSns[6] = TMPHSns[6]+TMPDATS[48 + m ]; //SS
TMPVS[7] = TMPVS[7]+TMPDATS[7 + m * 8]; //RRR:sensor右方向温度 :West
TMPHSns[7] = TMPHSns[7]+TMPDATS[56 + m ]; //SSS:sensor下方向温度 :South
}
TMPVS[VSminL[0]] = TMPVS[VSminL[0]] - 20 ; //+ 20 ;//ヒストグラムでVSmaxH[0]の温度合計max水平方向のTMPVSに+50のヒステリシスを付ける:チャッタ―防止
TMPHSns[HSnsminL[0]] = TMPHSns[HSnsminL[0]] - 20 ; //ヒストグラムでHSmaxH[0]の温度合計max水平方向のTMPHSに+50のヒステリシスを付ける:チャッタ―防止
//**EAST 正面 WEST 太陽方向**
Serial.println(" 温度vs水平&垂直角度/div8° サーモヒストグラム");
Serial.println("WEST:0~ 正面:4 ~EAST:7");
Serial.print(TMPVS[0]);Serial.print(" ");Serial.print(TMPVS[1]);Serial.print(" ");Serial.print(TMPVS[2]); Serial.print(" ");Serial.print(TMPVS[3]);Serial.print(" ");
Serial.print(TMPVS[4]);Serial.print(" ");Serial.print(TMPVS[5]);Serial.print(" ");Serial.print(TMPVS[6]); Serial.print(" ");Serial.print(TMPVS[7]);Serial.println(":VerticalSum");
//**NORTH 正面 SOUTH 太陽方向**
Serial.println("SOUTH:0~ 正面:4 ~NORTH:7");
Serial.print(TMPHSns[0]);Serial.print(" ");Serial.print(TMPHSns[1]);Serial.print(" ");Serial.print(TMPHSns[2]); Serial.print(" ");Serial.print(TMPHSns[3]);Serial.print(" ");
Serial.print(TMPHSns[4]);Serial.print(" ");Serial.print(TMPHSns[5]);Serial.print(" ");Serial.print(TMPHSns[6]); Serial.print(" ");Serial.print(TMPHSns[7]);Serial.println(":HorizontalSum");
//********1frame Data complete*********
objectscan() ; //sensor水平範囲(0:WEST~7:EAST)でVSmin(=太陽)をさがす 2frame一致H[1]=H[2])(VSmin:maxと差がない時は太陽がいない)
objectscanns(); //sensor垂直範囲(0:SOUTH~7:NORTH)でHSmin(=太陽)をさがす 2frame一致H[1]=H[2])(HSmin:maxと差がない時は太陽がいない)
Serial.print("VSminL E:7~W:0 2Framecheck[0]");Serial.print(VSminL[0]);Serial.print("=[1]");Serial.print(VSminL[1]);Serial.print("&[2]");Serial.println(VSminL[2]);
Serial.print("HSminL N:7~S:0 2Framecheck[0]");Serial.print(HSnsminL[0]);Serial.print("=[1]");Serial.print(HSnsminL[1]);Serial.print("&[2]");Serial.println(HSnsminL[2]);
Serial.print("VSmax");Serial.print(TMPVSmax);Serial.print("-VSmin");Serial.print(VSmin);Serial.print("=差");Serial.print(maxmin);Serial.print("/HS差");Serial.print(nsmaxmin);
Serial.print("ServoAngle E140~W50:");Serial.print(SA);Serial.print("° N120~S60:");Serial.print(SAns);Serial.print("° Solar");Serial.print(SPWV/1024*5);Serial.println("V")
;
if ((VSminL[0] == 4) && (HSnsminL[0] == 4)) //太陽正面チェック 正面の時はSLEEP4minutes 4分後に1°rotationチェック
{
Serial.println("LockON:SLEEP4M");delay(100); digitalWrite(13,LOW);
for (int n=0; n<=29; n++) //***太陽正面向いたので240秒(n=29 wdt:8s)Sleepに入る。
{
wdt_enable_set(WDTO_8S);
deepSleep();
}
delay(100); Serial.println("LockON:WAKE UP");
if (SA > 50)
{
SA = SA - 1 ; //240sec/west1°rotation
digitalWrite(13,HIGH); sg90.write(SA) ; digitalWrite(13,LOW);
}
}
//********TMPVSmax が(sensor水平範囲=4:sensor正面)に来るようにservoを1°づつ回転
servo() ; delay(900); //***delay(100)でチャッタ―(scan発振)防止
//********TMPHSnsmax が(sennsaor垂直範囲=4:sensor正面)に来るようにservonsを1°づつ回転
servons() ; delay(900); //***delay(100)でチャッタ―(scan発振)防止
EEPROM.write(0, (SA & 0x00FF)); //eeprom:8bit
EEPROM.write(1, (SAns & 0x00FF)); //eeprom:8bit
} //loop END
//****************************************************************************************************
//*****************************************************************************************************
void datasend(int id, int reg, int *data, int datasize)
{
Wire.beginTransmission(id);
Wire.write(reg);
for (int i = 0; i < datasize; i++)
{
Wire.write(data[i]);
}
Wire.endTransmission();
}
void dataread(int id, int reg, int *data, int datasize)
{
Wire.beginTransmission(id);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(id, datasize, false);
for (int i = 0; i < datasize; i++)
{
data[i] = Wire.read();
}
Wire.endTransmission(true);
}
void objectscan() //Thermosensor縦一列合計のMax Minの値と水平方向(0~7)を特定/2frame一致 *太陽scanの時は”温度min位置”を探す?
{
TMPVSmax = 0; VSmin = 3000; //TMPVSmax = 0; VSminL[2]=0; VSmin = 3000; //TMPVSmax = 0; VSmaxH[2]=0; VSmin = 3000; //仮初期値設定
for ( int h = 0; h < 8; h++ )
{
if (TMPVSmax < TMPVS[h]) {TMPVSmax = TMPVS[h] ; } // VSmaxH[2] = h ;} //VSmax[2]:NewmaxData
if (VSmin > TMPVS[h]) {VSmin = TMPVS[h] ; VSminL[2] = h ; } //VSmin:NewminData VSminL[2] のhデーター*太陽の時はminをscan
}
maxmin = TMPVSmax - VSmin ;
if (VSminL[1] == VSminL[2]) VSminL[0] = VSminL[1] ; //maxH[1]; //2frame 一致 VSmax[0]に代入
else VSminL[1] = VSminL[2]; //2frame 一致せず Buffer(=VSmaxH[1])⇐NewData(VSmax[2]) VSmax[0]変更なし
}
//--------------------------------------------------------------------------------------------------
void objectscanns() //Thermosensor横一列合計のMax Minの値と垂直方向(0~7)を特定/2frame一致 maxH:0~7 *太陽scanの時は”温度min位置”を探す?
{
TMPHSnsmax = 0; HSnsmin = 3000; //TMPHSnsmax = 0; HSnsminL[2]=0; HSnsmin = 3000; //仮初期値設定
for ( int h = 0; h < 8; h++ )
{
if (TMPHSnsmax < TMPHSns[h]) {TMPHSnsmax = TMPHSns[h] ; } //HSnsmaxH[2] = h ;} //HSnsmax[2]:NewmaxData
if (HSnsmin > TMPHSns[h]) {HSnsmin = TMPHSns[h] ;HSnsminL[2] = h ;} //HSnsmin:NewminData *太陽の時はminをscan
}
nsmaxmin = TMPHSnsmax - HSnsmin ;
if (HSnsminL[1] == HSnsminL[2]) HSnsminL[0] = HSnsminL[1]; //2frame 一致 HSnsmax[0]に代入
else HSnsminL[1] = HSnsminL[2]; //2frame 一致せず Buffer(=HSnsmaxV[1])⇐NewData(HSnsmax[2]) HSnsmax[0]変更なし
}
//****************************************************************************************************
void servo() //Therosensor縦一列合計MaxのSensor水平方向が太陽の正面(VSmaxH[0]=4)になるようServo East~West angleを向けてゆく
{
//digitalWrite(13,HIGH);
if ((maxmin > 100 )||(nsmaxmin > 100)||(SPWV/1024*5 > 4.2)) // 太陽がある:max-min差>100 and solar電圧>4.2V 3.5V:もう発電には低い
{
if ((VSminL[0] < 4)&&(SA > 50)) //太陽はsensor右:WESTにあり正面(VSmaxH[0]=4 SA=太陽のangleまで)へServoで右に向けてゆくWEST_END:~50°W
{
SA = SA - 1;
digitalWrite(13,HIGH); sg90.write(SA); digitalWrite(13,LOW);
}
else if ((VSminL[0] >4)&&(SA < 140)) //太陽はsensor左:EASTにあり正面(VSmaxH[0]=4 SA=太陽のangleまで)へServoで左に向けてゆくEAST_END:~140°E
{
SA = SA + 1;
digitalWrite(13,HIGH); sg90.write(SA); digitalWrite(13,LOW);
}
else if ((SA <=50)||(SA >=140)) //正面、EAST/WEST_ENDでは4MSLEEPのみEND超えるrotationwはせず
{
Serial.println("WEST_end:SLEEP4M");digitalWrite(13,LOW);delay(100);
for (int n=0; n<=29; n++) //4M=240s_sleep
{
wdt_enable_set(WDTO_8S); //4minutes:n=29 WDTO_8S
deepSleep();
}
delay(100);Serial.println("Dark:WAKE UP ");
}
}
else //dawn cloudy rainy sunset では240sec_sleepに入り240秒(=deepsleep4minutes)経過するとWAKU UPしてWESTへ赤道儀1度回転
{
Serial.println("Dark:SLEEP4M");digitalWrite(13,LOW);delay(100);
for (int n=0; n<=29; n++) //4minutes_sleep/west1°rotation
{
wdt_enable_set(WDTO_8S); //4minutes set:n=29 WDTO_8S
deepSleep();
}
delay(100);Serial.println("Dark:WAKE UP West 1degree rotation");
if (SA > 50)
{
SA = SA - 1; //夜明け 曇り 雨 夕方 太陽が見えない時240秒Sleepして赤道儀WEST1度回転
digitalWrite(13,HIGH); sg90.write(SA); digitalWrite(13,LOW);
}
else
{ //solarがSunSet向きWEST_END50°まで向くと 外部復帰SLEEPに入りWDTでの復帰はせずFEToffまでsleepのまま。//夜明けSunRise向き140°eastまで270°進む(=140-50=90°戻る)
Serial.print("longSLEEP sunset:外部復帰sleep➡FEToff ➡➡Night➡➡ Dawn/Sunrise:FETon SPWV=");Serial.print(SPWV/1024*5);Serial.println("V");
delay(100); interrupt(); delay(100); //SunRise向に戻るとDawnまでsleep:twighlight➡FETSWoff:nightに入る(WDT Disable=外部trigger復帰でFETSWoffし,SunRise前にONでreset_Wakeup)
//longsleep復帰はWDTでなく外部TriggerだがFEToff/onによる電源RESET :wakeup:24mA 4Msleep:10mA longsleep:10mA /FEToff:0mA }
}
}
} //servo END
ISR(WDT_vect) { // *** Intrpt svc rtn for WDT ISR(vect) *****
} // do nothing here
// ***** Sleep + Stopp ADC power *** deepSleep() *****
void deepSleep(void) {
ADCSRA &= B01111111; // disable ADC to save power
sleep_enable();
sleep_cpu(); // sleep until WDT-interrup
sleep_disable();
ADCSRA |= B10000000; // enable ADC again
}
//引数にはWDTO_500MS WDTO_1S WDTO_2S WDTO_4Sなどと設定
void wdt_enable_set(byte b){
b = ((0b00001000 & b) << 2) | (0b00000111 & b); //ウォッチドッグ・タイマー分周比設定ビットの4ビット目がWDTCSRレジスタで2ビットずれているための処理
b |= 0b00010000; //WDCE ウォッチドッグ変更許可ビットを立てる
MCUSR &= 0b11110111; //WDRF ウォッチドッグ・システム・リセット・フラグにゼロを書き込んでリセットの準備をする
WDTCSR |= 0b00011000; //WDE ウォッチドッグ・システム・リセット許可のビットを立ててリセット WDCE ウォッチドッグ変更許可により4サイクル以内は設定を変更可能
WDTCSR = b; //事前に作成しておいた設定を流し込む
WDTCSR |= 0b01000000; //WDIE ウォッチドッグ・割込み許可ビットを立てる
}
byte b;
void interrupt(){ //sleep解除はWDTでなく外部Trigger:D2pinLOW/実際はFETSW off/onによるresetで解除
b |= 0b00010000; //WDCE ウォッチドッグ変更許可ビットを立てる
MCUSR &= 0b11110111; //WDRF ウォッチドッグ・システム・リセット・フラグにゼロを書き込んでリセットの準備をする
WDTCSR |= 0b00011000; //WDE ウォッチドッグ・システム・リセット許可のビットを立ててリセット WDCE ウォッチドッグ変更許可により4サイクル以内は設定を変更可能
WDTCSR = b; //事前に作成しておいた設定を流し込む
MCUSR &= 0b10111111; //WDRF ウォッチドッグ・Enableフラグにゼロを書き込んでウォッチドッグによるwakeup 禁止する
ADCSRA &= B01111111; // disable ADC to save power
attachInterrupt(0,WakeUp, LOW); //[0]=D2pin LOW でWAKEUP PULLUPしているので外部trigger解除はせずFETSW CUTOFF ONで解除
sleep_mode();
detachInterrupt(0);
ADCSRA |= B10000000; // enable ADC again
}
void WakeUp(){
}
// -----------------------------------------------------------------------------------------------------------------------------------------------------------
void servons() //Therosensor横一列合計MaxのSensor垂直方向が太陽の正面(VSmaxH[0]=4)になるようServo North~South angleを向けてゆく
{
if ((maxmin > 100)||(nsmaxmin > 100)||(SPWV/1024*5 > 4.2)) // 太陽が出ている solar>4.2V 3.5V nsmaxmin差>50 TMPHS>2700 (実測 朝:1800 昼:2700 日差し窓/3m:2000 2300 )
{ if ((SAns > 60) && (HSnsminL[0] < 4 )&&(SA > 70)&&(SA < 110)) //60度以下limit :(solar正面-23.4度=90-23.5=66.5)凡そ60 70°<東西SA<110°の南中(SA90)前後の時調整
{
SAns = SAns -1 ; //太陽はsensor上(北)to太陽の正面(HSmaxV[0]=4 SAns=太陽のangleまで)へServonsで下(南)に向けてゆく
digitalWrite(13,HIGH); sg90ns.write(SAns);
}
else if ((SAns < 120) && (HSnsminL[0] > 4 )&&(SA > 70)&&(SA < 110)) //120度以上limit:(solar正面+23.45度=90+23.5=113.5)凡そ120 70°<東西SA<110°の南中(SA90)前後の時調整
{
SAns = SAns + 1 ; // 太陽はsensor下(南)to太陽の正面(HSmaxV[0]=4 SAns=太陽のangleまで)へServonsで上(北)に向けてゆく
digitalWrite(13,HIGH); sg90ns.write(SAns);
}
else SAns = 120; //North_END:120°
}
digitalWrite(13,LOW);
}
//**************************************************************************************************************
//END
感想
太陽を街の中で追尾することは難しい事がわかった。理由はAMG8833を規格外で使用している事は当然ながら、太陽は建物に隠れ直接見えている時間は意外と短く、また薄い雲でもあると空の温度が不均一になり太陽の特定が困難になりになることがよく起きた。電源系統は時間をかけて確認できていないが、外部に電気供給までは?でも自活は出来ていそう。とりあえず一区切り。
朝カーテンを開けると熟睡していた太陽追尾君が起きだして必死にエサの太陽を探し自活して生きてゆく様は、生き物のようで動く電子工作の楽しさを味わうことが出来ました。今回得た要素技術でまた何か動く電子工作ができたらと思っています。ヽ(^o^)丿
参考にさせて頂いた記事
太陽高度の季節変化
赤道儀作ろう
AMG88の使い方
FETの使い方
Arduino スリープとウオッチドックタイマー
Arduinoのスリープモードについて(外部トリガーによる復帰)
Arduino Unoで内蔵メモリEEPROMを使って状態を保存する方法
ArduinoでマイクロサーボSG90を動かしてみる
投稿者の人気記事
-
syouwa-taro
さんが
2024/05/29
に
編集
をしました。
(メッセージ: 初版)
-
syouwa-taro
さんが
2024/05/30
に
編集
をしました。
(メッセージ: 動作説明補足)
ログインしてコメントを投稿する