前回の記事「ロクハン パワーパックで 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つ) については対応できました。

 

その後、車両のスピードコントロール機能について作ろうとしたところ、パワーパックのつまみを回してもアウトプット出力から波形が現れなくなってしまい、壊してしまったかもしれない状態になってしまいました。

 

ということで、これ以上 作ることができなくなってしまいました。

 

残念ですが、以上です。