できること

第59回 Arduinoでモーター再入門(その3)サーボモーターを使ったデバイスに再チャレンジ!

2017-05-11 07.59.57

前回の記事では、無線LANを通じてサーボモーターを制御することができました。明らかに連載当初よりサーボモーターと仲良くなってきている実感を感じます。今回は、以前連載の第17回第18回で制作した水平カメラ台デバイスの実装に再挑戦してみます。正直に申し上げて、うまくいくかどうかはわかりません! 果たして、納得がいくものができるでしょうか……?

今回の電子工作レシピ

完成までの時間目安:60分
必要なパーツ

目次

  1. かつての生まれたての小鹿デバイス!
  2. デバイスの仕様検討
  3. 3Dプリンターによる形状作成
  4. プログラムの工夫について
  5. いざ動作!
  6. まとめ

1.かつての生まれたての小鹿デバイス!

水平カメラ台デバイス、一般的に「スタビライザー」とか「ジンバル」と呼ばれていて、昔は本格的な撮影現場などで利用されていることが多かったですが、最近ではドローン撮影やスマートフォンでも手軽に扱えるハンディタイプの製品もよく目にするようになりました。これらの製品では騒音性や速度などの面から現在ではブラシレスモーターが使われています。

写真1 スタビライザー

写真1 スタビライザー

そんなデバイスにあこがれて、第18回ではハンディタイプのデバイス作成にチャレンジしたのですが結果は下記のように、まるで生まれたての小鹿!のありさま。圧倒的な敗北です。

 

これはこれでなんとも愛嬌があるのですが、いかんせんデバイスとして機能しない時点でなんの役にもたちません。反省点は多々ありますが、明らかに使っているサーボモーターのトルクが追い付いていない感じがひしひしと伝わります。

そんなわけで、もう一度仕様を再検討しながら進めていきたいと思います。

 

2.デバイスの仕様検討

まず初めにサーボモーターの見直しです。以前利用したサーボモーターSG90は安価で手軽に使えるのは良いのですが明らかにトルクが足りてなかったです。そこで今回は、前回利用したMG996Rは動作速度は少しだけ遅くなるもののトルクが5倍近くある、このサーボモーターを利用します。

gimbal2

また、それ以外の部品は基本的にArduinoと加速度センサーになるので、これらはほぼ前回と同じ構成で進めてみます。サーボモーターが大きくなったので新たにアダプターから電源をとれるようにしました。回路については、第18回のものを参考にして制作していきます。

DSC_0360

6fab16e5322224d15f50cadcdbe6e2e4-e1424830428119

 

3.3Dプリンターによる形状作成

デバイスの形状に関しては、前回のようにホームセンターで木材や金具を購入してDIYでもよいのですが、せっかくなので3Dプリンターで出力してみます。今回、サーボモーターが大きくなったので、大きくなっても安定性を保てるようにすることと、カメラの三脚用ねじ穴を用意することで、カメラの三脚に固定しても使えて、小型の三脚につければハンディタイプでも利用できるような方向性でデザインしてみました。

7fc19c98c7fc0201d8acabfb17054d2d

最初にデザインして出力した形状です。組み立てると下記のようになります。

2017-04-24 08.52.18

これはこれで問題はなかったのですが、今回3Dプリンターの出力で利用しているABS樹脂の場合、素材が固まる際に縮みが発生してしまい、若干歪みが出てしまうことと、凹時ですべて出力すると各部品の組み立て時にねじが占めにくいなどの問題が発生してしまったため、試行錯誤した結果、下記のように2つのサーボモーターが付属する一番大きなパーツに関してはばらばらに出力することにしました。

223a656d6aef35e87cb0af86972f419c

実際に出力して、組み立てるとこんな感じになります。

2017-05-11 06.41.05 2017-05-11 06.42.25

2017-05-11 06.44.06

ケース自体はどんなカメラを載せるかなどで、載せる台は差し替えたり改良ができるようにしておきました。土台はできあがったので、次にプログラムの方を見ていきます。

 

4.プログラムの工夫について

プログラムに関しては、最初加速度センサーを実際に180度傾けて、出力される数値をもとにサーボモーターの傾き具合を調整するキャリブレーション作業が必要なので、第17回のプログラムを少し改良してキャリブレーション数値がわかりやすく出力されるようにしてみます。

 

Code-Example
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
int _maxX = 0;
int _minX = 1000;
int _maxY = 0;
int _minY = 1000;
int _maxZ = 0;
int _minZ = 1000;
 
