前回の記事「ロクハン パワーパックで DCCスロットルの製作1」の続きです。
ロクハン製パワーパック「トレインコントローラー RC-03」に接続するケーブルのコネクタは下記の品番になります。
コネクタ | ケーブル側プラグハウジング | コンタクト |
---|---|---|
ACアダプタ用 | 汎用DCプラグ φ5.5x2.1mm | - |
フィーダー用 及びアクセサリー用 |
JST ELP-02V (ELコネクタ) |
JST SLF-01T-P1.3E (AWG #26-#20) |
ポイント用 | TE 172336-1 or 172165-1 (Mini-Universal MATE-N-LOK Connectors) |
TE 170365-1 (AWG #26-#22) |
電子部品屋の店舗で、赤黒ケーブル付JST製ELコネクタと、TE製ミニユニバーサル・メイテンロックコネクタのハウジングとコンタクトのバラ品が偶然売っていましたので、ケーブルを半分に切ってメイテンロックコネクタのコンタクトに半田付けしてポイント用のケーブル付コネクタを作りました。
(なので必要以上に太い線になってしまいました)
マイコンボードは「Raspberry Pi Pico W」を使用しました。
パワーパックからのアクセサリ出力は 5V LDOと逆流防止用ダイオードを通してラズパイピコの電源入力に接続し、アウトプット出力は分圧兼 RCフィルタを通して A/D入力ポートに接続し、ポイント切替出力は抵抗内蔵トランジスタを通してデジタル入力ポートに接続しました。
また、線路電源ON/OFF用のタクトスイッチ1個と、DCC車両のファンクション制御用のタクトスイッチ4個も接続しました。
配線図
部品表
記号 | 部品名 | 部品品番 | 備考 |
---|---|---|---|
MCU | マイコンボード | Raspberry Pi Pico W | |
SW | タクトスイッチ | SKRGAQD010 | |
Q1,Q2 | 抵抗内蔵型トランジスタ | DTC124ESA | |
VD1,VD2 | 定電圧ダイオード | 1N5231B | Vz=5.1V |
LDO | 定電圧レギュレータ | UPC78N05H-AZ | Vin=Max35V , Vout=5V/300mA |
D1 | ダイオード | 1N4148 | Io=200mA |
C1,C2,C3,C4 | 積層セラミックコンデンサ | 1uF 50V | |
R1,R2 | 抵抗器 | 1 kohm 1% | |
R3,R4 | 抵抗器 | 220 ohm 1% |
他の角度から撮った写真
ファームウェアは「CircuitPython」を使い、スクリプトを作りました。
このようなマイコンボードのファーム開発では、車両やアクセサリの操作であったり Wi-Fi制御などの主目的の部分はやる気が出るのですが、車両やアクセサリの DCCアドレスを指定するなどの付随的なユーザーインターフェイスの部分はなかなか作り込む気が出ません。
その点 CircuitPythonでは、メモ帳でスクリプトファイルを修正して CIRCUITPYドライブ(USBストレージ)にファイルコピーするだけで更新ができますので、スクリプトファイルに直接 DCCアドレスを記入しても手間なく修正と更新ができ、付随的なユーザーインターフェイスを作り込む必要がありません。
以下、作成したスクリプトファイルです。
ライブラリは asyncio、adafruit_ticks、adafruit_requests を使用しますが、adafruit_requests については async/await 対応するために一部修正しています。
[\code.py]
# --------------------------------------------------------------------------------------
# DCC WiFi Throttle Adapter for DSair Wi-Fi Specification with Raspberry Pi Pico W
#
# Raspberry Pi Pico W
# https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html
#
# CircuitPython
# https://circuitpython.org/board/raspberry_pi_pico_w/
# adafruit-circuitpython-raspberry_pi_pico_w-en_US-8.*.*.uf2
#
# CircuitPython Libraries
# https://circuitpython.org/libraries
# adafruit-circuitpython-bundle-8.x-mpy-********.zip
# lib/asyncio
# lib/adafruit_ticks.mpy
# adafruit-circuitpython-bundle-py-********.zip
# lib/adafruit_requests.py (mod)
#
# DSair Wi-Fi Specification
# https://desktopstation.net/wiki/doku.php/dsair_wifi_specification
#
# Send Command
# http://flashair/command.cgi?op=131&ADDR=0&LEN=64&DATA=DSairCommand
# Function Command Parameters
# Power PW(PowerFlag) PowerFlag OFF=0, ON=1
# Direction DI(LocoAddr,Direction) LocoAddr 0-9999=49152(0xC000)-59151(0xE70F)
# Direction FWD=1, REV=2
# Function FN(LocoAddr,FuncNo,FuncVal) FuncNo F0-F28=0-28 / FuncVal OFF=0, ON=1
# LocSpeed SP(LocoAddr,Speed,Speedstep) Speed 0%-100%=0-1023, Speedstep 128Step=2
# Turnout TO(AccAddr,AccDirection) AccAddr 1-2044=14336(0x3800)-16380(0x3FFC)
# AccDirection DIV=0, STR=1
# Read Status
# http://flashair/command.cgi?op=130&ADDR=128&LEN=264
# IndexByte Size Parameter Definition
# 0 1 Rail Power ON="Y", OFF="N"
# 8-10 3 Rail Voltage 120=12.0V
# 12-13 2 Output Current 10=1.0A
#
# --------------------------------------------------------------------------------------
import time
import board
import digitalio
import analogio
import wifi
import socketpool
import asyncio
import adafruit_requests
WIFI_SSID = "FlashAir"
WIFI_PASSWORD = "12345678"
LOC_ADDRESS = 3
LOC_FUNCTION = [0, 1, 2, 3]
ACC_ADDRESS = [3, 4]
PIN_LOW = [board.GP9, board.GP10]
PIN_POWER = board.GP0
PIN_FUNCTION = [board.GP4, board.GP7, board.GP12, board.GP15]
PIN_TURNOUT = [board.GP17, board.GP21]
URL_SEND_COMMAND = "http://flashair/command.cgi?op=131&ADDR=0&LEN=64&DATA="
URL_READ_STATUS = "http://flashair/command.cgi?op=130&ADDR=128&LEN=264"
# --------------------------------------------------------------------------------------
print()
print("DCC WiFi Throttle Adapter for DSair")
air_command = []
air_status = ""
class PortInput:
pin = None
value = False
def __init__(self, pin):
self.pin = digitalio.DigitalInOut(pin)
self.pin.direction = digitalio.Direction.INPUT
self.pin.pull = digitalio.Pull.UP
def state(self):
value = self.pin.value
state = 0
if value != self.value:
state = 1 if not value else -1
self.value = value
return state
async def led_task():
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
while True:
led.value = not led.value
await asyncio.sleep(0.1)
async def wifi_task():
global air_status
pool = socketpool.SocketPool(wifi.radio)
request = adafruit_requests.Session(pool)
last = 0
while True:
await asyncio.sleep(0.1)
if not wifi.radio.connected:
if (time.monotonic() - last) >= 5:
try:
print("Connecting to WiFi AP:", WIFI_SSID)
wifi.radio.connect(WIFI_SSID, WIFI_PASSWORD)
print(" Connected. My IP address:", wifi.radio.ipv4_address)
except Exception as e:
print(f"! {type(e).__name__}: {e}")
last = time.monotonic()
else:
if (time.monotonic() - last) >= 5:
try:
url = URL_READ_STATUS
with await request.get(url, timeout=3) as response:
if response.status_code == 200:
air_status = response.text
print("DSair Status:", air_status)
except Exception as e:
print(f"! {type(e).__name__}: {e}")
last = time.monotonic()
if len(air_command) > 0:
try:
url = URL_SEND_COMMAND + (command := air_command.pop(0))
with await request.get(url, timeout=3) as response:
if response.status_code == 200:
command = command + " -> " + response.text
print("DSair Command:", command)
except Exception as e:
print(f"! {type(e).__name__}: {e}")
async def operation_task():
for pin in PIN_LOW:
low = digitalio.DigitalInOut(pin)
low.direction = digitalio.Direction.OUTPUT
low.value = False
adc1 = analogio.AnalogIn(board.A1)
adc2 = analogio.AnalogIn(board.A2)
st_power = PortInput(PIN_POWER)
st_function = [[PortInput(pin), False] for pin in PIN_FUNCTION]
st_turnout = [PortInput(pin) for pin in PIN_TURNOUT]
last = 0
while True:
await asyncio.sleep(0)
if (st_power.state() == 1) and (len(air_status) > 0):
if air_status[0] != "Y":
air_command.append("PW(1)")
else:
air_command.append("PW(0)")
for i, st in enumerate(st_function):
if st[0].state() == 1:
st[1] = not st[1]
LocoAddr = 0xC000 + LOC_ADDRESS
FuncNo = LOC_FUNCTION[i]
FuncVal = int(st[1])
air_command.append(f"FN({LocoAddr},{FuncNo},{FuncVal})")
for i, st in enumerate(st_turnout):
if state := st.state():
AccAddr = 0x3800 + ACC_ADDRESS[i] - 1
AccDirection = 1 if state == 1 else 0
air_command.append(f"TO({AccAddr},{AccDirection})")
if (time.monotonic() - last) >= 1:
print(
"{:.3f}".format(adc1.value * 3.3 / 65536),
"{:.3f}".format(adc2.value * 3.3 / 65536),
)
last = time.monotonic()
async def main():
await asyncio.gather(led_task(), wifi_task(), operation_task())
asyncio.run(main())
[\lib\adafruit_requests.py]
左側がオリジナルで、右側は変更後です。
このスクリプトで、パワーパックのポイント切替スイッチによるポイント制御、及びラズパイピコのタクトスイッチによる線路電源のON/OFF制御や車両のファンクション制御(4つ) については対応できました。
その後、車両のスピードコントロール機能について作ろうとしたところ、パワーパックのつまみを回してもアウトプット出力から波形が現れなくなってしまい、壊してしまったかもしれない状態になってしまいました。
ということで、これ以上 作ることができなくなってしまいました。
残念ですが、以上です。