無線マイコン TWELITE トワイライトをRaspberry Pi 4Bで動かしてみた。


###はじめに
単三電池２本で野外で安く通信ができる方法を探していたところ、TWELITEを見つけたのでAmazonで買って、使い方を調べてみました。その時ためした機能を、ここにまとめておきます。内容はすごく簡単で基礎的な機能の確認なので、なるべく電子工作初心者やこれから始めようと考えている人たちにもわかりやすく書くように心がけました。

###用意したもの
- 超簡単! 無線マイコンモジュール TWELITE DIP-トワイライトディップシリーズ マッチ棒アンテナ ピンヘッダ端子実装
- モノワイヤレス USBスティック MONOSTICK-モノスティック レッド
本日、アマゾンを調べたところセット買いなるものが出ていたのでそれを選択しても良いと思います。私の場合、子機にTWEILITEのブルーを選んで、親機にUSBスティックのレッドを選びました。レッドとブルーでも出力の違いはありますが、部屋の中では問題なく通信ができました。

###やること
1. リモートのLチカ
Raspberry Piから無線を通して、遠隔のTWELITEのLEDのON/OFFをする。
2. PWMでLEDの高度を調整
Raspberry Piから無線を通して、遠隔のTWELITEのLEDの明るさを変更する。
3. スイッチのON/OFFを受け取る
遠隔のTWELITEからのスイッチのON/OFFを、Raspberry Piで受け取る。

この３つをやってみます。

###ブレッドボード
すべての部品は自宅に余っていたものを使ったので、部品についての詳細な説明は割愛させていただきます。抵抗は１KΩを使いました。電池は単三電池２本です。
![TWELITE_Sketch_ブレッドボード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/f939fb7e-3796-934c-5b27-29397710e645.jpeg)
実際のブレッドボードになります。
![DSC_0091.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/f542d421-d701-5f4f-55ca-a66bbc20351b.jpeg)

###親機
親機としてRaspberry Piにモノワイヤレス USBスティックを挿入します。
![DSC_0098.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/dc51e123-c3ae-a421-9680-0533d37cc1ef.jpeg)

差し込んだらlsコマンドでデバイスファイルが正常に作成されているか、確認します。

```shell-session
 ls -l /dev/serial/by-id
```

lsコマンドの結果はこんな感じになります。
![ttyUSB0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/438a2aeb-e0fd-3cdb-6a0e-4abaa30a1f92.jpeg)

###Linux screenコマンドのインストール

以下のコマンドでLinux screenをインストールできます。使い方については、他に沢山の良い記事があるのでそちらを参照してください。

```shell-session
sudo apt update
sudo apt install screen
```

###screenコマンドでUSBデバイスにアクセスする
ポイントは、メッセージの最後にCRLFが必要になるのでonlcrのオプションがないと動かないことです。終了はCtrl + A、'\'でyes/noのプロンプトが出てくるのでyesを選んで終了できます。

```shell-session
screen /dev/ttyUSB0 115200 onlcr
```

![screen_result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/853bac8e-3b1a-28b2-5b9d-625fb9492cf0.jpeg)

###PythonでUSBデバイスにアクセスする

[Sample Video](https://www.youtube.com/watch?v=KLN7W0rbD2E)

```python
#!/usr/bin/python

import serial
import time
import argparse
import threading


def append_checksum(m):
    x = 0
    for i in range(1, len(m), 2):
        i = int(m[i:i+2], base=16)
        x = (x + i) % 256

    return "{:02X}".format(256 - x)

def main():
    parser = argparse.ArgumentParser(description='parser')
    parser.add_argument('--serial', dest='serial', type=str, default='/dev/ttyUSB0')
    parser.add_argument('--baudrate', dest='baudrate', type=int, default=115200)
    parser.add_argument('--timeout', dest='timeout', type=int, default=10)
    parser.add_argument('--receiver', dest='receiver', type=str, default="78")
    args = parser.parse_args()

    ser = serial.Serial(args.serial, args.baudrate)

    global last_msg, stop_read_msg
    stop_read_msg = False

    def read_msg():
        global last_msg, stop_read_msg
        while(not stop_read_msg):
            last_msg = ser.readline()
        print("read_msg thread end...")

    reader = threading.Thread(target=read_msg)
    reader.start()

    rcvr = args.receiver
    cmd  = "80"
    ver  = "01"

    io   = 0x00

    pwm1 = 0
    pwm2 = 0
    pwm3 = 0
    pwm4 = 0

    while(1):
        resp = raw_input("command?: ")

        resp = resp.lower().split()

        if(len(resp) < 1):
            continue

        if(resp[0] in ['q','quit','exit']):
            stop_read_msg = True
            ser.cancel_read()
            break

        if(resp[0] in ['r', 'read']):
            print("read:{}".format(last_msg))
            continue

        if(len(resp) < 2):
            print("value is missing!")
            continue

        mask = 0x00
        msg = ""
        if(resp[0] in ['led1', 'l1']):
            mask = 0b00000001
            if(resp[1] == '0'):
                io &= 0b11111110
            else:
                io |= 0b00000001

        if(resp[0] in ['led2', 'l2']):
            mask = 0b00000010
            if(resp[1] == '0'):
                io &= 0b11111101
            else:
                io |= 0b00000010

        if(resp[0] in ['led3', 'l3']):
            mask &= 0b00000100
            if(resp[1] == '0'):
                io &= 0b11111011
            else:
                io |= 0b00000100

        if(resp[0] in ['led4', 'l4']):
            mask &= 0b00001000
            if(resp[1] == '0'):
                io &= 0b11110111
            else:
                io |= 0b00001000

        if(resp[0] in ['pwm1', 'p1']):
            pwm1 = int(resp[1])

        if(resp[0] in ['pwm2', 'p2']):
            pwm2 = int(resp[1])

        if(resp[0] in ['pwm3', 'p3']):
            pwm3 = int(resp[1])

        if(resp[0] in ['pwm4', 'p4']):
            pwm4 = int(resp[1])

        msg = ":"
        msg += rcvr # Receiver
        msg += cmd  # command
        msg += ver  # version
        msg += "{:02X}".format(io)
        msg += "{:02X}".format(mask)
        msg += "{:04X}".format(pwm1)
        msg += "{:04X}".format(pwm2)
        msg += "{:04X}".format(pwm3)
        msg += "{:04X}".format(pwm4)
        msg += append_checksum(msg)
        msg += "\r\n"

        print("msg:{}".format(msg))

        ser.write(msg)

    print("stop:{}".format(stop_read_msg))
    reader.join()
    print("finish!")

if __name__ == "__main__":
    main()

```


###ボタンを押す
ボタンを押すと以下の部分が、ボタンを押すと１，ボタンを離すと０に変化します。

![button_on_off.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1615141/ba0b9dba-15ed-10e0-1fbc-ac2a82be638e.jpeg)


###終わりに
TWELITEのマイコンのプログラムを書き換えずに、ここまで出来ました。Lチカの機能を拡張することで、電源のON/OFFをコントロールしたり、PWMを使ってモーターの回転をコントロールしたり、ライトの明るさの強弱をコントロールすることができます。また、スイッチの機能を拡張すると、遠隔からドアの開閉をRaspberry Piで受け取ることもできます。