見出し画像

初めてのアニマトロニクス①:目の動きを実現するためのモジュールとソースコード解説(ラズパイ編)

ロボットを作りたい!アニマトロニクスをやってみたい!そんな思いから動き出した本企画。相棒となるおしゃべりロボットを作るべくさまざまな部位の動かし方や制御方法についてステップバイステップで検証していきます。

第一弾として今回は、「目の動き」を機械で制御してみましょう。記事「ロボットの目玉モジュールを作ろう!3Dプリンタで簡単作成」を参考に、そちらで紹介されているモジュールを利用してシングルボードコンピューターの使い方や、サーボモーターの動かし方を学んでいきます。
実際に動かした様子はこちら。


1. アニマトロニクスとは?

アニマトロニクス(Animatronics)は、アニメーションとエレクトロニクスを組み合わせた造語で、機械仕掛けの人形や動物などをリアルに動かす技術を指します。この技術は、映画やテーマパークでのキャラクター演出に広く利用されています。例えば、ディズニーランドの「魅惑のチキルーム」では、鳥のキャラクターたちが音楽に合わせて動くオーディオアニマトロニクス®が初めて導入されました。最近では、映画「Five Nights at Freddy's」の映画内のアニマトロニクスは全てCG無しの本物を利用していることでも話題に?なりました。

アニマトロニクスの制作には、機械工学、電子工学、プログラミング、そして芸術的なデザインなど、多岐にわたる専門知識と技術が必要です。これらの要素が組み合わさることで、まるで生きているかのようなリアルな動きを再現することが可能となります。

近年では、個人でも手軽にアニマトロニクスに挑戦できるようになってきました。例えば、ArduinoなどのマイクロコントローラーやRaspberry Piなどのシングルボードコンピュータとサーボモーターを使用して、目の動きや表情を制御する小型のアニマトロニクスを制作することが可能です。

2. 必要な機材・部品の準備

