USBで制御できるAC/DCのロードスイッチを作りました

No Image

そんなの既製品でいくらでもある...たしかにそれはそうなんです。
リレーをCOMポートからON/OFFできるモジュールなんていくらでもあります。
AliExpressやAmazonで安く売っています。
ただ、リレーのやつしかないんですよね...
FETやトライアックといった半導体で電源をON/OFFしたくて作ってしまいました。

スポンサーリンク

Amazonでも似たようなものは売ってるけど...

Amazonなどで売ってるモジュールはリレーをシリアル通信で制御できるものです。
よくあるUSBリレーモジュール
普通の用途であればこれで充分だと思います。
リレーじゃなくてロードスイッチやトライアックがいいんです...

制御にマイコンを使うのも面倒なので、FTDIのUSBシリアル変換ICのBitBangモードを使います。
今回はFT231Xを使いました。
FTDIのICはちょっと高めですが、ドライバのインストールが不要で資料も多くて作りやすいです。

回路図と基板実装

よくある回路でシンプルなので大したものではないです。
ACの方だけ載せておきます。
DCは P-ch MOSFET をフォトカプラで絶縁しただけのロードスイッチだから簡単ですよ。
USB制御ロードスイッチ

3分クッキングのように端折りますが、さくっと基板設計・発注をして実装したのがこちらです。
ACとDCのUSB制御ロードスイッチ
ACの方のバリスタはミスって一回り大きいモノになってしまいました。
DCの方はUSB-Aも取り付けられるような設計です。
負荷についているコンデンサはなんとなくです、なくてもいいです。

3Dプリンタでケースをつくる

ケースはタカチのような汎用品でもいいと思ったのですが、せっかくなので3Dプリンタで作りました。
中身
ケース外観
インサートナットを使った贅沢なケースです。
一昔前より苦労せずキレイに仕上がるのでだいぶ使いやすくなりました。
最近私の中で3Dプリンタへの興味が再燃しつつあります。

こういう小さいケースはパラメトリックに作れるようなモデルにしています。
ケースのモデル
高さや幅を指定するだけで簡単にケースが作れるのでおすすめです。

制御プログラム(Python)

シンプルなロードスイッチですが、USBでIOを制御するところをどうするかが肝です。
最初はCH341AというWCHのチップも候補に挙がっていましたが資料が少なくて諦めました。
PyFtdiというライブラリがあってこれが非常に便利なのでプログラムはPythonで書きます。

ただ、PyFtdiはWindowsの標準ドライバでは制御できないようです。
Zadigなどのツールを使用して標準ドライバをlibusb互換のドライバに置き換える必要があります。
これはちょっと面倒だと感じました。
そこで、Windowsでも標準ドライバで簡単に使えるPyFtdiWinというライブラリを使います。

PyFtdiWinはPyFtdiからフォークされたライブラリですので使い方はほとんど同じです。(更新がなく古そうですが...)
IO制御のところは特定の1ピンしか使わないので、これ以上の汎用性を今のところは考えていません。

デバイスのURLみたいな記述が必要なのですが、シリアルナンバーなどが入っているのでそれを調べて直書きするのは面倒です。
そこで、PIDなどから紐づけてURLを生成してCOMポートの番号を指定すれば実行できるようにしています。
そのため、プログラムがちょっと長めになってしまいました。

import sys
import re
import serial.tools.list_ports
from pyftdi.ftdi import Ftdi
from pyftdi.gpio import GpioAsyncController

# Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
#  RI  DCD  DSR  DTR  CTS  RTS  RXD  TXD
control_bit = 0b00000010

#コマンドライン引数を取得(COM, 0 or 1)
if len(sys.argv) < 3:
  print("Usage: python bitbang_control.py <COM_PORT> <0|1>")
  sys.exit(1)
com_name = sys.argv[1]
io_state = sys.argv[2]

# COMポートと FTDI URL の対応表を格納する辞書
com_to_ftdi_map = {}

