どうもメガネです、
今回は自分用に、わかっていても度々引っかかってしまうArduinoのコーディング時の注意についてまとめておきます。
起こった問題
初期化を最初だけ行いたいのに毎回行われてしまう、というのが今回取り上げた問題です。
以下にサーボモータのサンプルを示します。
#include <Servo.h>
Servo servo1;//ロック制御用サーボモータ
Servo servo2;//昇降用サーボモータ
#define SERVO1 10
#define SERVO2 11
void setup() {
servo1.attach(SERVO1);
servo2.attach(SERVO2);
}
int reset(int x){
int i;
if(x==0){
for(i=0;i<180;i++){
servo1.write(i);
delay(10);
}
}
x=1;
return x;
}
void loop() {
int x=0;
x=reset(x);
servo1.write(30);
delay(100);
servo1.write(150);
delay(100);
servo2.write(30);
delay(100);
servo2.write(150);
delay(100);
}
サンプルプログラムの内容としては、最初にサーボモータを0~180度まで動かす初期化を行った後に、30度と150度を繰り替えし動かす、というものです。
なお初期化は初期化なので最初の電源投入時だけ行いたい、というものです。
間違っている部分は以下の部分です。
void loop() {
int x=0;
x=reset(x);
なにが間違ってるかっていうと、「static」を付けてないところですね。
まぁ、Arduinoのプログラム書き込み部分が「loop」などという紛らわしい名前を付けていることによる問題が多いかと思いますが、、、
プログラムを上から追っていくと、
loop()ないで最初にx=0としてxが初期化されて、それを引数に関数reset(int x)が動くという感じですね。
そして最初の1回だけ実行したいので、「x=1」をいれて帰ってくるわけです。
なのでx=reset(x)=1
として次回以降はreset(x)ないのif(x==0)の判定でNOTとなり初期化は最初しか実行されない。
というわけです。
ですが残念ながら、このままでは初期化は毎回行われます。
なぜ毎回初期化reset(x)が行われるのか?
理由は簡単です。
Arduinoのloop()は「ループという名前がついたただの関数」なのであって、
ループする関数ではないからです。
プログラムにして(意味を疑似的に)表示させてみると以下のような感じで伝わるでしょうか?
Arduinoに書き込むプログラムを丸ごと自作してみた、、、みたいな、、、
main(){
setup();
while(1){
calc();
loop();
add();
}
}
calc(){
int x=0;
(etc.....)
}
loop(){
int x=0;
x=reset(x);
(etc.....)
}
add(){
int y=0;
(etc.....)
}
意味が分かりますかね。
つまり、loop()は単に名前のついた関数なのであって、センサなりモータなり状態を把握する関数を掻き込む場所としてloopという関数を使っているのであって、
単にloopのなかでxにreset(x)を代入したところで次にloop()が呼び出されれば
「intx=0」から始まるのでまた最初からやり直しというわけです。
解決法
えぇ、、そんなんどうしようもないし複数前のクロックのセンサの値使いたいとき使えへんやん、、、
となりますが、もちろんそんなわけはないです。
先ほどからぼちぼち言ってますが、これを解決するにはloop内で宣言したxの宣言を
「int x=0;」→「static int x=0;」
と、staticを付けて修正してあげればいいだけです。
こうすることでxは、x=0の初期化以降、x=○○、といった代入のような操作をしない限り、何度loop()が呼び出されても値が0で初期化されることはありません。
静的な記憶域機関、とか言うらしいですが、、、
修正したプログラム
一文追加しただけですが、確認用として残しておきます。
いろいろなパターンがあるかと思うので、間違いと正解の文を交互に試してみると意味が分かりやすいかもですね。
#include <Servo.h>
Servo servo1;//ロック制御用サーボモータ
Servo servo2;//昇降用サーボモータ
#define SERVO1 10
#define SERVO2 11
void setup() {
servo1.attach(SERVO1);
servo2.attach(SERVO2);
}
int reset(int x){
int i;
if(x==0){
for(i=0;i<180;i++){
servo1.write(i);
delay(10);
}
}
x=1;
return x;
}
void loop() {
static int x=0;
x=reset(x);
servo1.write(30);
delay(100);
servo1.write(150);
delay(100);
servo2.write(30);
delay(100);
servo2.write(150);
delay(100);
}
間違いの例(太字部分)
int reset(int x){
int i;
if(x==0){
for(i=0;i<180;i++){
servo1.write(i);
delay(10);
}
}
x=1;
return x;
}
void loop() {
int x=0;
reset(x);
x=1; //1を直接代入してもstaticじゃないので結局だめです。
それでは。