2008年 5月 30日 金曜日
[Sun SPOT Demo(9)] サーボ(Servo)を使ってパンとティルト(Pan and Tilt)を制御してみる。
Sun SPOTとServoを使って、カメラなどのパン(左右)とティルト(上下)の動きを制御する機構を作成してみます。今回は実装しませんが、Sun SPOTを2台使えばリモコン制御もできますね。
パン&ティルト制御機構は、以下のパーツを使って作成しました:
| 品名 | 参考価格 | 数量 |
| GWSサーボ S03T/2BB | 1600 | 2 |
| サーボブラケット AGBL-S03T | 1785 | 1 |
# サーボブラケットとGWSサーボ
組み立ては簡単です!
# 違うアングルから
配線は、ブレッドボードを使って行います。単三 x4(6V)の電池ボックスをブレッドボードの下に取り付けています。配線はサーボカーの時と基本的には同じです。3ピンのピンヘッダが2本並んでいますが、1番上のピンの横ラインがGND、真ん中の横ラインが電源(6V)、そして1番下のそれぞれのピンがサーボの制御信号ラインです。
また下図のように、GNDラインからケーブル(黒)をのばしてSun SPOTのGNDに、電源ラインからSun SPOTのVHに(赤)、そしてそれぞれのサーボの信号ラインからケーブル(白)を延ばして、下側のサーボ(パン)を H0、上側のサーボ(ティルト)をH1 に接続します。
# パン&ティルト制御機構を超強力接着剤で取り付けて完成!
おっと、デュークを忘れていました 
# 今度こそ完成!
今回は、デュークを左右および上下に一通り動かしてみる簡単なプログラムを作成しました。後半で、パンとティルトを同時に制御するプログラムも試しています。
# メインのプログラム部分
| package org.sunspotworld; import com.sun.spot.peripheral.Spot; import com.sun.spot.sensorboard.EDemoBoard; import com.sun.spot.sensorboard.peripheral.ITriColorLED; import com.sun.spot.sensorboard.peripheral.LEDColor; import com.sun.spot.util.*; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; /** * PanTiltControllerSpot: * パンおよびティルト制御用アプリケーション */ public class PanTiltControllerSpot extends MIDlet { private PanTiltController controller; // パン・ティルト制御用クラス private ITriColorLED[] leds; // LED /** ここからスタート */ protected void startApp() throws MIDletStateChangeException { new BootloaderListener().start(); // monitor the USB (if connected) and recognize commands from host Spot.getInstance().getSleepManager().disableDeepSleep(); // パン・ティルト制御用クラスの初期化 // パン用のサーボをH0, ティルト用のサーボをH1に接続 controller = new PanTiltController(EDemoBoard.H0, EDemoBoard.H1); // LEDの初期化 leds = EDemoBoard.getInstance().getLEDs(); initLeds(LEDColor.RED); // パンおよびティルトの位置の初期化 controller.center(); Utils.sleep(1000L); while (true) { blinkLeds(); // 右端、左端、中央の順にパン制御します testPan(); // 一番上、一番下、中央の順にティルト制御します testTilt(); blinkLeds(); Utils.sleep(3000L); // パンとティルトを同時に制御します testPanTilt(); blinkLeds(); Utils.sleep(10000L); } } /** 右端、左端、中央の順にパン制御します */ private void testPan() { controller.panRightmost(); Utils.sleep(1000L); controller.panLeftmost(); Utils.sleep(1000L); controller.panCenter(); Utils.sleep(1000L); } /** 一番上、一番下、中央の順にティルト制御します */ private void testTilt() { controller.tiltUpmost(); Utils.sleep(1000L); controller.tiltDownmost(); Utils.sleep(1000L); controller.tiltCenter(); Utils.sleep(1000L); } /** * パンとティルトを同時に制御します */ private void testPanTilt() { Thread[] threads = new Thread[2]; threads[0] = new PanWorker(); threads[1] = new TiltWorker(); for (int i = 0; i < threads.length; i++) { threads[i].start(); } for (int i = 0; i < threads.length; i++) { try { threads[i].join(); } catch (InterruptedException ex) { ex.printStackTrace(); } finally { threads[i] = null; } } } class PanWorker extends Thread { public void run() { testPan(); } } class TiltWorker extends Thread { public void run() { testTilt(); } } private void initLeds(LEDColor color) { for (int i = 0; i < leds.length; i++) { leds[i].setOff(); leds[i].setColor(color); } } private void blinkLeds() { for (int i = 0; i < 3; i++) { for (int j = 0; j < leds.length; j++) { leds[j].setOn(); } Utils.sleep(100L); for (int j = 0; j < leds.length; j++) { leds[j].setOff(); } Utils.sleep(100L); } } protected void pauseApp() { } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { } } |
# パン&ティルト制御用クラスpackage org.sunspotworld;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.IDemoBoard;
import com.sun.spot.sensorboard.peripheral.IServo;
import com.sun.spot.sensorboard.peripheral.Servo;
import com.sun.spot.util.Utils;
public class PanTiltController {
private final int MIN_VALUE = 800;
private final int MID_VALUE = 1500;
private final int MAX_VALUE = 2200;
private final int STEP = 100;
private final int WAIT = 10;
private IServo panServo; // 左右の動き
private IServo tiltServo; // 上下の動き
public PanTiltController(int panPinId, int tiltPinId) {
IDemoBoard demo = EDemoBoard.getInstance();
/** 左右の動きを制御 */
panServo = new Servo(demo.getOutputPins()[panPinId]);
/** 上下の動きを制御 */
tiltServo = new Servo(demo.getOutputPins()[tiltPinId]);
center();
}
/** パンおよびティルトを中央まで動かします */
public void center() {
pan(MID_VALUE);
tilt(MID_VALUE);
}
/** パンを右端まで動かします */
public void panRightmost() {
pan(MIN_VALUE);
}
/** パンを中央まで動かします */
public void panCenter() {
pan(MID_VALUE);
}
/** パンを左端まで動かします */
public void panLeftmost() {
pan(MAX_VALUE);
}
/** ターゲットで指定した値まで、パン(左右)方向にサーボを制御します */
public void pan(int target) {
moveServo(target, panServo);
}
/** ティルトを一番上まで動かします */
public void tiltUpmost() {
tilt(MIN_VALUE);
}
/** ティルトを中央まで動かします */
public void tiltCenter() {
tilt(MID_VALUE);
}
/** ティルトを一番下まで動かします */
public void tiltDownmost() {
tilt(MAX_VALUE);
}
/** ターゲットで指定した値まで、ティルト(上下)方向にサーボを制御します */
public void tilt(int target) {
moveServo(target, tiltServo);
}
/** ターゲットの位置にサーボを動かします */
private void moveServo(int target, IServo servo) {
int oldValue = servo.getValue();
if ((target - oldValue) > 0) {
for (int value = oldValue + STEP; value < target; value += STEP) {
setValue(value, servo);
}
} else {
for (int value = oldValue - STEP; value > target; value -= STEP) {
setValue(value, servo);
}
}
setValue(target, servo);
}
/** サーボに値を設定します */
private void setValue(int target, IServo servo) {
servo.setValue(target);
Utils.sleep(WAIT);
}
}
それでは実行してみます。。。
。。。。。
成功です 
# 土台を安定させていないのですこし暴れてます..
Posted at 02:20午前 5 30, 2008 by Shuichi Machida in SunSPOT | 投稿されたコメント[2]
すごい!Dukeがラジオ体操してますねー
かわいいです!
Posted by masakoo on 5月月 30日, 2008年 at 04:43 午後 JST #
> masakooさん
Duke ばかりでネタがマンネリ化してますが orz
次はねこび~ん!? :-)
Posted by machida on 6月月 02日, 2008年 at 10:52 午前 JST #