日記とか、工作記録とか

自分に書けることを何でも書いてゆきます。作った物、買ったもの、コンピュータ系の話題が多くなるかもしれません。

Raspberry pi 2 + Servo Motor(サーボモータを動かす)

Raspberry pi 2と合わせて買った電子工作エントリーキットには、小さなサーボモータが付属していました。せっかくなのでこれも動かしてみようと思います。
f:id:WindVoice:20160103181750j:plain

サーボモータの型番はTowerPro SG90です。

配線編

サーボモータは、スイッチがONになると回り続ける普通のモーターとは違って、指定した角度まで動くと止まることができます。一般には、ロボットの関節などで使われます。

作る側からみてどう制御するのか? というところが気になるわけですが、例によってGPIOポートを使います。PWM(Pulse Width Modulation)という仕組みで、電圧がONの時間とOFFの時間を細かく切り替え、ONになっている時間の割合を使って、角度をサーボモータ側に伝えるわけです。

PWMの仕組みとLEDを組み合わせると、LEDを明るく点灯したり暗めに点灯(実際には、目に見えないくらい細かく消灯している)することもできます。

さて、サーボモータからは3本のワイヤーがでています。赤っぽいのがプラス電源、黒っぽいのがマイナス電源(Ground)、もう一本オレンジっぽいのがでていたのでこれをGPIO 12番(PWM 0)につなぎます。キットの販売元のサイトによれば、プラス電源、マイナス電源の間にキャパシタをつなぐことになっていますので、これもつけました。でも、他のサイトで見る配線ではキャパシタがない場合もあります。GPIOに接続する途中に1kΩの抵抗を配線している例もあるみたいですが、私はつけていません。

サーボモータのメーカーは4.8Vの電源に接続する設計としているようですが、用意していた配線が足りないので、すでに配線済みだった3.3Vの電源にそのままつないでしまいました。大雑把ですが、5Vと3.3Vの比較ならパワーダウンしているはずですし、たぶん大丈夫でしょう。

ソフトウェア編

メーカーのサイトには簡単なサンプルプログラムがあります。これでもいいのですが、いまいちシンプルすぎるので動いただけでは面白くないです。あと、プログラムをシンプルにしたいからなのでしょうが、GPIOの終了処理を省略していたりします。

Pythonスクリプトを自分で書くことにしました。whileの永久ループのなかで、forとrangeを使ってサーボモータの角度を0.5秒ごとに少しずつ変化させています。値を2から12まで変化させる間に、ほぼ180度を行ったり来たりするように作りました(扇風機の首振りの要領です)。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO
import time
import signal
import sys

def exit_handler(signal, frame):
  """
  Ctrl+Cが押されたときにデバイスを初期状態に戻して終了する。
  """
  print("\nExit")
  servo.stop()
  GPIO.cleanup()
  sys.exit(0)

# 終了処理用のシグナルハンドラを準備
signal.signal(signal.SIGINT, exit_handler)

GPIO.setmode(GPIO.BCM)

# GPIO 12番を使用 (PWM 0)
GPIO.setup(12, GPIO.OUT)
# 20ms / 50Hzに設定、らしい
servo = GPIO.PWM(12, 50)

# 初期化
servo.start(0.0)

# ChangeDutyCycleに渡す値は 0.0 <= dc <= 100.0
# ……のはずだが、なぜか2から12の間で動作している。
dc = 0.0
while True:
  for dc in range(2, 12, 1):
    servo.ChangeDutyCycle(dc)
    print("dc = %d" % dc)
    time.sleep(0.5)
  for dc in range(12, 2, -1):
    servo.ChangeDutyCycle(dc)
    print("dc = %d" % dc)
    time.sleep(0.5)

永久ループするプログラムなので、Ctrl+Cで終了した場合に備えて、シグナルハンドラを設定して、シグナルハンドラの中の処理でGPIOをcleanupしています。GPIOライブラリの開発元(SourceForge)をみてみると、ChangeDutyCycle()に指定する値は0.0から100.0まで、となっているのですが、なぜかこれではうまくいかず、試行錯誤の結果2から12で0度~180度程度までサーボモータの角度が変化することを確認しました。

結果

さて、できあがったものを恒例のYouTube動画にしましたので引用しておきます。ちょっとわかりづらいですが、後半部分で配線も映しています。単に動かすだけだと「ふ~ん……」って感じですね。もう少し楽しめる何かをみつけなくては……

youtu.be