ラズPicoでサーボモーター(SG90)を動かそう〜その3〜 プログラムを、さらにかっこよくしよう
2024年2月2日(金)は、7割ほどの出席率でした。今回は、ひきつづきサーボモーター(SG90)を動かすプログラムを、さらにかっこよくします。
- 18時00分~18時25分 タイピング練習
- 18時25分~19時50分 サーボモーターのプログラミング
- 19時50分~20時00分 あとかたづけ
Contents
タイピング練習
今回のタイピングの練習は、英語入力です。使う教材は、下のサイトのWebアプリです。
https://manabi.benesse.ne.jp/gakushu/typing/
プログラムコードは、ほとんど英語です。したがって、日本語入力だけでなく、英語入力を練習しておくとコーディングがスムーズにできます。日本語入力と違う点は、「日本語で使わないキーを入力すること」「単語の区切りは、かならずスペースであること」です。
これも、正しい練習をすることで、確実にタイピングスキルが身についていきます。
サーボモーター(SG90)のプログラムをかっこよくする
前回、サーボモーター(SG90)を動かして、さらに繰り返しを少しだけはぶくプログラムを書いてみました。
今回は、さらにコードをかっこよくします。
繰り返しはforでまとめる
プログラムを学習するときに、おそらくごく初期にまなぶのが、繰り返しを制御する文法です。具体的には、while文、for文を学習します。
前回のservo2.pyで、最後の方に「rotmotor」の繰り返しがあるのが、かっこ悪いと説明しました。ここが学習の成果のみせどころです。繰り返しをfor文でまとめます。下のコードのハイライト箇所が変更箇所です。
from machine import Pin, PWM
import time
SERVO_PIN = 16
PWM_FREQ = 50
def pulse_width(val, freq = PWM_FREQ, resol = 65535):
pulse = freq * val * 1e-6 * resol
return int(pulse)
def rotmotor(pulse):
duty = pulse_width(pulse)
servo.duty_u16(duty)
time.sleep(1)
servo = PWM(Pin(SERVO_PIN))
servo.freq(PWM_FREQ)
motion = [1500, 500, 1500, 2500]
while True:
for i in range(4):
rotmotor(motion[i])
「rotmotor」に直接数値をわたしてプログラムを書いていたのを、数値をリストにまとめて(19行)、for文でひとつずつ読み出す(22〜23行)ようにしました。
この改修により、同じような記述を繰り返すことがなくなりました。それに、サーボモーターの動きを細かく制御したくなったら、19行の「motion」のリストに数値を入力し、22行の「range」のカッコ内の数字を変更するだけです。コピペを繰り返す必要がなくなりました。
コピペを繰り返すようなコードを書くと、なぜ悪いのでしょうか。かっこ悪いだけではありません。実は、コード全体の見通しが悪くなり、ミスしやすくなります。さらに、変更も難しくなります。コードは短く、簡潔に書きましょう。
サーボモーターの動きを角度で指定する
ここまでプログラムを書いてきて、「なぜサーボモーターの角度を1500とか500とか、バカでかい数値で指示するのだろう?」と思ったのではないでしょうか。実際にサーボモーターが動く角度は、「-90〜0〜90度」の180度です。ならば、「-90〜0〜90」の数値でプログラムできたほうが、わかりやすいと思いませんか?
そのご期待にそって書き換えたプログラムが、下記のservo4.pyです。
from machine import Pin, PWM
import time
SERVO_PIN = 16
PWM_FREQ = 50
def pulse_width(val, freq = PWM_FREQ, resol = 65535):
pulse = freq * val * 1e-6 * resol
return int(pulse)
def rotmotor(pulse):
duty = pulse_width(pulse)
servo.duty_u16(duty)
time.sleep(1)
def cnvPulse(degrees):
if degrees < -90:
degrees = -90
if degrees > 90:
degrees = 90
return -degrees*1000/90+1500
servo = PWM(Pin(SERVO_PIN))
servo.freq(PWM_FREQ)
degrees = [0, 90, 0, -90]
while True:
for deg in degrees:
pulse = cnvPulse(deg)
rotmotor(pulse)
まず、関数cnvPulseを作りました(16〜22行)。これが、角度をパルス幅に変換する関数です。サーボモーターは角度ではなく、パルス幅を指定しないと動きません。そこで、直感的にわかる角度をパルス幅に変換する関数を作りました。
なお、変換するだけなら「return -degrees*1000/90+1500」(21行)だけでもOKです。下の17〜20行は、サーボモーター(SG90)が「-90〜90度」の範囲でしか動かないので、範囲を超えた数値をはじく処理です。
if degrees < -90:
degrees = -90
if degrees > 90:
degrees = 90
SG90には「-90〜90度」しか指定できないと知っていても、人間は必ず間違えます。そこで、あらかじめ予測できるミスを防ぐ工夫が大切です。コーディングミスをしても、「動かない!」を防ぐことができます。
さて、もう一つの工夫は「for deg in degrees:」(29行)です。サーボモーターを制御する回数が増えたとき(degreesの要素が増えたとき)、servo3.pyだと数字を毎度書き換える必要がありました。しかし、servo4.pyの書き方だと、そもそも要素数を示す数値が書かれていません。「リストdegreesの中の要素を一つずつすべて読み込む」という記述なので、要素数を示す必要がないのです。
したがって、degreesリストを下のように細かく設定しても、変更箇所はこの行だけすむのです。
degrees = [0, 90, 0, -90, 30,-50, 3, -90, 46, 49, 0, -32]
変更する箇所が減るということは、「ミスをする可能性自体が減る」ということです。プログラムを組む場合は、常にあとから変更することを考えながら組むと、良いプログラムが書けるようになります。
今回でサーボモーター(SG90)のプログラムは一区切りです。次回からは、超音波距離センサーを使ったプログラムに挑戦します。