# FTDIのPIDに基づくURLのプレフィックスを設定
ftdi_chip_prefix = {
  0x6001: "ftdi://ftdi:232",   # FT232R
  0x6010: "ftdi://ftdi:2232",  # FT2232
  0x6015: "ftdi://ftdi:ft-x",  # FT230X,FT231X
  # 他のFTDI チップがあればここに追加
}

# COMポートのリストを取得
ports = list(serial.tools.list_ports.comports())

for port in ports:
  if "FTDI" in port.manufacturer:  # FTDIデバイスを特定
    hwid_parts = port.hwid.split(" ")
    serial_number = None
    pid = None

    for part in hwid_parts:
      if "PID=" in part:
        pid = int(part.split(":")[-1], 16)  # 16進数で取得
      if part.startswith("SER="):  # シリアル番号の部分を探す
        serial_number = part.split("=")[1]

    if serial_number and pid:
      # PID に基づいて URL プレフィックスを選択
      ftdi_prefix = ftdi_chip_prefix.get(pid, "ftdi://ftdi:unknown")
      # シリアル番号の末尾が英字なら削除
      serial_number = re.sub(r'[A-Za-z]$', '', serial_number)
      ftdi_url = f"{ftdi_prefix}:{serial_number}/1" # URLを作成
      com_to_ftdi_map[port.device] = ftdi_url # 辞書に保存

# 結果を表示
for com_port, ftdi_url in com_to_ftdi_map.items():
  print(f"COM Port: {com_port} -> FTDI URL: {ftdi_url}")

# FTDIデバイスを検出(念の為確認)
print(Ftdi.show_devices())

#コマンドライン引数(COMポート番号)から該当のURLを取得
if com_name in com_to_ftdi_map:
  gpio = GpioAsyncController()
  gpio.configure(com_to_ftdi_map[com_name], direction=control_bit)
  if io_state == "0":
    # GPIOのLOWにする
    gpio.write(control_bit)
  elif io_state == "1":
    # GPIOのHIGHにする
    gpio.write(0b00000000)
  else:
    print("Invalid argument. Use 0 or 1.")
else:
  print(f"No FTDI device found for {com_name}")

このソースコードを保存して、bitbang-control.py みたいなファイルにするとコマンドプロンプトで下記の形式で実行します。

python bitbang_control.py <COM_PORT> <0|1>

スポンサーリンク

実例としては、たとえばCOM1に接続したモジュールで"ON"(1)にするのであれば下記のような記述です。

python bitbang_control.py COM1 1

使いどころは?

で、結局こんなものを作って何をしたいかというと、PCに接続されているオーディオ機器の電源のON/OFFを制御したいのです。
たとえばイヤホン出力には自作のNutubeのヘッドホンアンプがつながっています。
改良型バスパワー式Nutubeヘッドホンアンプ

ずっと電源を入れっぱなしはいかがなものかということでUSBケーブルを抜いて電源を切っていますが、もっとスマートにON/OFFの制御をしたいなと思ったのがきっかけです。
だったらスピーカーも...ということで電源がACのスピーカーも制御しちゃおうという流れです。
スピーカーをリレーで電源投入するとポップノイズが発生します。
ゼロクロスのトライアックであればノイズが発生せず快適なのです。

Windowsの再生デバイスの切り替えはAutoHotKeyを使っていますので、切り替えの際のPythonのスクリプトを実行する部分を書き足します。

全部Pythonで書いてもいいのですが、すでにAHKを使っているので...

Run(A_ComSpec ' /c python "C:\...\bitbang-control.py" COM1 1', , "Hide")

C:\...\ の部分はPythonスクリプトを置いているフォルダのフルパスなので適宜設定します。


超シンプルなモジュールですが、電子機器のスマート化と省エネに貢献できるデバイスだと思います。
今どきであればWi-Fi対応で無線制御もありますが、そこまで大げさなものではないんですよね...
既製品で普通に売ってそうで売ってないので、AliExpressとかで似たようなものを売ってくれないかなと期待しています。

USBで制御できるAC/DCのロードスイッチを作りました

スポンサーリンク

Leave a Comment