目次

  1. はじめに
  2. 必要なもの
  3. 配線図
  4. ソースコード
  5. まとめ

はじめに

今回は、PATLITEが提供する製品である積層信号灯(パトランプ)をRaspberry Pi Pico W(以降picoW)で制御してみようと思います。

LR5 積層信号灯(Φ50)シグナル・タワー(R) - 株式会社パトライト
パトライトの豊富な積層情報表示灯、積層信号灯をご紹介。視認性が高く、様々なシーンで安心安全にご使用いただけます。LED・省電力・メンテナンスフリー・耐熱・耐衝撃・ユニット・脱着タイプ・防塵・防噴流・工具不用・壁面取付】

調べてみると、データの送受信用の拡張アタッチメントのようなものも販売されていて面白いですが、今回はシンプルな3色のライトを使用していきます。

必要なもの

  • パトライト(型番:LR5-_01PJN)
  • 12V ACアダプタ
  • Raspberry Pi Pico W
  • Nch MOSFET(12v以上の耐圧があるもの) × 3
  • 抵抗(10kΩ×3)
  • ジャンパワイヤ

配線図

パトライトの配線については製品ページの取扱説明書を見ると書かれているのでそれを参考にします。

参考www.patlite.co.jp/catalogimg/JP_KF_000628_DTCmFfu4.pdf

パトライトからはこのような線が出ています。

今回使用するのは「赤、緑、橙、黄、灰」色の5つの線です。

「茶」は点滅用と取扱説明書には書かれていますが、使い方がいまいちわからないので、今回は省きます。

それ以外の線として「白、青」が、別売りの追加ランプ用と、「紫」は型番によってブザーがついているようなので、その制御用です。使用する型番の製品では使えない線になります。

ソースコード

auth_info.py

SSID = "WiFiのSSID"
PASSWORD = "WiFiのパスワード"
STATIC_IP = "192.168.*.***"
GATEWAY = "192.168.*.1"

WiFiやIPアドレス周りの設定は個人の環境に合わせてください。

index.html

<!DOCTYPE html>

<html>

<head>
    <style>
        body {
            text-align: center;
        }

        table {
            margin: 0 auto;
            border-spacing: 50px 50px;
        }

        input[type=range] {
            width: 100%;
        }
    </style>
    <script>
        function updateQueryString(color) {
            var sliderValue = document.getElementById(color).value;

            // 現在のURLを取得
            var currentUrl = window.location.href;

            // URLから既存のクエリストリングを削除
            var urlWithoutQueryString = currentUrl.split('?')[0];

            // 新しいクエリストリングを追加
            var newUrl = urlWithoutQueryString + "?ledColor=" + color + "&" + "sliderValue=" + sliderValue;

            // APIを叩く
            fetch(newUrl);
        }
    </script>
</head>


<body>
    <table>
        <tr>
            <th>red</th>
            <th>yellow</th>
            <th>green</th>
        </tr>
        <tr>
            <th>
                <input type="range" id="red" value="0" min="0" max="65536" onchange="updateQueryString('red')">
            </th>
            <th>
                <input type="range" id="yellow" value="0" min="0" max="65536" onchange="updateQueryString('yellow')">
            </th>
            <th>
                <input type="range" id="green" value="0" min="0" max="65536" onchange="updateQueryString('green')">
            </th>
        </tr>
    </table>
</body>

</html>

main.py

from machine import PWM
from machine import Pin
from time import sleep
import auth_info
import network
import socket


def connect():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(auth_info.SSID, auth_info.PASSWORD)
    while wlan.isconnected() == False:
        print("Waiting for connection...")
        sleep(1)
    wlan.ifconfig((auth_info.STATIC_IP, "255.255.255.0", auth_info.GATEWAY, "8.8.8.8"))
    print(wlan.ifconfig())


def open_socket():
    addr = socket.getaddrinfo("0.0.0.0", 80)[0][-1]
    skt = socket.socket()
    skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    skt.bind(addr)
    skt.listen(1)
    return skt


def parse_query_string(query):
    params = {}
    pairs = query.split("&")
    for pair in pairs:
        if "=" in pair:
            key, value = pair.split("=", 1)
            params[key] = value
    return params


def is_end_of_line(line: bytes):
    return not line or line == b"\r\n"


def cut_out_query_string(line: bytes):
    if line.startswith(b"GET /?"):
        request_line = line.decode()
        return request_line.split(" ")[1].split("?", 1)[1]
    return ""


def get_query_strings(cl_file: socket.SocketIO):
    query_params = {}
    while True:
        line = cl_file.readline()
        if is_end_of_line(line):
            break
        query_string = cut_out_query_string(line)
        query_params.update(parse_query_string(query_string))
    return query_params


color_by_pin_num = {
    "red": 22,
    "yellow": 21,
    "green": 16,
}


def run_by_query(query_params):
    if query_params != {}:
        try:
            led_color = query_params["ledColor"]
            duty = int(query_params["sliderValue"])
            pwm_set(color_by_pin_num[led_color], 1000, duty)
        except Exception as e:
            # 特定のキーがなかった場合の握りつぶし
            print(e)
        return True
    else:
        return False


def pwm_set(pin_num, freq, duty):
    pwm_pin = PWM(Pin(pin_num, Pin.OUT))
    pwm_pin.freq(freq)
    pwm_pin.duty_u16(duty)


skt = None
try:
    connect()
    skt = open_socket()
except Exception as e:
    # ネットワーク関連のエラーが出たら再起動
    print(e)
    machine.reset()

while True:
    try:
        cl, addr = skt.accept()
        cl_file = cl.makefile("rwb", 0)
        query_params = get_query_strings(cl_file)
        is_api_request = run_by_query(query_params)
        contents = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
        cl.send(contents)
        if not is_api_request:
            f = open("./index.html")
            cl.send(f"{f.read()}\r\n\r\n")
        cl.close()
    except Exception as e:
        # コネクション系の処理でエラーが出たらcloseするようにする
        print(e)
        cl.close()

主にMicroPythonのsocketモジュールを使って、ブラウザ用の画面とAPIサーバをを兼用している構成になります。

ブラウザから、STATIC_IPで設定したIPアドレスにアクセスすると3つのスライドバーが画面に出てくると思います。

ブラウザ側のスライドバーが更新されたら、APIを叩くことによってスライドバーと対応した色のライトが値に応じて明るさが変わります。

スライドバーの更新イベントをoninputにして、値が少しでも変わったらAPIを叩くようにすれば、もっと滑らかな輝度の変化になりますが、Pico Wの処理能力なども考慮して、スライドバーの位置が確定した時に発火するonchangeを使っています。

まとめ

今回は、既製品であるパトランプをRaspberry Pi Pico Wを使って輝度の変更を行ってみました。
PWMの設定などはArduinoとは違い、若干面倒なところはありましたが、MicroPythonでの記述のため、人によってはコーディングが楽な印象を受けました。
その一方で、APIを叩いた時のレスポンスが若干遅いように感じたため、用途や実装面で若干の制限がありそうです。
実装方法によるものかもしれませんが、今回はこれぐらいで終わりにします。

Raspberry Pi Pico Wでパトライト(PATLITE)を制御する