使用するのは「OSOYOO マイクロサーボモーターSG90」という格安のサーボモーターです。
電子工作のキットに含まれていて、とても小さな実験用のモーターです。それでも多少のことなら実用的に使えそうです。
意外と力もあるので、そんなに重たくない物なら動かせます。

ネットにはこの制御についてたくさん記事があります。
その中から、目的もドンピシャで、一番簡単なコードで紹介されていた記事がQiitaにありました。
今回はそのまま使わせていただきます。
https://qiita.com/elyoshio92/items/b2e7a7728875ebebe542
このサーボモーターSG90の制御に関してこちらの記事通りで間違いありません。だから、コピペするだけでOKです。ここではちょっと補足だけしています。詳しくは元のサイトで読んでください。
GPIOとの接続
このSG90は3本の線が出ています。
サイトによってはGPIOの番号が色々と出てきます。いくつか試したのですけど、やはりこの参考にしたサイトの通り、電源とGND以外のデータ通信については、GPIO14でOKです。
- 赤色が電源(5V)へ
- 茶色がGNDへ
- オレンジが通信のGPIO14へ

Pythonプログラムコード
Pythonプログラムを用意します。
適当な場所(ユーザーフォルダなど)で新規に.pyファイルを作ります。
sudo nano sg90.py
基本は元のサイトで紹介されているコードをコピペでOKです。
import RPi.GPIO as GPIO
import time
INTERVAL = 0.6
PIN = 14
FREQ = 50
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT)
servo = GPIO.PWM(PIN, FREQ)
#init
servo.start(0.0)
for i in range(2):
servo.ChangeDutyCycle(2.5)
time.sleep(INTERVAL)
servo.ChangeDutyCycle(12.0)
time.sleep(INTERVAL)
GPIO.cleanup()
これ、思ったのはLチカ同様に非常に簡単なうえ、短いコードなので初心者に最適ですね!感謝!
角度を理解する
電源入れた時にGPIOに接続していたら、勝手に動いてちょっとズレてしまいました。手で無理矢理戻しても良いのですけど、せっかくなのでプログラム部分をイジって試してみましょう。

後半部分のfor文前に角度で遊んでみます。
for文をコメントアウトして、その前に1回だけ動作するようにします。
〜後半部分
#init
servo.start(0.0)
servo.ChangeDutyCycle(2.5)
time.sleep(INTERVAL)
#for i in range(2):
# servo.ChangeDutyCycle(2.5)
# time.sleep(INTERVAL)
# servo.ChangeDutyCycle(10.0)
# time.sleep(INTERVAL)
GPIO.cleanup()
servo.ChangeDutyCycle(2.5)とある2.5の部分が動く角度となります。正しくは電流量です。
ちょっと理解しにくいなと思ったのですけど、簡単なんです。
左水平位置が12.0、垂直方向から右水平に向かって数値が小さくなり、右水平位置が2.5です。垂直方向が7.5となります。
範囲は2.5〜12.0で指定すれば、あまり難しく考えなくても動作します。

角度ではないですが、決まった電流量で決まるので、正しくはありませんが座標みたいに考えれば簡単です。
左水平位置にしたいので、12.0を指定してあげれば良いだけです。
〜後半部分
#init
servo.start(0.0)
servo.ChangeDutyCycle(12.0)
time.sleep(INTERVAL)
#for i in range(2):
# servo.ChangeDutyCycle(2.5)
# time.sleep(INTERVAL)
# servo.ChangeDutyCycle(10.0)
# time.sleep(INTERVAL)
GPIO.cleanup()
書き換えたら保存して実行します。
python sg90.py

このように長い方が左側で水平になりました。
お手本コードの動き
最初のお手本コードを見てみると、for文で2回動かしています。最初に2.5の位置へ動かして、その後に10.0の位置へ動かし、それを2回繰り返しています。
ただ、2回目の10.0の位置だと結果的に扇形の動きをします。
ここは水平に180度を動かしたいので、10.0ではなく12.0に変更してみました。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
INTERVAL = 0.6
PIN = 14
FREQ = 50
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT)
servo = GPIO.PWM(PIN, FREQ)
GPIO.setwarnings(False)
#init
servo.start(0.0)
for i in range(2):
servo.ChangeDutyCycle(2.5)
time.sleep(INTERVAL)
servo.ChangeDutyCycle(12.0)
time.sleep(INTERVAL)
GPIO.cleanup()
しかし、完全な水平の動きにはなっていませんね??
概ねこれで良かったのでヨシとしておきます。
エラーが出たので以下を追加しました。
GPIO.setwarnings(False)
sg90.py:11: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings. GPIO.setup(PIN, GPIO.OUT)
とりあえずエラー出さないようにしただけです。なんでchannelが被っているのか??
これで一応は問題無く動きます。
時間で制御
自動的に実行させたい場合、cronを使います。
crontab -e
最初に使うエディタを選びます。

cornへの書式は以下です。
分 時 日 月 曜日 コマンド
例えば、毎朝の8時に実行したい場合
0 8 * * * python /home/pi/sg90.py
詳しくはmanファイルを読んでみてください。
man 5 crontab
スクリプトに実行権限がない場合は付与してください。
sudo chmod 755 /home/pi/sg90.py
権限の付与状態を確認するコマンド
ls -l /home/pi/sg90.py
最後に
スゴイ簡単です。
当初の予定通り、サーボモーターの白いプラスティック部分を金魚のエサに取り付けて真上から真下へ動かすことでエサを放出させます。

このような筒型のエサをお手本のサイトでは板と輪ゴムで取り付けていました。

エサを出す量は、穴を開ける数や大きさであったり、サーボモーターの動きを2回ではなく3回とすることで調節できますね。
あとは水槽に固定するだけで完成です。
設置してみました

ポテチの箱が高さピッタリでした!

水温を測ったり、LEDを制御したり、合わせて使いたい場合はGPIOが被らないようにしてブレッドボードに配線します。
実際に動かすモーター類なら、意外と他にもアイディアが沸きますね。
この記事のコメント(承認後に公開)