何回かに分けてTWE-Liteファームウェア開発について触れたいと考えております。
今回作成した物
最下段のサンプルにて親機から 0.5秒毎に全てのLED On/Offを要求しているのですが、通信のタイミングや処理速度の関係で全く上手く行かない...
最終的に実施したい事
- 親機1台/子機30台位で動作させる
- USB電源を接続したまま動作するハードウェアを作成する (スリープ等は要件に含まない)
- 子機のスイッチを押す度に自分の状態を示すLEDの色が変更される
- 子機のスイッチ状態が変化した事を親機に通知する
- 親機である ToCoStick on Raspberry Pi で何かの時間やWebAPI等の結果を元に、子機であるTWE-Lite DIP に接続されたLEDを点滅させる
※1 今回の記事は下記ページのFirmware 「超簡単!TWEアプリ」を利用したものとなります。
http://mono-wireless.com/jp/products/TWE-ZERO/index.html
※2 今回の標準ファームを利用する方法では最終的に実施したい事が出来ないと判断したため、独自でファームウェアを作成する事にしました、続編は引き続き掲載致します。
準備
ハードウェアの構成
- RaspberryPi2 B+
- ToCoStick
- TWE-Lite DIP 1台
- 抵抗 680オーム * 3
- LED 手持ちの物を適当に * 3
- ボタンスイッチ
配線
- 電源
Raspberry PiのGPIOから5Vを引き出し、3端子レギュレータ TA48M033F を用い 5v -> 3.3v へ降圧しています - DO1 LEDを接続
- DO2 LEDを接続
- DO3 LEDを接続
- DI1 ボタンスイッチを接続 (親機データ受信時のテストに利用)
LEDと抵抗、ボタンスイッチの接続は下記公式の入門ページに準じております。
TWE-Lite DIP使用方法(初級編)
RaspberryPiにcuパッケージをインストール
シリアルコンソールをインストール
cu - Call up another system だそうです覚えづらい...
下記の様に表示されれば接続成功です。(Macではデバイス名が異なります)
$ sudo apt-get install cu $ cu -s 115200 -l /dev/ttyUSB0 Connected.
rootユーザでは接続できません
$ sudo su - # cu -l /dev/ttyUSB0 cu: open (/dev/ttyUSB0): Permission denied cu: /dev/ttyUSB0: Line in use
dialoutグループにpiのみ所属しているためです
特に実施する必要は無いと思いますが groupファイル編集にて dialout:x:20:pi,root のようにして再ログインすれば接続出来るようになります。
$ getent group | grep dial dialout:x:20:pi
切断
Ctrl + C の後に ~.
Mac → Raspberry Pi から接続しているのですが 直接 ~. を入力すると
Mac → Raspberry Pi 間の接続が切られてしまいました
親機と子機の設定を行う
下記コマンドを実行後に Connected. と表示されたら + を 3回入力します
するとConfig画面が表示されます
$ cu -s 115200 -l /dev/ttyUSB0 Connected.
親機と子機で設定画面に入りApplication IDを揃える必要があります。
また、親機はDevice IDを121とする必要があります。
Application IDについて
http://mono-wireless.com/jp/products/TWE-Lite-DIP/TWE-Lite-DIP-step3-interactive.html
親機の設定
--- CONFIG/TOCOS TWELITE DIP APP V1-06-16/SID=0xxxx/LID=0x00 --- a: set Application ID (0x38380001) <- 変更 i: set Device ID (121=0x79) <- 親機は121固定 c: set Channels (18) x: set Tx Power (03) t: set mode4 sleep dur (1000ms) y: set mode7 sleep dur (10s) f: set mode3 fps (32) z: set PWM HZ (1000) o: set Option Bits (0x00000020) b: set UART baud (38400) p: set UART parity (N) --- S: save Configuration R: reset to Defaults
設定変更を行いたい頭文字 a を入力するとインタラクティブに値を入力できます
最後に S を押してConfigを保存しましょう、変更された箇所が *印 付きとなりました。
頭文字c 周波数チャネルは親機/子機同一である必要があります
子機の設定
--- CONFIG/TOCOS TWELITE DIP APP V1-06-16/SID=0xxxx/LID=0x01 --- a: set Application ID (0x38380001) <- 変更 i: set Device ID (1=0x01) <- 変更 c: set Channels (18) x: set Tx Power (03) t: set mode4 sleep dur (1000ms) y: set mode7 sleep dur (10s) f: set mode3 fps (32) z: set PWM HZ (1000) o: set Option Bits (0x00000000) b: set UART baud (38400) p: set UART parity (N) --- S: save Configuration R: reset to Defaults
設定変更を行いたい頭文字 a や i を入力するとインタラクティブに値を入力できます
最後に S を押してConfigを保存しましょう、変更された箇所が *印 付きとなりました。
頭文字c 周波数チャネルは親機/子機同一である必要があるとの事です
子機から親機へのデータ受信テスト
上記設定を行うと既にデータが飛んでくる状態となっています確認を行うには上記と同じコマンドで
接続すれば良いのですが INTERACTIVE MODE に入ったままだと飛んできたデータが確認できないので
+ を3回押し通常モードに戻ると受信データを確認出来ます。
INTERACTIVE MODEを抜ける
$ cu -s 115200 -l /dev/ttyUSB0 Connected. ++!INF EXIT INTERACTIVE MODE. <- +を3回押しINTERACTIVE MODEから抜けた際のメッセージ
以降が子機から飛んできたデータ
:01811501BD8101256D78853D000D271D0001FFFFFFFFFF10 :01811501BD8101256D78853F000D271D0001FFFFFFFFFF0E
子機DI1への入力が親機に反映するか確認
:01811501AB8101256D00463F000CF81D8001FFFFFFFFFF87 :01811501AB8101256D004671000CF81D8001FFFFFFFFFF55 :01811501B18101256D0046A3000CF81D8001FFFFFFFFFF1D :018115019F8101256D0046E3000CF81D8001FFFFFFFFFFEF :01811501A28101256D004701000CF81D0101FFFFFFFFFF4C <- スイッチを押した (DI1 を GNDに落とした時) :01811501A28101256D00474F000CF91C8101FFFFFFFFFF7E :01811501A28101256D00478B000CF81C8101FFFFFFFFFF43 :01811501A88101256D00478F000CF81D0001FFFFFFFFFFB9 <- スイッチを離した時 :01811501A88101256D0047D5000CF91D8001FFFFFFFFFFF2 :01811501A58101256D0047E5000CF91C0101FFFFFFFFFF65 <- スイッチを押した (DI1 を GNDに落とした時) :01811501A88101256D004831000CF81D8101FFFFFFFFFF95 :01811501A58101256D00484B000CF81D0001FFFFFFFFFFFF
Pythonで受信データを表示
下記を適当な名前で作成頂き実行する事で上記出力を得られます
#!/usr/bin/env python # -*- coding: utf-8 -*- import serial import sys argv = sys.argv argc = len(argv) def read_serial(s): while True: line = s.readline() print line.strip() # USBデバイスの指定 if argc != 2: s = serial.Serial("/dev/ttyUSB0", 115200, timeout=10) else : s = serial.Serial(argv[1], 115200, timeout=10) while True: try: read_serial(s) except KeyboardInterrupt: break except: continue s.close()
Pythonでデータ送信を行う
#!/usr/bin/env python # -*- coding: utf-8 -*- import serial import sys import select import time argv = sys.argv argc = len(argv) def digital_write(child_id, pin, value): header = get_send_header(child_id) if pin == 1: if value == HIGH: cmd = header + '0101'+'FFFFFFFFFFFFFFFF' if value == LOW: cmd = header + '0001'+'FFFFFFFFFFFFFFFF' if pin == 2: if value == HIGH: cmd = header + '0202'+'FFFFFFFFFFFFFFFF' if value == LOW: cmd = header + '0002'+'FFFFFFFFFFFFFFFF' if pin == 3: if value == HIGH: cmd = header + '0404'+'FFFFFFFFFFFFFFFF' if value == LOW: cmd = header + '0004'+'FFFFFFFFFFFFFFFF' # コマンド送信 パリティを省略 # SDKマニュアルを参照 s.write(cmd + 'XX\r\n') def get_send_header(child_id): if child_id == '': # 全ての子機を対象にする header = ':78' # コマンド番号 + 書式バージョンは固定値 header = header + '8001' else : if child_id >= 1 and child_id <= 100: # 特定の子機を対象にする header = ':' + '%02x' % int(child_id) # コマンド番号 + 書式バージョンは固定値 header = header + '8001' else : sys.exit("child_idの指定は1-100までの数値で指定して下さい") return header # main HIGH = 1 LOW = 0 # USBデバイスの指定 if argc != 2: s = serial.Serial("/dev/ttyUSB0", 115200, timeout=10) else : s = serial.Serial(argv[1], 115200, timeout=10) while True: # 全ての子機を対象 digital_write('', 1, HIGH) digital_write('', 2, HIGH) digital_write('', 3, HIGH) # 特定のidの機器を対象 digital_write(2, 1, HIGH) digital_write(2, 2, HIGH) digital_write(2, 3, HIGH) time.sleep(0.5) digital_write('', 1, LOW) digital_write('', 2, LOW) digital_write('', 3, LOW) time.sleep(0.5) s.close()
当初の予定では上記のようにして子機への通知としてLEDの点滅を親機側で制御できたら良いなと考えていたのですが
標準ファームウェアでは外部回路を用いないと、特定ポートをOn/Blink状態で保持等は出来ないため
次回以降でオリジナルのファームウェア開発について記載します。