序文
工場出荷時の予定された振動モードにうんざりして、自分でマイコンを使用しておもちゃを制御できないかと考え、この記事を書くことになりました。
モーターの駆動方法
実際には、すべての振動おもちゃ、例えばバイブや振動スティックなど、その中核は直流モーターです。したがって、この記事の焦点は、おもちゃの組み込みリモコンを模倣するためのマイコンの使用方法にあります。まず、電圧を測定するために万能計を使用してみましたが、アナログバーをシミュレートするために、これはPWM制御による調速であることが分かりました。そして、オシロスコープを使用して分析を行い、電圧、デューティ比、および周波数を得ました。実際には、電圧と周波数が重要なパラメータであり、デューティ比は参考値です。実際に変更する必要があるのはデューティ比であり、これを制御することで振動の強さを調整できます。
ここで6Vの電圧が必要であることに私も少し驚きました。通常、マイコンの駆動にはUSBの5V電圧が使用されますが、ここでは6Vが必要です。とりあえずこの問題を無視して、モーターがそれに耐えられることを期待しましたが、実際には耐えられませんでした。その後、ドライブ回路を用意し、最初にMOSFETを試してみましたが、ブレッドボード上で組み立てて電源を供給しました。しかし、MOSFETはパワー型でTOパッケージのため、寄生容量が大きく、遠隔制御のコントローラーのような完璧な方形波を生成することはできませんでした(プルダウン抵抗も試しましたが、同様の結果でした)。さらに、実際のテストでは5V電圧でも私のおもちゃを完全に駆動することができませんでした。そのため、最初の試みはここで一時停止しました。
Hブリッジとブースト回路
上記の問題をまとめると、一方面は駆動回路の問題、もう一方は電圧の問題です。実際の解決策は比較的簡単で、Hブリッジとブースト回路を使用することです。Hブリッジは、モーター制御用に特別に設計された回路で、正転と逆転をサポートします。一方、ブースト回路はDIYコミュニティで早くから人気のあるDC-DC昇圧回路(降圧バージョンや昇降圧バージョンもあります)です。私たちは昇圧のみを必要としているため、昇圧回路モジュールを購入することにしました。
要件を確定した後、チップの選択肢を検討し始めました。DIY愛好家にとって、選択肢は多くありません。成熟した、豊富な供給源がある、低価格の単一チップを検討するしかありませんでした。秋月電子でいくつかの検索を行った後、私は大まかなアイデアを持つことができました。その中で、Hブリッジチップとして東芝のTC78H653FTGを選びました。各種のパラメータが要件に合致し、またデュアルHブリッジを統合したチップで、1つのICで対の2つの振動モーターを制御することができます。それから、対応する回路ボードが秋月電子で直接購入可能でした。そして、昇圧回路については、私はルネサスのISL97519Aを選びました。各種のパラメータも要件に合致しており、秋月電子でも対応する回路ボードモジュールが販売されていました。
再度の試み
必要な部品を用意した後、再度試してみました。ま
ず、昇圧回路を使用して出力電圧を6Vに調整し、それをブレッドボードに接続しました。その後、データシートの要求に従ってHブリッジを接続しました。ESPHomeでHブリッジに対応する4つのピン(各モーター2つのピン)を設定しました。ただし、HブリッジICのENピンは浮遊させることはできず、VCCに接続する必要があります。以下に、参考までに私が設定したYAMLファイルを示します:
esphome:
name: esp8266-vibe
friendly_name: esp8266-vibe
esp8266:
board: esp01_1m
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
output:
- platform: esp8266_pwm
pin: GPIO4
frequency: 100 Hz
id: motor1_reverse_pin
- platform: esp8266_pwm
pin: GPIO0
frequency: 100 Hz
id: motor1_forward_pin
- platform: esp8266_pwm
pin: GPIO5
frequency: 100 Hz
id: motor2_forward_pin
- platform: esp8266_pwm
pin: GPIO16
frequency: 100 Hz
id: motor2_reverse_pin
fan:
- platform: hbridge
id: "motor1"
name: "motor1"
pin_a: motor1_forward_pin
pin_b: motor1_reverse_pin
decay_mode: slow
on_speed_set:
- globals.set:
id: motor1_speed
value: !lambda 'return id(motor1).speed;'
- platform: hbridge
id: "motor2"
name: "motor2"
pin_a: motor2_forward_pin
pin_b: motor2_reverse_pin
decay_mode: slow
on_speed_set:
- globals.set:
id: motor2_speed
value: !lambda 'return id(motor2).speed;'
globals:
- id: motor1_speed
type: int
restore_value: no
initial_value: '0'
- id: motor2_speed
type: int
restore_value: no
initial_value: '0'
- id: u_turn_mode
type: bool
restore_value: no
initial_value: 'false'
- id: dot_mode
type: bool
restore_value: no
initial_value: 'false'
script:
- id: "u_turn"
then:
- while:
condition:
lambda: 'return id(u_turn_mode);'
then:
- fan.turn_on:
id: motor1
speed: !lambda 'return id(motor1_speed);'
direction: forward
- fan.turn_on:
id: motor2
speed: !lambda 'return id(motor2_speed);'
direction: forward
- delay: 1s
- fan.turn_on:
id: motor1
speed: !lambda 'return id(motor1_speed);'
direction: reverse
- fan.turn_on:
id: motor2
speed: !lambda 'return id(motor2_speed);'
direction: reverse
- delay: 1s
- id: "dot"
then:
- while:
condition:
lambda: 'return id(dot_mode);'
then:
- fan.turn_on:
id: motor1
speed: !lambda 'return id(motor1_speed);'
direction: forward
- fan.turn_on:
id: motor2
speed: !lambda 'return id(motor2_speed);'
direction: forward
- delay: 250ms
- fan.turn_off: motor1
- fan.turn_off: motor2
- delay: 70ms
switch:
- platform: template
name: "u_turn_mode_switch"
id: "u_turn_mode_switch"
lambda: |-
if (id(u_turn_mode)) {
return true;
} else {
return false;
}
turn_on_action:
- switch.turn_off: dot_mode_switch
- globals.set:
id: u_turn_mode
value: 'true'
- script.execute: u_turn
turn_off_action:
- globals.set:
id: u_turn_mode
value: 'false'
- script.stop: u_turn
- fan.turn_off: motor1
- fan.turn_off: motor2
- platform: template
name: "dot_mode_switch"
id: "dot_mode_switch"
lambda: |-
if (id(dot_mode)) {
return true;
} else {
return false;
}
turn_on_action:
- switch.turn_off: u_turn_mode_switch
- globals.set:
id: dot_mode
value: 'true'
- script.execute: dot
turn_off_action:
- globals.set:
id: dot_mode
value: 'false'
- script.stop: dot
- fan.turn_off: motor1
- fan.turn_off: motor2
おそらくお気づきかもしれませんが、今回は通常のesp32ではなく、esp8266を使用しています。これは、手元にあるesp32が公式のdevkitバージョンで、VUSBピンが引き出されていないためです。一方、esp8266はNodeMCUバージョンで、VUSBピンが利用可能であるため、電源効率を最大化するためにesp8266を選択しました。また、"script"セクションでは、"回転モード"と"ドットモード"の2つの振動モードを記述しています。将来的にはさらに多くのモードを追加する予定であり、XToysコミュニティなどの提供する振動モードも参考にする予定です。
結果
最後に、電源を供給してテストし、予想通りの結果を得ました。PWMの方形波は非常に完璧で、モーターは安定して稼働し、以前の電圧不足による速度低下や不安定な波形による異音は発生しませんでした。全体的に、私にとってはこのDIYプロジェクトは、ソフトウェアエンジニアとしてハードウェアに足を踏み入れる最初のステップとしては順調だったと言えるでしょう。目的を持って学習し、簡単な勉強だけでこのようなDIYができることを見ると、非常に達成感があります。