Spresense HDRカメラ用のズームフォーカスレンズのモーターを制御する

Spresense HDRカメラをズームフォーカスカメラ化するために購入した正体不明のズームフォーカスレンズですが、[ネットに転がっていた情報](https://qiita.com/TaroYoshino/items/7f2b4e3c9ce0c7de4176)を頼りに動かしてみたいと思います。

## モータードライバの選定
前回しらべた仕様では、モーターはステッピングモーターらしいことがわかっています。モータードライバには、TI社製のDRV8835を使おうと思います。DRV8835はロジック側の信号電圧が2Vで、少し定格割れですが、メインボードの1.8VのIO電圧でも動かせる利点があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/ce041c2a-6758-d49f-729d-5445859c5867.png)
https://akizukidenshi.com/catalog/g/g109848/

DRV8835はモードが「MODE」端子で指定できるようになっています。「MODE=0」で ”IN/IN”モード、「MODE=1」では、”PHASE/ENABLE”モードです。どちらがよいのか悩むところですが、今回使おうと思っている [Arduino  Stepper library](https://github.com/arduino-libraries/Stepper)のソースコードを見ると、どうも IN/IN モード前提となっているようなので、IN/INモードを使用します。

| IN1 | IN2 | OUT1 | OUT2 | 動作 |
| --- | --- | ---- | ---- | ---- |
| 0   | 0   | HiZ  | HiZ  | 空転 |
| 0   | 1   | L    | H    | 逆転 |
| 1   | 0   | H    | L    | 正転 |
| 1   | 1   | L    | L    | ブレーキ |


このライブラリはモーターのスピードも設定できるようになっています。rpm（revolutions per minuites）で指定するようになっています。レンズのデータシートを見ると1パルス（ステップ）あたり 0.224度なのでモーターが１回転するステップ数は、1607パルスになります。推奨動作パルス数が 300-800 PPSなので、モーターを一回転するには、5.4～2.0秒になります。これを rpm に換算すると、**「11～30 rpm」** になります。

## SPRESENSEとレンズとの接続
SPRESENSEとの結線は次のようにしました。実験しやすいようにレンズのコネクタはとってピンヘッダを接続しています。MODEはGNDに落としていますが、DRV8835のデータシート見ると内部でプルダウンをしているようなので、接続しなくても問題なさそうです。
<br/>


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/f7b23697-bd56-46b0-bb7a-82bf093e0035.png)

UART2を潰すのは少しもったいない気もしますが、SoftwareSerial で代用できるし、ここは配線を楽にすることを選びました。モーターのコントロールは可変抵抗で行います。メインボードのADCのレンジは0.7Vなので、1.8Vだと半分以下のコントロールしかできません。抵抗分圧すべきですが、動作確認用のためだけなので良しとしましょう。

## 動作確認用のコード

動作確認用に作ったスケッチが下記です。可変抵抗の値の読み込みに analogRead を使うの簡単ですが、レンジが1024とステップ数に不足するので、SDKのAPIで直接int16_tの値を直接読み込みます。

```c++
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <arch/cxd56xx/scu.h>
#include <arch/cxd56xx/adc.h>
#include <Stepper.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)

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;

void setup() {
  Serial.begin(115200);

  // 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, zoomMaxStep);

  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;
  zoom_pos = val_z;
  focus_pos = val_f;
  ZoomStepper.step(zoom_step);
  FocusStepper.step(focus_step);

  delay(100);
}
```

## ズームフォーカスレンズの動作

動作の様子がこちら。モーターがすごく熱くなるのところが気になります。駆動するときだけモーター電源をつけるようにしたほうがよいかな。ちょっと悩むところです。

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">Spresense HDRカメラ用のズームフォーカスレンズのコントロール。モーターがすごい熱くなるのが気になる。 <a href="https://t.co/T1DVWHA1VM">pic.twitter.com/T1DVWHA1VM</a></p>&mdash; よしのたろう 🍥純国産ボード”スプレッセンス”応援団長（仮） (@Taro_Yoshino) <a href="https://twitter.com/Taro_Yoshino/status/1870467782346993690?ref_src=twsrc%5Etfw">December 21, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

次はいよいよ画像をとってみたいと思います。

関連記事
[Spresense HDRカメラのズームフォーカスレンズ用のフォルダを作る](https://qiita.com/TaroYoshino/items/d0abd58370d2c42f6fbb)
[Spresense HDRカメラ用のズームフォーカスレンズのモーターの仕様を確認する](https://qiita.com/TaroYoshino/items/7f2b4e3c9ce0c7de4176)
[Spresense ズームレンズ対応HDRカメラを動作させてみた](https://qiita.com/TaroYoshino/items/98f5ab07975a0fb59ebc)