ばかおもちゃ本店:Youtube twitter:@sashimizakana Amazon.co.jpアソシエイト

2013年8月24日土曜日

BeagleBone Blackでサーボモーターの使い方

もうスカートめくり以外でウケる動画を作れないんじゃ無いかというマンネリズムに悩む日々を送っています。どうも、ばかおもちゃ本店です。動画を作ったり工作をしたりブログを書いたりしております。

さて、今回は以前作ったスカートめくりの動画なんかでも使っているサーボモーターのBeagleBone Blackでの使い方を書く。安いサーボが出回っていることもあり、ちょっとした動きのあるものを使うには、サーボモーターは必須のアイテムでしょう。

サーボモーターについては以下のページなんかを参照のこと。

サーボモータの制御

上記のページにあるとおり、サーボモーターを動かすにはPWMという、マイコンなんかに付いている出力のオン/オフの周波数やデューティ比(オンオフの比率)を制御できる機能を使う。

でいきなり結論を書くと、サーボモーターのPWMはanalogWriteに引数を与えるだけですぐに使える。これがAVRなんかを直接叩くと結構いっぱいあるPWM関連の設定項目一個一個にどのビットが対応するみたいなことを読みながら、特定のメモリにその設定を書き込むみたいなことをやらなきゃならんので、大変簡単である。
更にぶっちゃけて書くと、PWMの使い方はここに書いてある。

BeagleBoard.org - ServoMotor

これで分かる人はこれを読めば良いでしょう。
分からない人のために、コードを解説します。

***

サンプルの説明

まず前段にも書いてあるけど、前提として、サーボモーターは一定時間出力がオンになっていると、その出力時間に応じて角度が変わるというものである。
上記のページを参照すると、オンになっている時間が1.5ms~2ms、一周期は15ms~20msで出力できれば良いらしい。ただこれはメーカーによって違いがあって、Amazonで買った格安サーボは0.5ms~2.4msくらいの幅になっていた。またこの幅は割と一般的なものなのか、上記のBeagleBoard.orgのサンプルもこの幅に合わせてあるし、ArduinoのServoクラスもデフォルトはこれくらいの値になっている。

次にanalogWriteの仕様は以下のとおり。

BeagleBoard.org - analogWrite

analogWrite(pin, value, [freq], [callback])

[引数]

pin:
出力対象のピン名。サーボモーターのサンプルではP9_14となっている。
analogWriteのページを見れば分かるが、USBポートに近い側のピンにあるPWM用のポートだ。ちなみにこういうマイコンの入出力はポートによって機能が違っているので、適当なポートに変えても良いってわけではない(PWMポートになら変えても良い)。

value:
デューティ比、設定値は0~1。

freq:
周波数(Hz)。サーボのサンプルでは60で固定されている。
60Hzは1秒間に60周期あるという意味だから、一周期は1/60で約16msになる。
上で書いてある15ms~20msというやつですね。

callback:
出力処理終了時に実行するコールバック。

ではサンプルを見ていく。

var b = require('bonescript');
var SERVO = 'P9_14';
var duty_min = 0.03;
var position = 0;
var increment = 0.1;

b.pinMode(SERVO, b.OUTPUT);
updateDuty();

function updateDuty() {
    // compute and adjust duty_cycle based on
    // desired position in range 0..1
    var duty_cycle = (position*0.115) + duty_min;
    b.analogWrite(SERVO, duty_cycle, 60, scheduleNextUpdate);
    console.log("Duty Cycle: " + 
        parseFloat(duty_cycle*100).toFixed(1) + " %");   
}

function scheduleNextUpdate() {
    // adjust position by increment and 
    // reverse if it exceeds range of 0..1
    position = position + increment;
    if(position < 0) {
        position = 0;
        increment = -increment;
    } else if(position > 1) {
        position = 1;
        increment = -increment;
    }
    
    // call updateDuty after 200ms
    setTimeout(updateDuty, 200);
}

8行目まではライブラリを読み込んで、変数の設定をしている。SERVOはサーボにつかうPWMのポート名、duty_minは0度のときのデューティ比を表している。ここでは0.03で3%になっている。上述の通り周期が約16msなので、16*0.03=0.48msが最小になる。1ms~2msのサーボを使うなら、duty_minを0.06などにする必要がある。

positionは180度までを0~1で表していて、incrementはサーボの動作幅だが、どうせ実際に使うときは角度を入力して動作させるようなものにするはずなので、特に気にする必要は無い。同じ理由で、scheduleNextUpdateという関数も単純にポジションをincrement分ずつ増やしていって、1になったらincrement分減らすというだけのものなので、あんまり気にしなくて良い。

で、やっと実際のPWM出力の部分であるupdateDutyだが以下の二行が重要である。
(あとはコメントと、コンソール出力なので)

    var duty_cycle = (position*0.115) + duty_min;
    b.analogWrite(SERVO, duty_cycle, 60, scheduleNextUpdate);

duty_cycleはposition*0.115 + duty_minということで、0の時は0+0.03でデューティ比が3%になる。1の時は0.115+0.03なので0.145で14.5%になる。
b.analogWriteには出力ポート、デューティ比、周波数、コールバックを渡していていて、60Hzの3~14.5%でパルス幅0.48ms~2.32msがサーボに出力される。

ということで、サンプルの説明はこんな感じ。

実際につかうときは角度をパルス幅に変換したり、最小・最大時のパルス幅を設定できるライブラリみたいなものを作ってしまった方が良いだろうと思う。
その辺探してみて、無かったらまた自作してみよう。



マイクロサーボ SG90 (2個入)
Tower Pro
売り上げランキング: 24,712
安いけど品質も値段なり。

BeagleBone Black
BeagleBone Black
posted with amazlet at 13.08.25
Circuitco Electronics LLC
売り上げランキング: 2,613
たのしい。