目次
章 | タイトル | 内容 |
---|---|---|
1 | はじめに | 今回やることの説明 |
2 | if文の使い方 | if文を使った分岐について説明 |
3 | 関係演算子 | 条件式を書くための関係演算子について説明 |
4 | switch文の使い方 | switch文を使った分岐について説明 |
5 | for文の使い方 | for文を使ったループについて説明 |
6 | while文の使い方 | while文を使ったループについて説明 |
7 | 待機について | 待機処理の仕方について説明 |
8 | まとめ | 今回のまとめ |
1. はじめに
前回はC言語のキホン➀として、演算子・変数・配列・関数について簡単に記しました。
今回も同じくC言語のキホン➁として、「分岐」や「ループ」といった制御構文の使い方について説明していきたいと思います。
前回同様、EV3rtで開発する上での最低限の部分のみ記しますので、詳しい文法等はC言語の書籍やサイトを参考にしてください。
参考書籍
参考サイト
2. if文の使い方
今回はまず、「if文」の使い方から説明していきます。
EV3ソフトウェアで言うところの「スイッチ」ですね。
if文は 「条件分岐」 と呼ばれる制御構文の一つです。
ある「条件」に対してその条件を 「満たしている」か「満たしていない」 かでプログラムを分岐するということです。
例えば以下の例、ポート1に接続されたタッチセンサが「押されている」か「押されていない」かで、変数に代入する値を変えています。
これを、C言語で表現してみましょう。
if(ev3_touch_sensor_is_pressed(EV3_PORT_1)){
a = 1;
}
else{
a = 0;
}
1行目のif
の後にカッコ(
)
がありますが、この中に 「条件式」 を書きます。
今回は『ポート1に接続されたタッチセンサが「押されている」か「押されていない」か』が条件式ですので、これをプログラムで記述します。
今後のセンサの回で紹介しますが、ev3_touch_sensor_is_pressed()
という関数でタッチセンサーが押されているか否かを返してくれます。
押されている場合は戻り値として True
が、押されていない場合は False
が返ってきます。
このTrue
(真)とFalse
(偽)が条件分岐において非常に重要なわけですが、if文ではこの条件式がTrue
(真)であった場合、if
の直後の中カッコ{
}
の中身を実行します。
一方、False
(偽)であった場合、if
の直後は実行しません。
上記の例ではif
の後にelse
とそれに付随する中カッコ{
}
があります。
この場合、条件式がFalse
(偽)であった場合はelse
の直後の中カッコ{
}
の中身を実行します。
尚、elseの部分は必要なければ省略することも出来ます。
例えば以下のようなプログラムを表現するとき。
a = 0;
if(ev3_touch_sensor_is_pressed(EV3_PORT_1)){
b = 1;
}
a = 1;
else文を使わずとも、これだけで良いわけです。
シンプルで読みやすいプログラムを書くためにも、必要なコードだけ書くように心がけましょう。
else ifを使う場合
では、以下のようなプログラムを作りたい時はどうすれば良いでしょうか。
例えば、こんな👇プログラムが書けるかと思います。
if(ev3_color_sensor_get_color(EV3_PORT_3)==2){ //青か?
a = 1;
}
else{
if(ev3_color_sensor_get_color(EV3_PORT_3)==3){ //緑か?
a = 2;
}
else{
if(ev3_color_sensor_get_color(EV3_PORT_3)==5){ //赤か?
a = 3;
}
}
}
確かにこれでも動作はしますが、elseの中へ中へと入ってしまい、コードが見にくくなってしまいます。
そこで、else if
文を使いましょう。
if(ev3_color_sensor_get_color(EV3_PORT_3)==2){ //青か?
a = 1;
}
else if(ev3_color_sensor_get_color(EV3_PORT_3)==3){ //緑か?
a = 2;
}
else if(ev3_color_sensor_get_color(EV3_PORT_3)==5){ //赤か?
a = 3;
}
else if
文は、直前のif
文の条件式がFalse
(偽)だった時に実行されます。
上記の例で言えば、一行目の『カラーセンサの値が青か』の判定がFalse
だった時に、二行目は実行せず、四行目の『カラーセンサの値が緑か』の判定に移るということになります。
これを用いればコードをシンプルに書くことが出来るので、積極的に利用しましょう。
(もちろん、else
文同様に省略することもできます。)
3. 関係演算子
さて、先ほどのelse if
の説明用のコードで、サラッとこんな👇コードを書いてしまいました。
if(ev3_color_sensor_get_color(EV3_PORT_3)==2){ //青か?
a = 1;
}
これの条件式の中にあるイコール=
が二つ連なった文字==
ですが、これは==
の両隣の値が 「等しいかどうか」 を調べるものです。
こういった文字のことを、「関係演算子」(かんけいえんざんし)といいます。
上記のコードの例の場合、関数ev3_color_sensor_get_color()
により、カラーセンサの値が戻り値として返ってきます。
その値と、右辺側の値2
が等しいかを調べて、等しければTrue
(真)を、等しくなければFalse
(偽)を返すということになります。
このような関係演算子はいくつか種類がありますので、EV3ソフトのブロックと比べながら紹介していきます。
演算子 | 記述例 | 意味 | EV3ソフトの値 |
---|---|---|---|
== | a == b | bがaに等しい | 0 |
!= | a != b | bがaに等しくない | 1 |
> | a > b | bよりaが大きい | 2 |
>= | a >= b | bよりaが大きいか等しい | 3 |
< | a < b | bよりaが小さい | 4 |
<= | a <= b | bよりaが小さいか等しい | 5 |
C言語入門 | Let'sプログラミング / 関係演算子 / 関係演算子の種類 より引用・追記
例えば以下のようなEV3ソフトでのプログラムをC言語で表現してみます。
if(ev3_color_sensor_get_reflect(EV3_PORT_3)>30){
a = 1;
}
else{
a = 2;
}
他の演算子についても、上記の例のようにして使うことができるので、是非試してみてください。
4. switch文の使い方
if文の章で、else if
文を使えば複数の条件分岐が書ける事を紹介しましたが、その条件分岐がいくつもあるとき、いちいちelse if
で条件式を書くのも面倒です。
そのような時は、これから紹介するswitch
文を使うことでプログラムを簡潔に書くことが出来ます。
例えば、以下のようなEV3ソフトのブロックを使いたいとします。
EV3ソフトにおいても縦に長くなりすぎてしまい、プログラムが億劫になるほどです。
これをif
文およびelse if
文で表現すると、以下のようになります。
if(ev3_color_sensor_get_color(EV3_PORT_3) == 0){
// カラー値 0 (判定無し) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 1){
// カラー値 1 (黒) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 2){
// カラー値 2 (青) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 3){
// カラー値 3 (緑) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 4){
// カラー値 4 (黄) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 5){
// カラー値 5 (赤) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 6){
// カラー値 6 (白) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 7){
// カラー値 7 (茶) の時の処理
}
EV3ソフトでの表現よりは幾分かマシかもしれません。
しかし、条件式のうち変わっているのは右辺側の値だけで、左辺側の長い関数の部分は一切変わっていないわけです。
これを8つも書くのはやはり無駄ですよね。
そこで登場するのが、switch
文です。
今回のように、条件式の左側が変わらず、右側の値だけが変わっている時に使うことが出来ます。
上記のコードをswitch
文を使って書き直してみます。
switch(ev3_color_sensor_get_color(EV3_PORT_3)){
case 0:
// カラー値 0 (判定無し) の時の処理
break;
case 1:
// カラー値 1 (黒) の時の処理
break;
case 2:
// カラー値 2 (青) の時の処理
break;
case 3:
// カラー値 3 (緑) の時の処理
break;
case 4:
// カラー値 4 (黄) の時の処理
break;
case 5:
// カラー値 5 (赤) の時の処理
break;
case 6:
// カラー値 6 (白) の時の処理
break;
case 7:
// カラー値 7 (茶) の時の処理
break;
default:
// どれにも当てはまらなかったときの処理
break;
}
文法としては、switch
の後の(
)
の中に「判定したい値」を書き、値ごとの処理をcase 【値】:
として分岐して書きます。
「判定したい値」が「caseの後の値」と等しいかどうかを、上から順番に判定してきます。
判定した結果True
(真)だった場合、そのcase
の直後のプログラムを実行します。
処理の一番最後にはbreak;
というコードがあります。
このコードを書くことで、switch
文全体から抜け出すことが出来ます。
ちなみにbreak;
を書かないと、その下にあるcase
に対しても条件を満たすかどうか判定してしまいますので、気を付けましょう。
又、一番下にdefault:
がありますが、これはどの条件にも当てはまらなかった時に実行されるコードです。
if
文におけるelse
の処理と同じような立ち位置ですね。
default:
に関しては、書かなくてもコンパイルは通るはずですが、思わぬエラーを引き起こす可能性があるので、書くように心がけましょう。
(例えばエラーの処理を行うとか。)
5. for文の使い方
ここからは、ループ処理のやり方について説明していきます。
まずはループ構文の代表格であるfor
文の使い方についてです。
例えば、以下のようなEV3ソフトのプログラムがあるとします。
意味としては、モータを前後に動かす動作を10回繰り返す、というものですね。
これをC言語のfor
文を用いると、以下のように書くことが出来ます。
int i; // カウンタ変数
for(i=0; i<10; i++){
ev3_motor_rotate(EV3_PORT_D, 360, 50, true);
ev3_motor_rotate(EV3_PORT_D, -360, 50, true);
}
for
文の(
)
の中については、以下の画像のように、左から順に 「初期化式」「条件式」「変化式」 となっています。
まず、for
文を使うには「カウンタ変数」という変数が一つ必要です。
カウントする変数、つまり「今何回目か?」を格納する変数と考えるとわかりやすいでしょう。
上記のコードでは、一行目に「カウンタ変数」としても用いる変数i
を定義しています。
次に、for
文の中に入ると一度だけ「初期化式」が実行されます。
ここで、カウンタ変数を一度初期化するわけです。
その次に、「カウンタ変数が条件式を満たしているか」の判定が入ります。
True
(真)だった場合は、for
文の中カッコ{
}
の中身のコードが実行されます。
中カッコの中のコードが全て実行されたら、最後に「変化式」が実行されます。
ここで、前回紹介した「インクリメント演算子」が用いられています。
意味としては「変数に1
加算する」でしたね。
これで、ループ回数を数えていくわけです。
「変化式」が実行された後は、再び「条件式」による判定が行われます。
これがTrue
(真)である限り、ループが実行されます。
では、上記のコードでのカウンタ変数i
が11
になった時ですが、この時「条件式」による判定結果はFalse
(偽)になります。
すると、プログラムはfor
文を抜けて、ループが終了します。
以上がfor
文の基本的な使い方です。
6. while文の使い方
もう一つ、代表的なループ構文であるwhile
文を紹介します。
先ほどのfor
文は、「回数を指定する」タイプのループでしたが、while
文は「条件を満たしている限り続ける」タイプのループです。
例えば、以下のようなEV3ソフトのプログラムがあるとします。
意味としては「モータを前後に動かす動作を、カラーセンサの反射光の値が50未満である限り繰り返す」というものですね。
これをC言語のwhile
文を用いると、以下のように書くことが出来ます。
while(ev3_color_sensor_get_reflect(EV3_PORT_3) < 50){
ev3_motor_rotate(EV3_PORT_D, 360, 50, true);
ev3_motor_rotate(EV3_PORT_D, -360, 50, true);
}
while
文の文法としては、while
の直後のカッコ(
)
に条件式を書き、その条件式を満たしている限り、中カッコ{
}
内のコードを実行するという形です。
for
文とwhile
文、状況に合う方のループを選んで使うようにしましょう。
7. 待機について
今回は最後に 「待機」 の仕方を説明したいと思います。
EV3ソフトで待機をするには以下のブロックを使用していました。
EV3rtでは、以下のコードにより待機(正確にはタスクのスリープ)を行います。
tslp_tsk(1*1000*1000);
tslp_tsk()
という関数が、EV3rtの核であるTOPPERS/HRP3のタスクスリープ関数となります。
引数にはスリープする時間(=待機する時間)を マイクロ秒 単位で指定します。
(※EV3rt β7.3 まではHRP2を使用しているので「ミリ秒」での指定となります。)
「マイクロ秒」というのは、 $10^{-6} = \frac{1}{10^6}$ 秒のことで、0を6個付けると1秒になります。
ちなみに $10^{-3} = \frac{1}{10^3}$ 秒が「ミリ秒」であり、$1/1000$ されるごとに単位の名前が変わります。
従って、上記のコードのように、$1000$ ずつ掛け算をして表現すると分かりやすいかもしれません。
では実践例を見てみましょう。
例えば、以下のEV3ソフトのブロックのように、モータを0.5秒回転させるプログラムがあるとします。
これを先ほどのスリープ関数を用いて表すと、以下のようになります。
ev3_motor_set_power(EV3_PORT_D, 50);
tslp_tsk(500*1000);
ev3_motor_stop(EV3_PORT_D, True);
これは、モータを動かす関数に「何秒動かす」という命令がないため、始めにパワーをセットする命令を置いています。
その後、0.5秒スリープさせる処理を行っています。
(EV3ソフトに逆翻訳すれば以下👇のような形になります。)
以上が、待機処理の行い方でした。
ロボットの制御で待機処理は非常に多く使いますので、これは確実に使えるようにしておきましょう。
8. まとめ
今回は分岐やループ、待機といった制御構文を紹介してきました。
プログラミングの本質は「アルゴリズム」の構築であり、それに制御構文は欠かせません。
シンプルで読みやすく、そしてバグのないプログラムを組むためにも、それぞれの制御構文をしっかり使いこなせるようになりましょう。
次回はいよいよモータを動かす関数(API)を紹介していきます。
前回: #4 C言語のキホン➀
次回: #6 モータを動かそう