前回の記事でズームレンズのモーター制御に成功しました。転がっていたデータシートがあっていてよかった。今回はいよいよHDRカメラとあわせてカメラとして動作するか買う人をしていきます。
SPRESENSE HDRカメラズームレンズの接続
Spresense HDRカメラとしての動作を確認するために、LCDとSDカード、そして画像を保存するためのシャッターボタンを追加しました。SDカードとLCDとの接続には拡張ボードを使います。
実際の接続の様子はこちら。かなりビジーになってしまいました。
SPRESENSE HDRカメラズームレンズのプログラム
ズームとフォーカスは可変抵抗で調整します。シャッターを押すとBMP画像でSDカードに保存します。
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <arch/cxd56xx/scu.h>
#include <arch/cxd56xx/adc.h>
#include <Camera.h>
#include <Stepper.h>
#include <Adafruit_ILI9341.h>
#include <BmpImage.h>
#include <SDHCI.h>
// D27 - Focus A+ (BLACK)
// D28 - Focus A- (BLUE)
// D01 - Focus B+ (RED)
// D00 - Focus B- (WHITE)
// D23 - Zoom A+ (ORANGE)
// D24 - Zoom A- (GREEN)
// D25 - Zoom B+ (YELLOW)
// D26 - Zoom B- (PURPLE)
#define FOCUS_AP (27)
#define FOCUS_AN (28)
#define FOCUS_BP (1)
#define FOCUS_BN (0)
#define ZOOM_AP (23)
#define ZOOM_AN (24)
#define ZOOM_BP (25)
#define ZOOM_BN (26)
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
BmpImage bmp;
SDClass theSD;
const int turnSteps = 1607; // 0.224 deg/step
const int zoomMaxStep = 2342;
const int focusMaxStep = 2342;
const int rpm = 20;
Stepper FocusStepper(turnSteps, FOCUS_AP, FOCUS_AN, FOCUS_BP, FOCUS_BN);
Stepper ZoomStepper(turnSteps, ZOOM_AP, ZOOM_AN, ZOOM_BP, ZOOM_BN);
int fd_a2;
int fd_a3;
const int intPin = 21;
bool bButtonPressed = false;
void changeState() {
bButtonPressed = true;
}
void setup() {
Serial.begin(115200);
tft.begin();
tft.setRotation(3);
theCamera.begin();
theCamera.setStillPictureImageFormat(
CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V,
CAM_IMAGE_PIX_FMT_RGB565);
while (!theSD.begin()) { Serial.println("Insert SD Card"); }
pinMode(intPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(intPin) ,changeState ,FALLING);
// initialize LLPADC 2 and 3
fd_a2 = open("/dev/lpadc2", O_RDONLY);
fd_a3 = open("/dev/lpadc3", O_RDONLY);
ioctl(fd_a2, SCUIOC_SETFIFOMODE, 1);
ioctl(fd_a3, SCUIOC_SETFIFOMODE, 1);
ioctl(fd_a2, ANIOC_CXD56_FIFOSIZE, 2);
ioctl(fd_a3, ANIOC_CXD56_FIFOSIZE, 2);
ioctl(fd_a2, ANIOC_CXD56_START, 0);
ioctl(fd_a3, ANIOC_CXD56_START, 0);
FocusStepper.setSpeed(rpm);
ZoomStepper.setSpeed(rpm);
Serial.println("move home position");
FocusStepper.step(focusMaxStep);
ZoomStepper.step(zoomMaxStep);
Serial.println("home position");
delay(1000);
}
void loop() {
static int zoom_pos = zoomMaxStep;
static int focus_pos = focusMaxStep;
int16_t val_z;
int16_t val_f;
while(read(fd_a2, &val_z, sizeof(int16_t)) == 0);
while(read(fd_a3, &val_f, sizeof(int16_t)) == 0);
val_z = map(val_z, -0x7fff, 0x7fff, 0, zoomMaxStep);
val_f = map(val_f, -0x7fff, 0x7fff, 0, focusMaxStep);
Serial.println("Zoom: " + String(val_z));
Serial.println("Focus: " + String(val_f));
int zoom_step = val_z - zoom_pos;
int focus_step = val_f - focus_pos;
if (abs(zoom_step) > 100 || abs(focus_step) > 100) {
zoom_pos = val_z;
focus_pos = val_f;
ZoomStepper.step(zoom_step);
FocusStepper.step(focus_step);
}
CamImage img = theCamera.takePicture();
if (img.isAvailable()) {
tft.drawRGBBitmap(0, 0, (uint16_t*)img.getImgBuff(), CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V);
if (bButtonPressed) {
static int g_counter = 200;
bmp.begin(BmpImage::BMP_IMAGE_RGB565, CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V, img.getImgBuff());
bmp.alignImageLine(false);
char filename[16] = {};
sprintf(filename, "rgb16%03d.bmp", g_counter++);
if (theSD.exists(filename)) theSD.remove(filename);
File myFile = theSD.open(filename, FILE_WRITE);
myFile.write(bmp.getBmpBuff(), bmp.getBmpSize());
myFile.close();
bmp.end();
Serial.println("Saved as " + String(filename));
bButtonPressed = false;
}
}
}
撮影結果
フォーカスを手動で合わすのはちょっと難儀しましたが、慣れてくるとなんとかなりますね。今後、オートフォーカスの実装を試してみたいと思います。倍率をかえた画像をいくつか撮影をしましたので、その結果をこちらに披露します。被写体は私の大好きなトラスト・イカちゃんです。
最大ワイドのケースでは、被写体との距離が近すぎてフォーカスがあいませんでした。レンズの特性をよく考えて制御をする必要がありますね。
こうして画像を並べてみると、かなりズームできるのがわかります。これは、かなり使えそうです。HDRカメラなら監視カメラとしてもばっちりです。オートフォーカスやパン・チルト機能をつければ立派なカメラになりそうですね。
そのあたりは今後検討していきたいと思います。
関連記事
Spresense HDRカメラのズームフォーカスレンズ用のフォルダを作る
Spresense HDRカメラ用のズームフォーカスレンズのモーターの仕様を確認する
Spresense HDRカメラ用のズームフォーカスレンズのモーターを制御する