電動レンズを入手
SPRESENSE HDRカメラのよいところは、レンズが着脱可能なところ。せっかくならズームレンズとか制御できるともっと面白いかなと思い、実験用に次のレンズを入手しました。
電動レンズ、アルミ合金カメラレンズ、カメラオートアイリスレンズCCTVカメラ
アイリス制御なのであまり面白みはないですが、実験用なので安いのにしてみました。で、肝心のモータ制御ですが、探せども探せどもモータに関するドキュメントがまったく見つからない。Arduino界隈では電動レンズ制御はあまり流行らないのでしょうか。
やっと見つけたドキュメントが下記。どうもステッピングモーターを使っているっぽいです。アイリスのオープン、クローズに3秒もかかるのにちょっとびっくりです。
HDRカメラに電動レンズを装着
HDRカメラのレンズはネジ止めされているので簡単に外すことができます。M14レンズホルダとなっていましたが、ネジ穴はM12と同じ位置にあるので次のアダプタを3Dプリンタで印刷して使うことができます。
ただネジ穴が途中で細くなっていたので、上からネジが止められません。そこで無理やりドリルを使ってネジ穴を広げました。ステンレス製なのでちょっと苦労しました。
すったもんだで装着した状態の写真です。かっこいいですね。
SPRESENSEと電動レンズHDRカメラを接続する
電動レンズはきっとステッピングモータだろうということで、定番のDRV8835を使って次のように SPRESENSEと接続をしました。
実際の接続の様子は次の通りです。
制御プログラムは普通のステッピングモータと同じようなコードを組んでみたのですがどうも挙動がおかしい。加える電圧パターンでアイリスが開いたり閉じたり。電圧を印加する時間でアイリスの開口率も変わるみたいで、なにが何やら、、、いろいろと試行錯誤を繰り返し、なんとなく動いたかなというのが下記のコード。
#include <Camera.h>
#include <MP.h>
#include "Adafruit_ILI9341.h"
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define SAVE_IMAGE
#ifdef SAVE_IMAGE
#include <SDHCI.h>
#include <BmpImage.h>
SDClass SD;
BmpImage bmp;
#endif
const int pinIN1 = 0; // Black C+ (A) 制動+
const int pinIN2 = 1; // Yellow C- (B) 制動ー
const int pinIN3 = 2; // White D+ (C) 駆動+
const int pinIN4 = 3; // Red D- (D) 駆動ー
int phase = 0;
// Phase ABCD Coils
// 0 1000 A 0x01
// 1 1100 AB 0x03
// 2 0100 B 0x02
// 3 0110 BC 0x06
// 4 0010 C 0x04
// 5 0011 CD 0x0c
// 6 0001 D 0x08
// 7 1001 A D 0x09
const uint8_t phase_map[] = {0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x09};
void Init() {
pinMode(pinIN1, OUTPUT);
pinMode(pinIN2, OUTPUT);
pinMode(pinIN3, OUTPUT);
pinMode(pinIN4, OUTPUT);
}
void SetPhase(int8_t p) {
phase = p;
if (phase < 0) phase = 7;
if (phase > 7) phase = 0;
digitalWrite(pinIN1, ((phase_map[phase] & 0x01) == 0x01 ? HIGH : LOW));
digitalWrite(pinIN2, ((phase_map[phase] & 0x02) == 0x02 ? HIGH : LOW));
digitalWrite(pinIN3, ((phase_map[phase] & 0x04) == 0x04 ? HIGH : LOW));
digitalWrite(pinIN4, ((phase_map[phase] & 0x08) == 0x08 ? HIGH : LOW));
}
void Reset() {
digitalWrite(pinIN1, LOW);
digitalWrite(pinIN2, LOW);
digitalWrite(pinIN3, LOW);
digitalWrite(pinIN4, LOW);
}
void setup() {
tft.begin();
theCamera.begin();
tft.setRotation(3);
Init();
theCamera.setAutoExposure(false);
theCamera.setAbsoluteExposure(100); // 10msec
theCamera.setAutoWhiteBalance(true);
theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_FLUORESCENT);
theCamera.setStillPictureImageFormat(
CAM_IMGSIZE_QVGA_H ,CAM_IMGSIZE_QVGA_V
,CAM_IMAGE_PIX_FMT_RGB565);
Reset();
delay(100);
}
void loop() {
static int inc = 25;
static int delay_time = 0;
static const int max_delay = 3000;
static int count = 0;
printf("%d\n", count++);
delay_time += inc;
if (delay_time >= max_delay) delay_time = max_delay-1;
printf("delay_time = %d\n", delay_time);
SetPhase(5); // なぜこれでアイリスが開くか謎すぎる
delay(delay_time); // 短い時間のほうがアイリスが開く?
CamImage img;
img = theCamera.takePicture();
if (img.isAvailable()) {
tft.drawRGBBitmap(0, 0, (uint16_t *)img.getImgBuff(), CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V);
#ifdef SAVE_IMAGE
// need 896kB for Maincore memory to save the below bmp file
char filename[16] = {0};
bool reverse = false;
bmp.begin(BmpImage::BMP_IMAGE_RGB565, CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V, (uint8_t*)img.getImgBuff(), reverse);
bmp.alignImageLine();
sprintf(filename, "img%03d.bmp", delay_time);
File myFile = SD.open(filename, FILE_WRITE);
myFile.write(bmp.getBmpBuff(), bmp.getBmpSize());
myFile.close();
bmp.end();
#endif // SAVE_IMAGE
}
SetPhase(2); // なぜこれでアイリスが開いたままになるか謎すぎる
delay(max_delay); // 短い時間だとうまくいかない なぜ??
}
撮影結果
撮影結果を次に示します。ただ、電圧印加時間が500ミリ秒を超えると画が変わりませんでした。印加ア時間を長くすることでアイリスをもっと閉じれると思ったのですが、この制御パターンだとある一定の開口で止まってしまうようです。
なんとなくそれっぽい結果が得られましたが、このコードなんで動くのかさっぱりわかりません。何が正解かも不明… いろいろ調査した結果、どうもこのアイリス制御は次のコンポーネントを使っているのではないかと思われました。(光学系のキーコンポーネントは、やはり日本製なんですね)
制御方式を見ると、「制動コイルによる速度制御方式」とありますが、どのように制御するのかどこにもドキュメントがなく、ここで手詰まり。どなたか、制御方法ご存知の方がいたら教えてください!!
作ってみた感想
電動レンズが使えることがわかったのは朗報です。しかし、素性のよくわからないモータ製品は、やはり簡単には制御はできませんね。このレンズをバラせればもう少し分かりそうですがステレンス製でがっちり組み上げられているので難しそうです。もう少し調べて制御できるようにして、次はもっと高機能なズームやフォーカスのついた電動レンズにチャレンジしてみたいと思います。