TWE-Lite DIPをRaspberry Pi上のToCoStickとPythonプログラム経由で通信しLチカ

何回かに分けて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
  • ボタンスイッチ

配線

IMG_3725
  • 電源
    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状態で保持等は出来ないため
次回以降でオリジナルのファームウェア開発について記載します。

投稿者プロフィール

takashi
開発会社での ASP型WEBサービス企画 / 開発 / サーバ運用 を経て
2010年よりスカイアーチネットワークスに在籍しております

機械化/効率化/システム構築を軸に人に喜んで頂ける物作りが大好きです。
個人ブログではRaspberryPiを利用したシステムやロボット作成も
実施しております。

スカイアーチネットワークスで一緒に働きましょう!

ABOUTこの記事をかいた人

開発会社での ASP型WEBサービス企画 / 開発 / サーバ運用 を経て 2010年よりスカイアーチネットワークスに在籍しております 機械化/効率化/システム構築を軸に人に喜んで頂ける物作りが大好きです。 個人ブログではRaspberryPiを利用したシステムやロボット作成も 実施しております。 スカイアーチネットワークスで一緒に働きましょう!