目次 [ Contents ]
モータドライバを使ってDCモータを動かしてみました。簡易的なフォローフォーカスが作れないかな、と。
結論として、フォローフォーカスとしては「失敗」なんですけど、環境や使用モータによっては上手く機能すると思うので、参考になるようであれば。
TA7267BP
以前、マルツ電波で見つけたモータドライバ、TA7267BPです。
Arduinoなどのマイコンから2系統の電圧変化を送ることで、モータの回転方向等を制御できます。
確か200円もしなかったので、ついでに購入してそのまま放置してたんですが、先日、ポロっと出てきたので、久しぶりに動かしてみました。そしたら、クリックなしロータリーエンコーダと組み合わせれば、結構細かい制御ができます。
そこで、アルミチャンネル等を加工して固定出来るようにして、動作を確認してみました。
ちなみに、TR7267BPのピン配置は以下のようになっています。
そしてこの電子パーツはもう時代遅れらしく、あまり市場には出回っていないようです。普段、自分が利用する入手先だとここしかありませんでした。
ただし、今回のスケッチでは、Arduinoの2ピンで右回り左回りのHigh・Lowを出しているだけなので、同様な機能のICはいくらでも見つけられるかと。
使用電子パーツ
- Arduino
- モータドライバ
- ロータリーエンコーダ(クリックなし)
- DCモータ
- コンデンサ(モータ用)
駆動部分はこちらを使いました。ただ、後述通り、あまり抵抗の大きい物体を細かく動かすのには向いてないので、今回の用途としてはあまりオススメできません。参考までに。
回路図
TA7267BPは大きいモータ用らしく、こういった小さいモータにはあまり適さないようです。でも、まあ動きました。
また、モータへ供給する電源は写真だと5Vバッテリーで一緒にしていますが、このギヤボックスのモータは3V定格です。ちゃんと定格に合わせた別電源を接続する事をオススメします。
スケッチ
このプロジェクトファイルをダウンロードするか、下記のウインドウを開いてコピペしてください。
Sample Sketch file – DC motor driver contorl
*このスケッチにはMsTimer2ライブラリが必要です。IDEに無ければインストールしてください。
// DC motor driver control v1.1
// for Arudino Sketch 21.6.2017
// by jumbler (jumbleat.com)
#include <MsTimer2.h>
#define TIM MsTimer2
//defined values
// pins
#define ENCA 3
#define ENCB 4
#define MTRA 5
#define MTRB 6
#define LED 13
//values
#define MOVE_VAL 10
#define REV_RAG 150
//encoder constants
#define ENC_JUDGE 25
#define ECUR B00000011 // enc current position
#define EPRE B00001100 // enc previous position
#define EHOM B00110000 // enc home position
#define ETRG B01000000 // enc has been triggered
#define ECHG B10000000 // encoder count has been charged
const byte enc_pins[2] = {ENCA, ENCB};
volatile byte enc_status;
volatile short enc_count = 0;
//motors
byte motor_pins[2] {MTRA, MTRB};
short ENC_COUNT(int val) {
static int enc_old;
if (enc_old != enc_count)
{
val += enc_count - enc_old;
enc_old = enc_count;
enc_status = enc_status & ~ECHG;
}
return val;
}
byte SBIT(byte layer) {
for (byte i = 0 ; i < 8; i++) if ((layer >> i)&B00000001) return i;
}
byte SBVAL(byte val, byte layer) {
byte tmp = (val & layer) >> SBIT(layer);
return tmp;
}
byte ENC_PIN_READ() {
// Read encoder pins status
byte enc_cur = (digitalRead(ENCB) << 1) + digitalRead(ENCA);
// Modify position order
if (enc_cur < 2) enc_cur = 1 + (enc_cur * -1);
if (!SBVAL(enc_status, ETRG))
{
if (SBVAL(enc_status, EHOM) != enc_cur) enc_status = enc_status | ETRG;
}
// apply update to enc_status
enc_status = (enc_status & B11110000) + ((enc_status & ECUR) << 2) + enc_cur;
return enc_cur;
}
void ENC_GAUGE() {
static unsigned short gauge[2];
byte curr = ENC_PIN_READ();
// if encoder change has been triggerd
if (SBVAL(enc_status, ETRG))
{
byte prev, dist;
dist = SBVAL(enc_status, EHOM);
for (byte i = 0 ; i < (ENC_JUDGE * 1.5) ; i++)
{
curr = ENC_PIN_READ();
prev = SBVAL(enc_status, EPRE);
// each gauge for "moved" or "not moved"
bool bias = (curr != dist) ? 1 : 0;
gauge [bias]++;
int goal = gauge[1] - gauge[0];
if (abs(gauge[1] - gauge[0]) > ENC_JUDGE)
{
// encoder moved!
if (goal > 0)
{
// increase or decrease
bool dir = ((curr - dist) > 0) ? 1 : 0;
if (curr == 0 && dist == 3) dir = 1;
else if (curr == 3 && dist == 0) dir = 0;
// add count by the direction
if (dir) enc_count++;
else enc_count--;
// update home position
enc_status = (enc_status & ~EHOM) + (curr << SBIT(EHOM));
enc_status = enc_status | ECHG;
}
for (byte i = 0 ; i < 2 ; i++) gauge[i] = 0;
enc_status = enc_status & ~ETRG;
break;
}
}
}
}
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(38400);
for (byte i = 0 ; i < 2 ; i++)
{
pinMode(enc_pins[i], INPUT_PULLUP);
pinMode(motor_pins[i], OUTPUT);
digitalWrite(LED, 1 - i);
delay(1000);
}
TIM::set(1, ENC_GAUGE);
TIM::start();
enc_status = ENC_PIN_READ() << SBIT(EHOM);
}
void loop() {
static int val;
static unsigned long time_move;
if (SBVAL(enc_status, ECHG)) // if encoder has changed
{
static int val_ref = val;
static bool dir_ref = 0;
digitalWrite(LED, HIGH);
// get encoder's increase or decrease
val = ENC_COUNT(val);
// move Motor
bool motor_dir = (val_ref > val) ? 1 : 0;
digitalWrite(motor_pins[!motor_dir], LOW);
digitalWrite(motor_pins[motor_dir], HIGH);
// refresh time value
if (millis() >= time_move) time_move = millis();
// if rotation has reversed
if (motor_dir != dir_ref)
{
time_move = millis() + REV_RAG; // add times for reversed idling
dir_ref = motor_dir; // update present direction
}
// set moving duration
time_move += MOVE_VAL * abs(val - val_ref);
// set present val to reference old
val_ref = val;
} else {
if (millis() > time_move) // set move action off
{
digitalWrite(LED, LOW);
for (byte i = 0 ; i < 2 ; i++) digitalWrite(motor_pins[i], LOW);
}
}
}
ちょっと長いですが、ほぼ、エンコーダ読み取り関係です(こちらのコードをまんま流用)。やっているのは、「ロータリーエンコーダの増減があれば、少し(10ms)その方向にモータを動かす」だけです。あまり早いと取りこぼしはありますが、それでも、かなり細かい動きが出来ます。
定数の詳細
スケッチ内の定数についていくつか補足しておきます。
#MOVE_VAL
モータの動く時間で、そのままms(ミリ秒)です。エンコーダの1目盛り分での動きをもっと細かくしたければ値を減らし、逆なら増やします。
#REV_RAG
使ったギヤボックスは遊びがあるので、回転方向が反転すると、その分だけ空回りします。それを補うため、回転が反転した場合、余分に動く秒数(ms)を設定しています。いらなければ0にします。
失敗のワケ
動きは良かったんですが、このギヤボックス、結構ガタや遊びがあって、大事なところで滑って空回りしてしまいます。要は剛性・トルク不足です。
使おうとしていたレンズ「SIGMA 30mm1.4F」はかなり年季が入っていて、フォーカスリングが硬いです。なので、この程度のトルクではうまく機能しませんでした。アルミフレーム工作の精度が低いからかも知れませんが。

ただ、リングが軽いレンズならそれなりに動いたので、場合によっては使えるな、と。あるいは、もっと負荷の低い、別の用途だったら充分機能するのでは、と思います。
参考サイト
panchiga’s blog – DCモーターを制御する