必要な機材一覧(汎用)

  • シングルボードコンピュータ:Raspberry Pi ¥6,500~(Amazon

  • ラズパイ用電源(5V, 3A等):micro USB端子に給電できるACアダプタ(今回は5V/2,000mAのACアダプタを利用)

  • 配線ケーブル:ブレッドボード・ジャンパーワイヤ(オス-メス) ¥300/10個(秋月電子通商

  • ブレッドボード:ブレッドボード BB-801 ¥220/個(秋月電子通商

  • 3Dプリンター:Bambu Lab A1 ¥54,800 (Amazon、'25/1/4現在)

目のモジュールを作るための部品一覧

3.パーツの出力

DLした.stlファイルをそのままスライサーに読み込んでそのまま出力しました。特に特別な設定は不要でした。
スライサーにはBambu Lab Studioを用いました。出力時間は合計で6時間くらいでした。

Bambu Lab Studioでスライス
実際に印刷した様子

4.パーツの組み立て

基本的には記事「ロボットの目玉モジュールを作ろう!3Dプリンタで簡単作成」の作り方通りです。
実際に組み立ててみて注意すべき点のみ記載します。

サーボモーターの向きには気を付ける
5. 基本動作を確認>SG90モーターの仕様を確認」で詳細を記しますが、今回使用するSG90モーターは180°の可動域しか持ちません。取り付ける位置やモーターの0°の位置がずれてしますと、角度を制御する際に混乱します。

5.Raspberry Piとサーボモーターを接続する

サーボモーターの茶色のワイヤがGND、赤色のワイヤが5Vに接続するように結線します。
目玉の動きを制御するモーターのオレンジ色のワイヤはGPIO2(ピン番号3)、瞼の動きを制御するモーターのオレンジ色のワイヤはGPIO3(ピン番号5)にそれぞれ接続しました。

ジャンパー線が飛び交っている!

各部品について詳細に確認したい場合は以下を参照してください。それぞれ参考になるサイトを掲載しています。

[補足]Raspberry PiのGPIOピンを確認

[補足]サーボモーターの端子を確認

[補足]ブレッドボードの仕組みを確認

6. 基本動作を確認

Pythonの開発環境を確認

Raspberry Pi OSには標準でpythonのIDE(統合開発環境)がインストールされている。メニュー>プログラミング>Python 3を選択して起動する。

メニューから>プログラミング>Python 3
python実行用の対話型シェルが立ち上がる

実行したコマンドを保存しておくために、適当なフォルダ内に.pyファイルを作成しておく。今回は、test_servo_motor.pyというファイルを作成し、このファイルに実行するコマンドを記録していく。

.pyファイル作成
.pyに記述したコマンドをshellに一行ずつコピペして実行

※Macbookで作成したファイルをいRaspberry Piに送りたい場合は、

  1. Raspberry PiのIPアドレスを確認

  2. 接続するMacbookとRaspberry Piを同一のネットワークに接続

  3. MacbookでFinder>移動>サーバへ接続を選択

  4. `afp://`を入力して「ブラウズ」を選択し、表示されたrasberrypiを選択して、ユーザ名とパスワードを入力して接続

接続成功すると、MacbookからRaspberry Pi側のディレクトリにアクセスできます。あとは送信したいファイルをドラッグ&ドロップすれば完了。

SG90モーターの仕様を確認

PWM(Pulse Width Modulation)サイクル 20ms
制御パルス 0.5ms~2.4ms
制御角 ±約90°(180°)
動作速度 0.1秒/60°
動作電圧 4.8V(~5V)

サーボはおよそ180度回転できます(それぞれの方向に90度ずつ)。
モーターの回転角度はDuty Cycle(デューティ比)によって制御できます。Duty Cycleとは、周期的な現象において、"ある期間" に占める "その期間で現象が継続される期間" の割合のことを意味し、SG90は2.5% ~ 12%で制御角 ±約90°を制御します。

PWMサイクル:20ms
これは周波数にすると 1 / 0.02 = 50Hz です。

制御パルス:0.5ms~2.4ms
Duty Cycleにすると 0.5 × 50 / 1000 ~ 2.4 × 50 / 1000 、つまり 0.025 ~ 0.12 でパーセントを単位にすると 2.5% ~ 12% という意味です。

制御角:±約90°(180°)
制御パルスに対し、制御角が決まります。
つまり、2.5% で -90° 回転、12% で +90° 回転 ということです。
これらを考慮すると、DutyCycleは次の計算式でDegreeから求まります。

DutyCycle = 2.5 + ( 12.0 - 2.5 ) / 180 × ( degree + 90 )

https://monomonotech.jp/kurage/raspberrypi/servo.html

目玉を動かしてみる

全体の動作

  1. test_move_eyeballs関数を呼び出すと、指定ピンでPWM信号を生成。サーボを初期位置(0度)に設定。

  2. サーボを45度 → -45度 → 0度の順で繰り返し動かし、眼球の左右移動を再現。

  3. Ctrl+Cで終了するとサーボを停止し、リソースを解放。

以下のコードをshellにコピペして実行すると、目玉が中心から水平方向45°、−45°、0°に1秒ごとに向くことが確かめられるはずです。

import RPi.GPIO as GPIO
from time import sleep

def set_angle(pwm, angle, pin_num):
    duty = 2.5 + (12.0 - 2.5) / 180 * (angle + 90)
    GPIO.output(pin_num, True)
    pwm.ChangeDutyCycle(duty)
    sleep(1)
    GPIO.output(pin_num, False)
    pwm.ChangeDutyCycle(0.0)
	

def test_move_eyeballs(pin_num):
    pwm = GPIO.PWM(pin_num, 50)
    pwm.start(0.0)
    set_angle(pwm, 0, pin_num)
	
    try:
        while True:
            set_angle(pwm, 45, pin_num)
            set_angle(pwm, -45, pin_num)
            set_angle(pwm, 0, pin_num)
    except KeyboardInterrupt:
        set_angle(pwm, 0, pin_num)
        pwm.stop()
        print("finished")
# GPIOの設定
GPIO.setmode(GPIO.BOARD)

# Pin番号3を使用することを宣言
pin_num = 3
GPIO.setup(pin_num, GPIO.OUT)

# 実行
test_move_eyeballs(pin_num)

# GPIO設定解除
GPIO.cleanup()

コードの解説

1. ライブラリのインポート

import RPi.GPIO as GPIO 
from time import sleep
  • RPi.GPIO: Raspberry PiのGPIOピンを制御するための標準ライブラリです。

  • time.sleep: 処理を一時停止するための関数を提供するライブラリです。


2. GPIOの初期化

GPIO.setmode(GPIO.BOARD) 

pin_num = 3
GPIO.setup(pin_num, GPIO.OUT)
  • GPIO.setmode(GPIO.BOARD):

    • Raspberry PiのGPIOピンの番号指定方法を「物理ピン番号(BOARDモード)」に設定します。

    • もう一つの方法として「GPIO番号(BCMモード)」もありますが、ここでは物理的なピン番号を使用しています。

  • GPIO.setup(pin_num, GPIO.OUT):

    • eyeball_pin_numで指定したピンを「出力モード(OUTPUT)」に設定します。このピンを使用してデバイスに信号を送る準備をします。


3. set_angle 関数
この関数は、サーボモーターを指定した角度に動かします。

  • 引数:

    • pwm: PWM制御オブジェクト。サーボモーターの制御に使用。

    • angle: 動かしたい角度。

    • pin_num: GPIOピン番号。

デューティサイクルの計算
サーボモーターの制御信号(デューティサイクル)を計算します。角度angleは±90度を想定。

duty = 2.5 + (12.0 - 2.5) / 180 * (angle + 90)

GPIOピンの出力設定
指定ピンをONにする。

GPIO.output(pin_num, True)

サーボを動かす
サーボモーターを指定角度に動かし、安定するまで1秒待つ。

GPIO.output(pin_num, True)

ピンをOFFにして停止
モーターへの信号を止めて省エネモードに移行。

GPIO.output(pin_num, False)
pwm.ChangeDutyCycle(0.0)

4. test_move_eyeballs 関数
この関数は、サーボモーターを繰り返し動かして「眼球の動き」を模倣します。

  • 引数:

    • pin_num: GPIOピン番号。

PWMの初期化
PWMを50Hzで初期化し、サーボモーターを0度の位置に設定。

pwm = GPIO.PWM(pin_num, 50)
pwm.start(0.0)
set_angle(pwm, 0, pin_num)

無限ループで角度を変化
サーボを45度、-45度、0度に動かして往復運動を繰り返す。

while True:
    set_angle(pwm, 45, pin_num)
    set_angle(pwm, -45, pin_num)
    set_angle(pwm, 0, pin_num)

キーボード割り込みへの対応
Ctrl+Cでプログラムを終了すると、サーボを停止してPWMリソースを解放。

except KeyboardInterrupt:
    set_angle(pwm, 0, pin_num)
    pwm.stop()
    print("finished")

まぶたを動かしてみる

全体の動作

  1. サーボモーターを制御するためのPWM信号を設定します。

  2. モーターを角度50と40の間で繰り返し動かし、「まぶたの動き」を模倣します。

  3. キーボード割り込みで終了すると、モーターを停止し、リソースを解放します。

以下の関数をshellにて実行後、GPIOを初期化して関数を実行します。

def test_move_eyelids(pin_num):
    pwm = GPIO.PWM(pin_num, 50)
    pwm.start(0.0)
    set_angle(pwm, 0, pin_num)

    try:
        while True:
            set_angle(pwm, 50, pin_num)
            set_angle(pwm, 40, pin_num)
    except KeyboardInterrupt:
        set_angle(pwm, 0, pin_num)
        pwm.stop()
        print("finished")
# GPIOの設定
GPIO.setmode(GPIO.BOARD)

# Pin番号3を使用することを宣言
pin_num = 5
GPIO.setup(pin_num, GPIO.OUT)

# 実行
test_move_eyelids(pin_num)

# GPIO設定解除
GPIO.cleanup()

コードの解説

関数: test_move_eyelids
この関数は、指定されたGPIOピン(pin_num)を使用してデバイスを動作させるロジックを持っています。

def test_move_eyelids(pin_num):

メインループ
この部分で、まぶたが「開閉」しているような動作を模倣します。

try:
    while True:
        set_angle(pwm, 50, pin_num)
        set_angle(pwm, 40, pin_num)
  • while True:

    • 永遠にループして処理を繰り返します。

  • set_angle(pwm, 50, pin_num):

    • モーターを「50の角度」に設定します。具体的な角度はset_angleの定義によります。

  • set_angle(pwm, 40, pin_num):

    • モーターを「40の角度」に設定します。


目玉とまぶたをランダムに動かしてみる

これまでの実験を組み合わせてまぶたと目玉をそれぞれランダムに動かしてみます。

def move_eyeballs(pin_num, angles=[0, 45, -45]):
    # 引数anglesリストからランダムに角度を選択
    choiced_angle = random.choice(angles)
    pwm = GPIO.PWM(pin_num, 50)
    pwm.start(0.0)

    set_angle(pwm, choiced_angle, pin_num)
    pwm.stop()

def move_eyelids(pin_num, angles=[10, 50, 40]):
    # 引数anglesリストからランダムに角度を選択
    choiced_angle = random.choice(angles)
    pwm = GPIO.PWM(pin_num, 50)
    pwm.start(0.0)

    set_angle(pwm, choiced_angle, pin_num)
    pwm.stop()

def main():
    # define parameters
    eyeball_pin_num = 3
    eyelids_pin_num = 5
	
    # Initialize GPIO
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(eyeball_pin_num, GPIO.OUT)
    GPIO.setup(eyelids_pin_num, GPIO.OUT)

    try:
        while True:
            move_eyeballs(eyeball_pin_num)
            move_eyelids(eyelids_pin_num)
			
    except KeyboardInterrupt:
        print("finished")
# 実行
main()

GPIO.cleanup()

7. 終わりに

今回は、初めてのアニマトロニクスとして目の動きを実現するための簡単な実験を行いました。氏の目玉モジュールはシンプルながら目の動きを再現できてとても楽しめました。皆さんもぜひ参考にしてアニマトロニクスで遊んでみてはいかがでしょうか。

いいなと思ったら応援しよう!