//********************************
//加速度センサの値を取得するプログラム
//********************************
void setup()
{
// シリアルモニターの初期化をする
Serial.begin(9600) ;
}
void loop()
{
long x , y , z ;
x = y = z = 0 ;
x = analogRead(1) ; // X軸
y = analogRead(2) ; // Y軸
z = analogRead(3) ; // Z軸
 
if(_maxX < x){ _maxX = x; }
if(_minX > x){ _minX = x; }
if(_maxY < y){ _maxY = y; }
if(_minY > y){ _minY = y; }
if(_maxZ < z){ _maxZ = z; }
if(_minZ > z){ _minZ = z; }
 
int centerX = (_maxX-_minX)/2+_minX;
int centerY = (_maxY-_minY)/2+_minY;
int centerZ = (_maxZ-_minZ)/2+_minZ;
 
float rotateX = ((float)_maxX-(float)_minX)/180;
float rotateY = ((float)_maxY-(float)_minY)/180;
float rotateZ = ((float)_maxZ-(float)_minZ)/180;
 
 
Serial.print("X:") ;
Serial.print(_minX) ;
Serial.print(" ") ;
Serial.print(centerX) ;
Serial.print(" ") ;
Serial.print(_maxX) ;
Serial.print(" ") ;
Serial.print(rotateX) ;
Serial.print(" Y:") ;
Serial.print(_minY) ;
Serial.print(" ") ;
Serial.print(centerY) ;
Serial.print(" ") ;
Serial.print(_maxY) ;
Serial.print(" ") ;
Serial.print(rotateY) ;
Serial.print(" Z:") ;
Serial.print(_minZ) ;
Serial.print(" ") ;
Serial.print(centerZ) ;
Serial.print(" ") ;
Serial.print(_maxZ) ;
Serial.print(" ") ;
Serial.println(rotateZ) ;
delay(50) ;
}

f58002d4f68ba3b59c732393ea193af9

2017-05-11 06.53.15

このプログラムを動かして、シリアルモニターを立ち上げた後、センサをXY軸方向に-90度~90度までそれぞれ傾けて出力される数値を確認します。出力数値の最小値、最大値の幅を180度で割った数値が1度あたりの加速度センサーの傾き数値になるので、それをサーボモーターの動作とシンクロするようにします。

sirial

シリアルモニターで確認した数値をサーボモーターを動作させるプログラムに反映します。

Code-Example
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//********************************
//加速度センサの値を取得するプログラム2
//********************************
#include <Servo.h>
Servo myservoX;
Servo myservoY;
 
void setup()
{
// シリアルモニターの初期化をする
Serial.begin(9600) ;
myservoX.attach( 5 );
myservoY.attach( 6 );
}
 
void loop()
{
int i ;
long x , y;
// 各データを100回読み込んで平均化する
x = y = 0 ;
for (i=0 ; i < 100 ; i++) {
x = x + analogRead(1) ; // X軸を読み込む
y = y + analogRead(2) ; // Y軸を読み込む
}
 
x = x / 100 ;
y = y / 100 ;
 
int rotateX = (x-493)/1.30; //角度を求める式
myservoX.write( 90-rotateX );
Serial.print("X:") ;
Serial.print(x) ;
Serial.print(" ") ;
Serial.print(rotateX) ;
 
int rotateY = (y-488)/1.23;
myservoY.write( 90-rotateY );
Serial.print(" Y:") ;
Serial.print(y) ; // Y軸
Serial.print(" ") ;
Serial.println(rotateY) ; // Y軸
delay(10) ;
}

準備は整った、はずです。

 

5.いざ動作!

一通り準備ができたので、いよいよリベンジです。スイッチを入れると……。

おお! 明らかにパワーはあるのですが肝心の動作がやはりカクカク……。

原因を調べてみると、手で持っている際に発生する微妙なブレを加速度センサーがとらえて、軸を合わせるわけですが、合わせ終わった時にまた違う角度のブレが発生しているため、この差分を適切に吸収して、回転をなめらかにする必要があることがわかりました。小さいものを載せているとブレが少ないので比較的軽快に動いてくれるのですがスマートフォンなど少し重量のあるものだとブレがひどくなり、動画のようになってしまいます。これ以上は、かなり綿密にプログラムを改良していく必要がありそうです。

実際にYoutubeなどで調べてみると、上手にそれらの問題をクリアしている人もいれば、苦戦している方もいるようです。

ドローンで試している方も結構いるみたいですが、ドローンは比較的手持ちに比べて姿勢が安定している状態なので相性がいいのかもしれません。

この方はかなりなめらかに制御ができているようです。

 

まとめ

今回リベンジ、ということでハードウェア部分の問題はクリアできたのですが、今度はなめらかな制御をするためのプログラム側の問題が発覚しました。実際に作ってみるとわかるこれらの問題、普段気軽に使っている製品は開発者の先人の汗と知恵が詰まったものだということを実感させられます。このデバイスが日の目を見るためには、まだまだ道のりは長そうです……。

今回利用した3Dモデルデータはこちらからダウンロードできます

 

■関連記事

アバター画像

電子工作や新しいデバイスをこよなく愛するエンジニア。日常生活のちょっとしたことを電子工作で作って試して、おもしろく過ごしたいと日々考えています。

学生ロボコン2017 出場ロボット解剖計画