最適な出力のために、Google Chrome(15以降)または Microsoft Edge(79以降)を推奨いたします。
2026-08-25 現在 スタートガイド 最初に目を通していただきたい情報です。お持ちの製品から選んでください。
お持ちの製品から選ぶ
TWELITE CUE / TWELITE ARIA をお持ちの方へ
CUE と ARIA は完成品のセンサー製品です。電池を入れて設置するだけで送信を始めます 。したがって、送信側で用意する作業はありません。
必要なのは受け取る側 です。PC で受け取るなら TWELITE STICK 、Wi-Fi のネットワークへ渡すなら TWELITE SPOT のスタートガイドをご覧ください。
各スタートガイド 1 - TWELITE DIP 超簡単!標準アプリを使ってデジタル・アナログ信号を伝送する
超簡単!無線モジュール TWELITE DIP は、TWELITE を 2.54mm ピッチの基板へ搭載した製品です。手作業による配線を容易に行えるため、試作や小規模ロット生産に適しています。
外観
すぐに使用できる無線モジュール 超簡単!標準アプリ 工場出荷時の TWELITE DIP には 超簡単!標準アプリ(App_Twelite)をインストールしています。
超簡単!標準アプリは、デジタル・アナログ信号の伝送を行うファームウェアです。
デジタル アナログ UART I2C 一方のデジタル入力をもう一方のデジタル出力へ 一方のアナログ入力をもう一方の PWM 出力へ 一方のシリアル入力をもう一方のシリアル出力へ 子機のターゲットへ親機からアクセス
デジタル・アナログの基本的な信号伝送は、配線するだけで「超簡単に」実現できます。
クイックマニュアル(PDF)
シンプルな無線通信 TWELITE は、起動直後から通信できます。Bluetooth のようなペアリングを行いません。
周波数チャネルを合わせた端末同士で同報通信を行います。したがって、同一の周波数チャネルでは、同時に複数の端末が送信を行うことはできません。自分宛でないパケットは無視します。トランシーバやインカムの動作をイメージすると分かりやすいかもしれません。
TWELITE は受信を伴わずとも送信できるため、省電力性能に優れた端末を実現できます。
無線通信の規格は? TWELITE は 2.4GHz 帯の電波を使用する無線モジュールですが、Bluetooth (IEEE 802.15.1) とは異なる規格の IEEE 802.15.4 へ準拠しています。
IEEE 802.15.4 へ準拠した他の製品には Zigbee モジュールがありますが、TWELITE は Zigbee モジュールではありません 。Zigbee モジュールは IEEE 802.15.4 の上層に Zigbee プロトコルスタックを採用していますが、TWELITE はシンプルな独自のプロトコルスタックを代わりに実装しています。
データ量の多い通信には適していないものの、単純な信号伝送といった用途には最適です。
ピンの機能 ピン配置表
超簡単!標準アプリで使用するピンの機能には、いくつかの種類があります。
電源入力(3.3V) デジタル・アナログ入出力 シリアル通信 設定入力Mx 動作モード切り替えBPS 代替ボーレート選択 RST リセット入力x: 任意の番号
1.1 - まずは使ってみる 初期設定の超簡単!標準アプリを使ってデジタル・アナログ信号を伝送する
超簡単!標準アプリ(App_Twelite)では、配線するだけで基本的な信号伝送を実現できます。
工場出荷時の TWELITE DIP に書き込まれている超簡単!標準アプリを使って、片方の DIx/AIx ポートへ入力した信号をもう片方の DOx/PWMx ポートへ反映させてみましょう。
使用する製品
TWELITE DIP は、BLUE シリーズ と RED シリーズのどちらでも構いません。
片方向の信号伝送 親機へ入力された信号を、子機から出力できます。
親機はすべての子機へデータを送信します 複数の子機を用意すると、親機の DIx で全ての子機の DOx を同時に制御できます。
デジタル信号 親機へ接続したスイッチを押すと子機へ接続した LED が点灯し、親機へ接続したスイッチを離すと子機へ接続した LED が消灯します。
親機の配線
子機の配線
上記の例では DI1 と DO1 だけを使っていますが、ポートは合計4つあります。他のポートも同様に使用できます。
片側の TWELITE DIP は、M1 ピンを GND へ接続してください。親機となります。
また、未使用の AIx ポートは VCC へ接続してください。無効化されます(インタラクティブモードによる設定変更で省略可)。
出力できる電流の大きさには制限があります 電源電圧 駆動能力 2.7V-3.6V 4mA 2.2V-2.7V 3mA 2.0V-2.2V 2.5mA
駆動能力を超える場合は、MOSFET やトランジスタを使用してください。
アナログ信号 親機へ接続したボリュームを回すと、子機へ接続した LED の明るさが変化します。
親機の配線
子機の配線
上記の例では AI1 と PWM1 だけを使っていますが、ポートは合計4つあります。他のポートも同様に使用できます。
入出力の電圧について アナログ入力は2.0V以下で動作します。
上記の例では、電源電圧をボリューム(10KΩ)と抵抗(10KΩ)で半分に分圧しています。初期状態の超簡単!標準アプリでは、ボリューム用に調節した出力を PWMx へ適用します。このときのデューティ比を\(duty\)とするとき、入力電圧\(V_{input}\)と電源電圧\(V_{cc}\)を使って表す計算式を次に示します。
\(duty=min(230\frac{V_{input}}{V_{cc}}-5, 100)\)
なお、インタラクティブモードを使ってオプションビット 0x00000040 を設定すると、1.8V 以下の入力に対してフルスケールで出力できます(2.0V以上で未使用扱い)。
\(duty=100\frac{min(V_{input}, 1.8)}{1.8}\)
PWM2 および PWM3 へ何らかの配線をしていると、ファームウェアを書き換えできない場合があります。
これらのピンは、ファームウェア書き換え時に使用するための機能を備えているからです(詳細 )。
双方向の信号伝送 信号伝送は、親機から子機だけではなく、子機から親機へも同様に行えます。
親機はすべての子機からデータを受信します 複数の子機を用意すると、排他的な子機の DIx で親機の DOx を平行して制御できます。
(例:ある子機の DI1 を親機の DO1 へ、別の子機の DI2 を親機の DO2 へ反映させる)
デジタル信号の伝送例 を双方向に拡張してみましょう。なおアナログ信号の伝送例 も同様に拡張できます。
親機へ接続したスイッチを押すと子機へ接続した LED が点灯し、親機へ接続したスイッチを離すと子機へ接続した LED が消灯します。
同時に子機へ接続したスイッチを押すと親機へ接続した LED が点灯し、子機へ接続したスイッチを離すと親機へ接続した LED が消灯します。
親機の配線
子機の配線
上記の例では DI1 と DO1 だけを使っていますが、ポートは合計4つあります。他のポートも同様に使用できます。
中継機の設置 中継機として設定したものを親機と子機の間へ設置することで、通信距離を延長できます。最大3段まで中継できます。
中継機の配線
M2 を GND へ接続します。
1.2 - インタラクティブモードによるカスタマイズ インタラクティブモードを利用して機能をカスタマイズする
インタラクティブモードを利用すると、ネットワークのグループ分けや低レイテンシモードの有効化といった各種パラメータの変更を行うことができます。
インタラクティブモードとは インタラクティブモードは、TWELITE シリーズを PC へ接続して設定を行う際に利用するモードです。TWELITE シリーズを USBアダプター TWELITE R シリーズを介して PC へ接続することで、UART 通信により各種パラメータの変更を行うことができます。
TWELITE STAGE アプリの使用を推奨します。TWELITE STAGE アプリは、ファームウェアの設定や書き換えに加え、親機との送受信を評価するための機能を備えたツールです。TWELITE STAGE アプリは TWELITE STAGE SDK に含まれています。
TWELITE STAGE アプリの詳細については、TWELITE APPS マニュアル をご覧ください。
カスタム例 目的別に TWELITE DIP のカスタム例を示します。
興味のあるものを選んでお試しください。
ネットワークのグループ分け 初期状態では、すべての TWELITE DIP が相互に通信できる状態にあります。親機と子機のペアを2つ用意した場合、親機の入力は双方の子機へ反映されるほか、子機の入力も双方の親機へ反映されます。
インタラクティブモードによってアプリケーションIDと周波数チャネルを変更し、2つのペアを同時に独立して使用できるようにしましょう。
使用する製品 カスタムの内容 インタラクティブモードの値を次のように設定し、2つのペアをグループAとBに分けます。
アプリケーションIDは論理的に、周波数チャネルは物理的にネットワークを分離します。グループ数が16以下であれば、どちらも変更することを推奨しています。
周波数チャネルは、できる限り間隔を空けるように推奨しています。
カスタム方法 TWELITE DIP を TWELITE R2 へ差し込み、USB-C ケーブルを使って PC と接続する TWELITE STAGE アプリ を立ち上げ、シリアルポート選択 から対象の TWELITE R2 を選択するメインメニュー の「3: インタラクティブモード 」を選択する大文字のRを押下して、設定を初期状態へ戻す a を押下したのち、AAAAAAAA/BBBBBBBBを入力してEnterを押下するc を押下したのち、11/26を入力してEnterを押下する大文字のSを押下して、設定を適用する(TWELITE はリセットされる) ESCを何度か押してメインメニュー へ戻り、TWELITE R2 の USB-C ケーブルを抜くTWELITE DIP を取り外し、ブレッドボード等へ差し込み、回路へ接続する 動作確認 グループAとグループBの双方を「まずは使ってみる」の片方向デジタル信号の例 のように配線し、親機へスイッチを、子機へ LED を接続します。
グループAの親機のスイッチを押すと、グループAの子機の LED だけが光ります グループBの親機のスイッチを押すと、グループBの子機の LED だけが光ります グループBの子機のアプリケーションIDを0xAAAAAAAAへ、周波数チャネルを11へ変更します。
グループAの親機のスイッチを押すと、2台の子機の LED がどちらも光ります 低レイテンシモードの使用 初期状態では、送信元のDIxが送信先のDOxへ反映されるまでに30-70ms程度の遅延が生じます。チャタリングや無線パケットの干渉を避けるための処理が存在するからです。
低レイテンシモード は、これらの処理を簡略化することで遅延を3-10ms程度に短縮します。
インタラクティブモードによって送信側の端末の低レイテンシモードを有効化してみましょう。
低レイテンシモードは、次のような場合に有用です。
ハードウェアにチャタリングの懸念がない場合 入力状態をすばやく変化させる場合 使用する製品 カスタムの内容 インタラクティブモードの値を次のように設定し、送信側(親機)の低レイテンシモードを有効化します。
オプションビットの値は32bitの非不整数です。各ビットのフラグを立てることで対応した設定を有効化できます。
同時に複数の設定を有効化するには、すべての論理和を取ります。
カスタム方法 TWELITE DIP を TWELITE R2 へ差し込み、USB-C ケーブルを使って PC と接続する TWELITE STAGE アプリ を立ち上げ、シリアルポート選択 から対象の TWELITE R2 を選択するメインメニュー の「3: インタラクティブモード 」を選択する大文字のRを押下して、設定を初期状態へ戻す o を押下したのち、00000001を入力してEnterを押下する大文字のSを押下して設定を適用する(TWELITE はリセットされる) ESCを何度か押してメインメニュー へ戻り、TWELITE R2 の USB-C ケーブルを抜くTWELITE DIP を取り外し、ブレッドボード等へ差し込み、回路へ接続する 動作確認 親機と子機を「まずは使ってみる」の片方向デジタル信号の例 のように配線し、親機へスイッチを、子機へ LED を接続します。
親機のスイッチを押すと、子機の LED が光ります 動作は初期状態と変わりませんが、少しレスポンスが向上したことを感じ取れるかもしれません 親機のDO1と子機のDI1へオシロスコープを接続して比較すると、その効果を確認できます ボタン押下時のみ送信させる 初期状態では、入力状態が変化したときに送信を行うほか、1秒おきに送信します。
このとき、例えば送信側のボタンを押したまま電源を断つと、受信側の出力は残り続けて しまいます。
ボタン押下時のみ送信 設定では、送信側のDIxがLowのときに繰り返し送信を行い、Highへ遷移しても1秒間は送信を続けます。受信側のDOxをLowとしてから受信が途絶えた場合はHighへ戻します。
インタラクティブモードによってボタン押下時のみ送信するように変更してみましょう。
リモコンのボタンを押している間にモータを回転させるといった用途に有用です。
DIxがLowのときは短い間隔で送信を続けるため、同一の周波数チャネルに送信機を増やすことは推奨しません。このオプションは1:1の通信を行う際に適用してください。
使用する製品 カスタムの内容 インタラクティブモードの値を次のように設定し、送信側(親機)と受信側(子機)のデジタル入出力の振る舞いを変更します。
カスタム方法 TWELITE DIP を TWELITE R2 へ差し込み、USB-C ケーブルを使って PC と接続する TWELITE STAGE アプリ を立ち上げ、シリアルポート選択 から対象の TWELITE R2 を選択するメインメニュー の「3: インタラクティブモード 」を選択する大文字のRを押下して、設定を初期状態へ戻す o を押下したのち、00000100を入力してEnterを押下する大文字のSを押下して設定を適用する(TWELITE はリセットされる) ESCを何度か押してメインメニュー へ戻り、TWELITE R2 の USB-C ケーブルを抜くTWELITE DIP を取り外し、ブレッドボード等へ差し込み、回路へ接続する 動作確認 親機と子機を「まずは使ってみる」の片方向デジタル信号の例 のように配線し、親機へスイッチを、子機へ LED を接続します。
親機のスイッチを押すと、子機の LED が光ります 親機のスイッチを押したまま電源供給を断つと、子機のLEDは消えます(初期状態は消えない) 1.3 - UART機能によるPCとの連携 親機をPCへ接続して、UARTを通じたデータの受信と送信を行う
UART 通信を利用することで、親機を PC と連携させることができます。
TWELITE STAGE アプリ および Python スクリプトを用いて UART 通信を行い、PC から親機を通じて子機のデータを取得/操作します。
使用する製品 なお、TWELITE DIP と TWELITE R2 のペアは MONOSTICK 単体と同等です。次の組み合わせでも構いません。
TWELITE STAGE アプリの導入 TWELITE STAGE アプリは、ファームウェアの設定や書き換えに加え、親機との送受信を評価するための機能を備えたツールです。
ここでは、TWELITE STAGE アプリを使って TWELITE DIP(超簡単!標準アプリ)の子機のデータを表示、また操作してみましょう。
TWELITE STAGE アプリは、TWELITE STAGE SDK に含まれています。
TWELITE STAGE アプリによる受信 超簡単!標準アプリの子機が送信するデータは、DIx/AIxポートの入力状態や電源電圧、送信元の論理デバイスIDといった情報を含んでいます。
シリアル文字列の表示 親機が子機から受信したデータは、親機がシリアル通信(UART)で出力する文字列を解釈することで取得できます。まずはこの文字列を表示してみましょう。
初期状態におけるシリアル通信の仕様は 115200bps 8-N-1 です。
TWELITE STAGE アプリを立ち上げ、シリアルポート選択 で親機を選択します。メインメニュー の「1: ビューア」 >「1: ターミナル」 を開いてください。
子機のデータを受信すると、次のようなメッセージを表示します。
:78811501C98201015A000391000C2E00810301FFFFFFFFFB 親機が出力するこのような文字列を解釈することで、子機が送信したデータを得ることができます。
上記の文字列は次のデータを表しています # データ 内容 値 :charヘッダ :780 uint8送信元の論理デバイスID 0x78811 uint8コマンド番号 0x81152 uint8パケット識別子 0x15013 uint8プロトコルバージョン 0x01C94 uint8LQI 201/2558201015A5 uint32送信元のシリアルID 0x201015A009 uint8送信先の論理デバイスID 0x00039110 uint16タイムスタンプ 約14.27秒 0012 uint8中継回数 00C2E13 uint16電源電圧 3118mV0015 int8- 8116 uint8デジタル信号 DI1 L DI2 HDI3 H DI4 H (定期送信)0317 uint8デジタル信号マスク DI1 DI20118 uint8AI1の変換値16mVFF19 uint8AI2の変換値未使用 FF20 uint8AI3の変換値未使用 FF21 uint8AI4の変換値未使用 FF22 uint8AIxの補正値AI1 0x03FBuint8チェックサム 0xFBcharフッタ \rcharフッタ \n
なお、TWELITE の親機が出力する文字列は、基本的に次の形式へ従います。
ヘッダ ペイロード チェックサム フッタ :00-FFの繰り返しペイロードのLRC8 CRLF
すべて ASCII 文字※ 先頭は : (0x3A) 末端は CRLF (\r\n/0x0D 0x0A) ビッグエンディアン ※ シリアル通信アプリのバイナリ書式を除く
標準アプリ ビューア 上記のような形式はコンピュータにやさしいものですが、人間が確認するにはこれを解釈する必要があります。TWELITE STAGE アプリには、超簡単!標準アプリの子機が送信したデータを表す文字列を解釈して表示する機能があります。後述の Python ライブラリはこの解釈を行います。
メインメニュー の「1: ビューア」 へ戻り、「2: 標準アプリ ビューア」 を開いてください。
タイムスタンプと論理デバイスID、シリアルIDとDIx/AIxの値を確認できます。
標準アプリ ビューアの画面
TWELITE STAGE アプリによる送信 これまでとは反対に、親機から子機へ無線パケットを送信し、子機の出力状態を変更することもできます。
コマンダー メインメニュー の「1: ビューア」 へ戻り、「5: コマンダー」 を開いてください。
DIxおよびAIxの入力をシミュレートしたパケットを送信できます。
コマンダーの画面
使い方
コマンダーは、PCから親機へシリアル通信によって文字列を送信しています。すなわち、標準アプリ ビューアとは逆の仕組みです。
この文字列も:で始まり CRLF で終わります。詳しい書式は超簡単!標準アプリ マニュアル をご覧ください。
Python スクリプト TWELITE STAGE アプリの「標準アプリ ビューア」および「コマンダー」は、どちらもシリアル通信によって文字列をやりとりしているに過ぎません。シリアル通信を利用できる環境であれば、自作のアプリケーションと親機を連携させることができます。
ここでは Python スクリプトを使ってDI1の入力状態を表示したのち、DO1の出力を制御してみましょう。
Python スクリプトを応用すれば、受信したデータを加工して保存したり、自作のソフトウェアから出力ポートを操作したりといった仕組みを実現できます。
Python に関する知識と経験のある読者を想定しています。
MWings ライブラリの導入 MWings ライブラリは、TWELITE と Python スクリプトの連携を簡単に実現するためのライブラリです。具体的には、子機から受信したデータを表す文字列の解釈と、子機へ送信するデータの構築を行います。
PyPI からインストールできます。
以降は pyenv と poetry による実行環境を想定しますが、MWings は Python 3.12 以降であれば動作します。お好みの環境があれば読み替えてください。
Python スクリプトによる受信 TWELITE DIP のDI1へ接続したボタンが押された際にメッセージを表示する Python スクリプトを実装してみます。
サンプルスクリプトの実行 下記の内容のスクリプト dip_show_di1.py を作成してください。
# -*- coding:utf-8 -*-
# TWELTIE DIP start guide: receiving in python
import mwings as mw
def main ():
twelite = mw. Twelite(mw. utils. ask_user_for_port())
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
if packet. di_state[0 ]:
print("DI1 Pressed" )
try :
twelite. daemon = True
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 )
except KeyboardInterrupt :
print("Flushing..." )
twelite. stop()
print("Completed" )
if __name__ == "__main__" :
main() スクリプトを実行すると、子機のDI1が Low になったときに DI1 Pressed と出力します。
実行時に複数の TWELITE R シリーズや MONOSTICK シリーズが接続されているときは、親機へ接続されたシリアルポートを選択してください。
poetry run python dip_show_di1.py
Multiple ports detected.
[ 1] /dev/cu.usbserial-R2xxxxxx TWE-Lite-R ( Genuine)
[ 2] /dev/cu.usbserial-R2xxxxxx TWE-Lite-R ( Genuine)
Select [ 1-2] : 2
Selected: /dev/cu.usbserial-R2xxxxxx
Started receiving
DI1 Pressed
DI1 Pressed
^CFlushing...
Completed 上記は macOS における例です。WindowsではCOMポート名を表示します。
サンプルスクリプトの解説 MWings ライブラリのインポート
短縮名 mw を使って呼び出せるようにしています。pandas as pd や numpy as np と同様です。
オブジェクトの作成
twelite = mw. Twelite(mw. utils. ask_user_for_port()) 親機をとやりとりするためのインタフェースとなる Twelite オブジェクトを作成しています。
引数にはシリアルポートを指定しますが、ここでは mw.utils.ask_users_for_port() ユーティリティを呼び出し、動的に決定しています。この関数はシリアルポートが存在しないときにエラーメッセージを出力し、1つだけ存在する場合はそのポートを、複数存在する場合はユーザが指定したポートを返します。
受信イベントハンドラの登録
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
if packet. di_state[0 ]:
print("DI1 Pressed" ) 超簡単!標準アプリの子機からのパケットを受信したときに呼び出されるイベントハンドラを登録しています。
イベントハンドラの登録は、Python のデコレータ(? )を使って行います。今回は超簡単!標準アプリ(App_Twelite)のデータを対象とするため、@twelite.on(mw.common.PacketType.APP_TWELITE) を記述しています。この記述の直後に定義された関数がハンドラとなります。関数名は問いませんが、Twelite オブジェクトの初期化後に定義する必要があります。
今回は子機のDI1がLowになったことを検知するため、受信ハンドラが受け取る変数 packet(mwings.parsers.app_twelite.ParsedPacket )のうち、DIxの状態を示す List-like なオブジェクト di_state(デジタルインタフェースの状態)0番目の真偽値を判定しています。di_stateの各値は、Trueのときに Low を示します。
その他のデータの取り扱い packet変数は、入力状態に加えて送信元の情報や受信側の情報も格納しています。例えばto_json() を使って次のように改変すると、すべてのデータをJSON形式で出力できます。
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
print(packet. to_json(verbose= True , spread= False )) なお verboseはシステム情報の省略を、spreadはList-likeなオブジェクトの展開を有効化します。
pandas を導入している場合は、to_df() を使ってデータフレームを得ることもできます。
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet):
print(packet. to_df(verbose= False ). to_string()) データの待機
twelite. daemon = True
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 ) ここでは、別のスレッドで親機からのデータの待機を行っています。
Twelite のオブジェクトは threading.Thread のサブクラスであり、ここではその機能によってデーモンスレッドを立ち上げ、スクリプトを終了するまでメインスレッドをブロックしています。
なぜ while ループおよび join(0.5) としているのか Ctrl-C を押した際に正常終了できないからです。メインスレッドがシグナルを受け取ることができるようにしなくてはなりません。
終了処理
print("Flushing..." )
twelite. stop()
print("Completed" ) Ctrl-C が押された際には、twelite.stop() を呼び出すことでサブスレッドを終了しています。
Python スクリプトによる送信 次は、反対に TWELITE DIP のDO1へ接続された LED をPCから点滅させる Python スクリプトを実装してみます。
サンプルスクリプトの実行 下記の内容のスクリプト dip_blink_led.py を作成してください。
# -*- coding:utf-8 -*-
# TWELITE DIP start guide: blinking from python
from time import sleep
import mwings as mw
def main ():
twelite = mw. Twelite(mw. utils. ask_user_for_port())
initial = {
"destination_logical_id" : 0x78 ,
"di_to_change" : [True , False , False , False ],
"di_state" : [False , False , False , False ],
}
command = mw. serializers. app_twelite. Command(** initial)
while True :
command. di_state[0 ] = not command. di_state[0 ]
twelite. send(command)
print(f "Flip DO1: { command. di_state[0 ]} " )
sleep(1 )
if __name__ == "__main__" :
try :
main()
except KeyboardInterrupt :
print("...Aborting" ) スクリプトを実行すると、子機のDO1が一秒おきに点滅します。
実行時に複数の TWELITE R シリーズや MONOSTICK シリーズが接続されているときは、親機へ接続されたシリアルポートを選択してください。
poetry run python dip_blink_led.py
Multiple ports detected.
[ 1] /dev/cu.usbserial-R2xxxxxx TWE-Lite-R ( Genuine)
[ 2] /dev/cu.usbserial-R2xxxxxx TWE-Lite-R ( Genuine)
Select [ 1-2] : 2
Selected: /dev/cu.usbserial-R2xxxxxx
Flip DO1: True
Flip DO1: False
Flip DO1: True
Flip DO1: False
Flip DO1: True
^C...Aborting サンプルスクリプトの解説 MWings ライブラリのインポート
短縮名 mw を使って呼び出せるようにしています。pandas as pd や numpy as np と同様です。
オブジェクトの作成
twelite = mw. Twelite(mw. utils. ask_user_for_port()) 親機をとやりとりするためのインタフェースとなる Twelite オブジェクトを作成しています。
引数にはシリアルポートを指定しますが、ここでは mw.utils.ask_users_for_port() ユーティリティを呼び出し、動的に決定しています。この関数はシリアルポートが存在しないときにエラーメッセージを出力し、1つだけ存在する場合はそのポートを、複数存在する場合はユーザが指定したポートを返します。
親機へ送信するコマンドの作成
initial = {
"destination_logical_id" : 0x78 ,
"di_to_change" : [True , False , False , False ],
"di_state" : [False , False , False , False ],
}
command = mw. serializers. app_twelite. Command(** initial) 超簡単!標準アプリの子機へ送信するパケットを生成するためのコマンドを表すデータ command(mwings.serializers.app_twelite.Command )を初期化しています。
辞書オブジェクト initial は、コマンドの初期状態を表しています。ここでは、送信先の論理デバイスIDを 0x78(全子機)としたうえで、DI1を変更対象、High 状態としています。
データの送信
while True :
command. di_state[0 ] = not command. di_state[0 ]
twelite. send(command)
print(f "Flip DO1: { command. di_state[0 ]} " )
sleep(1 ) ここでは、コマンドデータの文字列への変換および親機への送信を1秒おきに行っています。
コマンドデータのうち、DOxの状態を示す List-like なオブジェクト di_state(デジタルインタフェースの状態)0番目の真偽値を反転させることで、点滅を実現しています。
1.4 - バイナリデータの伝送 UART通信により任意のバイト列を伝送する
シリアル通信アプリを使うことで、任意のバイナリデータの送受信を行うことができます。
TWELITE をシリアル通信を無線化する装置として利用し、PC間でバイト列のデータを送信してみます。
使用する製品 なお、TWELITE DIP と TWELITE R2 のペアは MONOSTICK 単体と同等です。次の組み合わせでも構いません。
シリアル通信アプリ TWELITE のファームウェアを、シリアル通信の無線化に特化したシリアル通信アプリ(App_Uart)へ書き換えます。超簡単!標準アプリはシリアル通信によるバイナリデータの伝送機能を備えているものの、その機能は非常に限られているからです。
ファームウェアの書き換え 親機と子機、すべての端末を書き換えます。
TWELITE STAGE SDK を導入 し、TWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「2: アプリ書換 」を選択する 「1: BINから選択 」を選び、App_Uart... を選択する 書き込みが完了するまで、数回Enterを押す
初期設定では、書き込みが成功すると次のようなインタラクティブモード の画面へ移行します。
--- CONFIG/TWE UART APP V1-04-5/SID=0x82018ca0/LID=0x78 -- ---
a: set Application ID (0x67720103)
i: set Device ID (120=0x78)
c: set Channels (18)
x: set RF Conf (3)
r: set Role (0x0)
l: set Layer (0x1)
b: set UART baud (38400)
B: set UART option (8N1)
m: set UART mode (E)
k: set Tx Trigger (sep=0x0d0a, min_bytes=0 dly=0[ms])
h: set header format [;U;%t;%i;0x%A;%q;%s;<*>;%X;\n]
C: set crypt mode (0)
o: set option bits (0x00000100)
---
S: save Configuration
R: reset to Defaults 通信モードの一覧 シリアル通信アプリには5つの通信モードがあり、用途に応じて使い分けることができます。
初期状態はヘッダ付き透過モードです。
シリアル通信アプリの各通信モードの詳細については、
マニュアル をご覧ください。
ここでは、次の4つのモードを使った通信テストの手順を紹介します。気になるものを選んでお試しください。
ヘッダ付き透過モード 送信側の書式はありません。 受信側の書式から、送信元の論理デバイスIDや受信時の電波通信品質といった情報を得ることができます。 バランスのよいモードです。 透過モード 送受信双方に書式はありません。 送信側の入力と受信側の出力は同等です。 最も簡単ですが、機能は限られています。 書式モード(アスキー) 送受信双方へ書式を適用します。 外部デバイスの対応が必要ですが、送信先の指定や送信元の識別ができます。 バイナリデータは16進数の文字列で表現します。 書式モード(バイナリ) 送受信双方へ書式を適用します。 外部デバイスの対応が必要ですが、送信先の指定や送信元の識別ができます。 バイナリデータはそのまま表現します。 今回は同一のPCへ2台の TWELITE を接続し、データをループバックさせてみましょう。通常は外部デバイス同士を無線経由で接続します。
ヘッダ付き透過モード ヘッダ付き透過モードを使用して、ASCIIデータHelloという文字列を双方から送信してみましょう。
設定方法 シリアル通信アプリの既定のモードはヘッダ付き透過モードです。よって初期設定のまま使用します。
通信テスト 1. TWELITE STAGE アプリを2つ立ち上げる TWELITE STAGE アプリ(TWELITE_Stage.exe/.command/.run)を2つ立ち上げてください。
必須ではありませんが、実行ファイルを複製しておくことを推奨します(例:TWELITE_Stage_1とTWELITE_Stage_2)。
2. ターミナルを表示する 双方の TWELITE STAGE アプリにおいてシリアルポートを選択したのち、「1: ビューア」>「1: ターミナル」を選択します。
3. 片側から送信 片方の画面を選択し、Helloと入力してEnterを押します。もう片方の画面へ反映されます。
片側から送信
4. 反対側から送信 もう片方の画面を選択し、Helloと入力してEnterを押します。元の画面へ反映されます。
反対側から送信
次の系列は、以下のように解釈できます。
;U;00052;120;0x82036841;255;000;Hello;79; データ 内容 値 Uchar固定値 U00052uint16出力時のタイムスタンプ 52 秒120uint8送信元の論理デバイスID 120 IDなし子機0x82036841uint32送信元の拡張アドレス 82036841255uint8LQI(電波通信品質) 255/255000uint8送信元の続き番号 0Hello[uint8]入力データ Hello79uint8XORチェックサム 0x79
書式の詳細はマニュアル をご覧ください。
透過モード 透過モードを使用して、ASCIIデータHelloという文字列を双方から送信してみましょう。
設定方法 m:通信モード をDとします。
通信テスト 1. TWELITE STAGE アプリを2つ立ち上げる TWELITE STAGE アプリ(TWELITE_Stage.exe/.command/.run)を2つ立ち上げてください。
必須ではありませんが、実行ファイルを複製しておくことを推奨します(例:TWELITE_Stage_1とTWELITE_Stage_2)。
2. ターミナルを表示する 双方の TWELITE STAGE アプリにおいてシリアルポートを選択したのち、「1: ビューア」>「1: ターミナル」を選択します。
3. 片側から送信 片方の画面を選択し、Helloと入力してEnterを押します。もう片方の画面へ反映されます。
片側から送信
エコーバック機能はないため、入力側の端末に入力した文字は表示されません。
4. 反対側から送信 もう片方の画面を選択し、Helloと入力してEnterを押します。元の画面へ反映されます。
反対側から送信
入出力のどちらにも書式がないため、入力したデータをそのまま出力します。
書式モード(アスキー) 書式モード(アスキー)を使用して、バイナリデータ 0x5A 0xAB 0x90 0x00 を双方から送信してみましょう。
Saab 9000 CD 2.3
設定方法 m:通信モード をAとします。
片方の端末のi:論理デバイスID を0(親機)としたうえで、もう片方の端末は1(子機、ID1)とします。
通信テスト(簡易形式) まずは、簡易形式のシンプルな書式を試してみましょう。
1. TWELITE STAGE アプリを2つ立ち上げる TWELITE STAGE アプリ(TWELITE_Stage.exe/.command/.run)を2つ立ち上げてください。
必須ではありませんが、実行ファイルを複製しておくことを推奨します(例:TWELITE_Stage_1とTWELITE_Stage_2)。
2. ターミナルを表示する 双方の TWELITE STAGE アプリにおいてシリアルポートを選択したのち、「1: ビューア」>「1: ターミナル」を選択します。
3. 親機側から送信 まず、以下の系列をコピーします。
上記の系列は、次の内容を指します。
データ 内容 値 :charヘッダ(固定値) :01uint8送信先の論理デバイスID 0x01 子機23uint8任意のコマンド番号 0x235AAB9000[uint8]送信するデータ 0x5A 0xAB 0x90 0x0047uint8チェックサム(LRC) 0x47charフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
次に、親機側の画面を選択します。
最後に、Alt+V/⌘+Vを押してペーストし、Enterを押します。子機側の画面へ反映されます。
親機側から送信
エコーバック機能がないほか、手入力ではタイムアウトしてしまいます。コピー&ペーストを利用してください。
上記における受信側の系列は、以下のように解釈できます。
データ 内容 値 :charヘッダ(固定値) :00uint8送信元の論理デバイスID 0x00 親機23uint8コマンド番号 0x235AAB9000[uint8]送信されたデータ 0x5A 0xAB 0x90 0x0048uint8チェックサム(LRC) 0x48charフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
:DBA1... の書式についても、
マニュアル をご覧ください。
4. 子機側から送信 まず、以下の系列をコピーします。
上記の系列は、次の内容を指します。
データ 内容 値 :charヘッダ(固定値) :00uint8送信先の論理デバイスID 0x00 親機23uint8任意のコマンド番号 0x235AAB9000[uint8]送信するデータ 0x5A 0xAB 0x90 0x0048uint8チェックサム(LRC) 0x48charフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
次に、子機側の画面を選択します。
最後に、Alt+V/⌘+Vを押してペーストし、Enterを押します。親機側の画面へ反映されます。
子機側から送信
上記における受信側の系列は、以下のように解釈できます。
データ 内容 値 :charヘッダ(固定値) :01uint8送信元の論理デバイスID 0x01 子機23uint8コマンド番号 0x235AAB9000[uint8]送信されたデータ 0x5A 0xAB 0x90 0x0047uint8チェックサム(LRC) 0x47charフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
:DBA1... の書式についても、
マニュアル をご覧ください。
通信テスト(拡張形式) 次に、拡張形式の高度な書式を試してみましょう。
1. TWELITE STAGE アプリを2つ立ち上げる TWELITE STAGE アプリ(TWELITE_Stage.exe/.command/.run)を2つ立ち上げてください。
必須ではありませんが、実行ファイルを複製しておくことを推奨します(例:TWELITE_Stage_1とTWELITE_Stage_2)。
2. ターミナルを表示する 双方の TWELITE STAGE アプリにおいてシリアルポートを選択したのち、「1: ビューア」>「1: ターミナル」を選択します。
3. 親機側から送信 まず、以下の系列をコピーします。
上記の系列は、次の内容を指します。
データ 内容 値 :charヘッダ(固定値) :01uint8送信先の論理デバイスID 0x01 子機A0uint8コマンド番号(固定値) 0xA0CDuint8任意の応答ID 0xCDFFuint8オプション なし0xFF5AAB9000[uint8]送信するデータ 0x5A 0xAB 0x90 0x00FEuint8チェックサム(LRC) 0xFEcharフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
次に、親機側の画面を選択します。
最後に、Alt+V/⌘+Vを押してペーストし、Enterを押します。子機側の画面へ反映されます。
親機側から送信
エコーバック機能がないほか、手入力ではタイムアウトしてしまいます。コピー&ペーストを利用してください。
上記における受信側の系列は、以下のように解釈できます。
:00A0CD82036841FFFFFFFFFF00045AAB9000D1 データ 内容 値 :charヘッダ(固定値) :00uint8送信元の論理デバイスID 0x00 親機A0uint8コマンド番号(固定値) 0xA0CDuint8応答ID 0xCD82036841uint32送信元の拡張アドレス 0x82036841FFFFFFFFuint32送信先の拡張アドレス 0xFFFFFFFF なしFFuint8LQI 255/2550004uint16続くデータの長さ 4バイト5AAB9000[uint8]送信されたデータ 0x5A 0xAB 0x90 0x00D1uint8チェックサム(LRC) 0xD1charフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
:DBA1... の書式についても、
マニュアル をご覧ください。
4. 子機側から送信 まず、以下の系列をコピーします。
上記の系列は、次の内容を指します。
データ 内容 値 :charヘッダ(固定値) :00uint8送信先の論理デバイスID 0x00 親機A0uint8コマンド番号(固定値) 0xA0CDuint8任意の応答ID 0xCDFFuint8オプション なし0xFF5AAB9000[uint8]送信するデータ 0x5A 0xAB 0x90 0x00FFuint8チェックサム(LRC) 0xFFcharフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
次に、子機側の画面を選択します。
最後に、Alt+V/⌘+Vを押してペーストし、Enterを押します。親機側の画面へ反映されます。
子機側から送信
上記における受信側の系列は、以下のように解釈できます。
:01A0CD820163B2FFFFFFFFFF00045AAB900066 データ 内容 値 :charヘッダ(固定値) :01uint8送信元の論理デバイスID 0x01 子機A0uint8コマンド番号(固定値) 0xA0CDuint8応答ID 0xCD820163B2uint32送信元の拡張アドレス 0x820163B2FFFFFFFFuint32送信先の拡張アドレス 0xFFFFFFFF なしFFuint8LQI 255/2550004uint16続くデータの長さ 4バイト5AAB9000[uint8]送信されたデータ 0x5A 0xAB 0x90 0x0066uint8チェックサム(LRC) 0x66charフッタ(改行文字) CR (0x0D/\r) charフッタ(改行文字) LF (0x0A/\n)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
:DBA1... の書式についても、
マニュアル をご覧ください。
書式モード(バイナリ) 書式モード(バイナリ)を使用して、バイナリデータ 0x5A 0xAB 0x90 0x00 を双方から送信してみましょう。
Saab 9000 CD 2.3
以降、バイナリデータ表現の 0x を省略します。
例えば、0x5A 0xAB 0x90 0x00 は 5A AB 90 00 と表します。
設定方法 m:通信モード をBとします。
片方の端末のi:論理デバイスID を0(親機)としたうえで、もう片方の端末は1(子機、ID1)とします。
バイナリへ対応した環境を用意 TWELITE STAGE アプリのターミナル機能や TeraTerm はバイナリデータの扱いに対応していないため、バイナリ形式に対応したターミナルソフトを導入する必要があります。
ここでは、一例としてCoolTermを使用します。
通信テスト(簡易形式) まずは、簡易形式のシンプルな書式を試してみましょう。
1. CoolTerm の画面を2つ開く CoolTerm の画面を2つ開き、それぞれのデバイスへ接続します。
設定について Options > Terminal > Terminal Mode を Raw Modeとしたうえで、Options > Transmit > Send String Options > Terminate 'Send String' Data のチェックを外してください。
設定の詳細については、STAGEアプリを使わずにUART通信する のページをご覧ください。
受信したデータを16進数で表示するために、View > View Hex を選択しておきます。Connect を押して接続します。
2つの画面を開いた様子
2. 親機側から送信 親機側の画面を選択し、Connection > Send String... を選択して送信画面を開き、ラジオボタンのHex を選んでおきます。
送信画面を開いた様子
次の内容を入力し、Send を押して親機へ送信します。
A5 5A 80 06 01 23 5A AB 90 00 43 04
上記の系列は、次の内容を指します。
データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8006uint16データ長 6バイト01uint8送信先の論理デバイスID 0x01 子機23uint8任意のコマンド番号 0x235AAB9000[uint8]送信するデータ 5A AB 90 0043uint8チェックサム(XOR) 0x4304uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
親機側から送信
上記における受信側の系列は、以下のように解釈できます。
A5 5A 80 06 00 23 5A AB 90 00 42 04 データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8006uint16データ長 6バイト00uint8送信元の論理デバイスID 0x00 親機23uint8コマンド番号 0x235AAB9000[uint8]送信されたデータ 5A AB 90 0042uint8チェックサム(XOR) 0x4204uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
A5 5A 80 04 DBA1... の書式についても、
マニュアル をご覧ください。
3. 子機側から送信 親機と同様に子機側の画面を選択し、Connection > Send String... を選択して送信画面を開き、ラジオボタンのHex を選んでおきます。
次の内容を入力し、Send を押して親機へ送信します。
A5 5A 80 06 00 23 5A AB 90 00 42 04
上記の系列は、次の内容を指します。
データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8006uint16データ長 6バイト00uint8送信先の論理デバイスID 0x00 親機23uint8任意のコマンド番号 0x235AAB9000[uint8]送信するデータ 5A AB 90 0042uint8チェックサム(XOR) 0x4204uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
子機側から送信
上記における受信側の系列は、以下のように解釈できます。
A5 5A 80 06 01 23 5A AB 90 00 43 04 データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8006uint16データ長 6バイト01uint8送信元の論理デバイスID 0x01 子機23uint8コマンド番号 0x235AAB9000[uint8]送信されたデータ 5A AB 90 0043uint8チェックサム(XOR) 0x4304uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
A5 5A 80 04 DB A1... の書式についても、
マニュアル をご覧ください。
通信テスト(拡張形式) 次に、拡張形式の高度な書式を試してみましょう。
1. CoolTerm の画面を2つ開く CoolTerm の画面を2つ開き、それぞれのデバイスへ接続します。
設定について Options > Terminal > Terminal Mode を Raw Modeとしたうえで、Options > Transmit > Send String Options > Terminate 'Send String' Data のチェックを外してください。
設定の詳細については、STAGEアプリを使わずにUART通信する のページをご覧ください。
受信したデータを16進数で表示するために、View > View Hex を選択しておきます。Connect を押して接続します。
2つの画面を開いた様子
2. 親機側から送信 親機側の画面を選択し、Connection > Send String... を選択して送信画面を開き、ラジオボタンのHex を選んでおきます。
送信画面を開いた様子
次の内容を入力し、Send を押して子機へ送信します。
A5 5A 80 08 01 A0 CD FF 5A AB 90 00 F2 04
上記の系列は、次の内容を指します。
データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8008uint16データ長 8バイト01uint8送信先の論理デバイスID 0x01 子機A0uint8コマンド番号(固定値) 0xA0CDuint8任意の応答ID 0xCDFFuint8オプション なし0xFF5AAB9000[uint8]送信するデータ 0x5A 0xAB 0x90 0x00F2uint8チェックサム(XOR) 0xF204uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
親機側から送信
上記における受信側の系列は、以下のように解釈できます。
A5 5A 80 12 00 A0 CD 81 0E 0E 23 FF FF FF FF BA 00 04 5A AB 90 00 10 04 データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8012uint16データ長 18バイト00uint8送信元の論理デバイスID 0x00 親機A0uint8コマンド番号(固定値) 0xA0CDuint8応答ID 0xCD810E0E23uint32送信元の拡張アドレス 0x810E0E23FFFFFFFFuint32送信先の拡張アドレス 0xFFFFFFFF なしBAuint8LQI 186/2550004uint16続くデータの長さ 4バイト5AAB9000[uint8]送信されたデータ 0x5A 0xAB 0x90 0x0010uint8チェックサム(XOR) 0x1004uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
A5 5A 80 04 DB A1... の書式についても、
マニュアル をご覧ください。
3. 子機側から送信 親機と同様に子機側の画面を選択し、Connection > Send String... を選択して送信画面を開き、ラジオボタンのHex を選んでおきます。
次の内容を入力し、Send を押して親機へ送信します。
A5 5A 80 08 00 A0 CD FF 5A AB 90 00 F3 04
上記の系列は、次の内容を指します。
データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8008uint16データ長 8バイト00uint8送信先の論理デバイスID 0x00 親機A0uint8コマンド番号(固定値) 0xA0CDuint8任意の応答ID 0xCDFFuint8オプション なし0xFF5AAB9000[uint8]送信するデータ 0x5A 0xAB 0x90 0x00F3uint8チェックサム(XOR) 0xF304uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
子機側から送信
上記における受信側の系列は、以下のように解釈できます。
A5 5A 80 12 01 A0 CD 81 0E 00 92 FF FF FF FF BA 00 04 5A AB 90 00 AE 04 データ 内容 値 A5uint8ヘッダ(固定値) 0xA55Auint8ヘッダ(固定値) 0x5A8012uint16データ長 18バイト01uint8送信元の論理デバイスID 0x01 子機A0uint8コマンド番号(固定値) 0xA0CDuint8応答ID 0xCD810E0092uint32送信元の拡張アドレス 0x820163B2FFFFFFFFuint32送信先の拡張アドレス 0xFFFFFFFF なしBAuint8LQI 186/2550004uint16続くデータの長さ 4バイト5AAB9000[uint8]送信されたデータ 0x5A 0xAB 0x90 0x00AEuint8チェックサム(XOR) 0xAE04uint8フッタ EOT (0x04)
書式の詳細はマニュアル をご覧ください。
入力側の応答メッセージ
A5 5A 80 04 DB A1... の書式についても、
マニュアル をご覧ください。
1.5 - リモコンアプリによる高度なデジタル伝送 リモコンアプリを使用して、デジタル信号に特化した高度な機能を使用する
ファームウェアを超簡単!標準アプリ(App_Twelite)からリモコンアプリ(App_IO)へ書き換えることで、デジタル信号に特化した高度な機能を使用することができます。
リモコンアプリを使用して、デジタル信号の伝送に特化した高度な機能を利用します。例えば、子機の入力を12系統へ増やします。
使用する製品 リモコンアプリ TWELITE のファームウェアを、デジタル信号の伝送に特化したリモコンアプリ(App_IO)へ書き換えます。超簡単!標準アプリはデジタル信号の伝送機能を備えているものの、入出力は4本に限られています。リモコンアプリは入出力を増やし、その組み合わせを切り替えることができます。
ファームウェアの書き換え 親機と子機、すべての端末を書き換えます。
TWELITE STAGE SDK を導入 し、TWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「2: アプリ書換 」を選択する 「1: BINから選択 」を選び、App_IO... を選択する 書き込みが完了するまで、数回Enterを押す
初期設定では、書き込みが成功すると次のようなインタラクティブモード の画面へ移行します。
--- CONFIG/APP_IO V1-03-2/SID=0x86300001/LID=0x00 ---
a: set Application ID (0x67720107)
i: set Device ID (--)
c: set Channels (16)
x: set Tx Power (3)
t: set mode4 sleep dur (1000ms)
y: set mode7 sleep dur (0s)
f: set mode3 fps (16)
d: set hold mask (000000000000)
D: set hold dur (1000ms)
o: set Option Bits (0x00000000)
b: set UART baud (38400)
p: set UART parity (N)
C: set crypt mode (0)
K: set crypt key []
---
S: save Configuration
R: reset to Defaults まずは使ってみる 初期状態のリモコンアプリは、次のように子機が12本のデジタル入力ポートを、親機が12本のデジタル出力ポートを備えた片方向伝送の設定 としています。まずは配線してみましょう。
名称 子機 親機 標準 DIP # I1/O5I1O5DI115 I2/O6I2O6DI216 I3/O7I3O7DI317 I4/O8I4O8DI418 I5/O1I5O1DO15 I6/O2I6O2DO28 I7/O3I7O3DO39 I8/O4I8O4DO412 I9/O9I9O9SCL2 I10/O10I10O10SDA19 I11/O11I11O11PWM14 I12/O12I12O12PWM411
親機の配線 初期状態のとき、親機は最大12本のデジタル信号を受信できます。
親機の配線図
上図では DIP 9番 O3 ピンを出力として使用していますが、他のOxピンも同様に使用できます。また、超簡単!標準アプリにはないチャネル上書き機能 を検証するため、DIP 23番 C1 ピンへタクトスイッチを接続しています。
子機の配線 初期状態のとき、子機は最大12本のデジタル信号を送信できます。
子機の配線図
上図では DIP 17番 I3 ピンを入力として使用していますが、他のIxピンも同様に使用できます。また、こちらも同様にチャネル上書き機能 を検証するため、DIP 23番 C1 ピンへタクトスイッチを接続しています。
動作確認 子機のI3へ接続したボタンを押したり離したりします親機のO3へ接続した LED が点灯したり消灯したりします。 子機のC1へ接続したボタンを押しながら、I3 のボタンを押したり離したりします 親機と子機のC1へ接続したボタンを押しながら、子機のI3へ接続したボタンを押したり離したりします親機と子機の周波数チャネルを両方とも上書きするため、再び通信できるようになります。
C1/C2ピンは、次のように周波数チャネルを上書きします。
ボタンと LED に余りがあれば、入出力を増やしてみましょう。
12系統あるため、例えば 7セグメント LED を使用できます。
高度な機能を使ってみる 次のようなシチュエーションを想定して、インタラクティブモードによる設定変更を行ってみましょう。
子機と親機の入出力の割り当てを変更し、双方とも6入力6出力とする 子機の入力を最短で親機へ反映する パケットが断絶した際に出力信号を復帰させる 子機を省電力リモコンとする 子機を長押しによる連続送信へ対応した省電力リモコンとする 子機と親機を6入力6出力とする インタラクティブモードからオプションビット の値を変更することで、入出力の割り当てを下記のなかから選ぶことができます。
ここでは、双方とも6入力6出力としてみましょう。
TWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00002000 を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了これで次のように、子機と親機がともに6本の入出力をもつ割り当て となります。
名称 子機 親機 標準 DIP # I1/O5I1I1DI115 I2/O6I2I2DI216 I3/O7I3I3DI317 I4/O8I4I4DI418 I5/O1O1O1DO15 I6/O2O2O2DO28 I7/O3O3O3DO39 I8/O4O4O4DO412 I9/O9O5I5SCL2 I10/O10O6I6SDA19 I11/O11I5O5PWM14 I12/O12I6O6PWM411
超簡単!標準アプリと比較して、2本ずつデジタル信号を多く扱えます!
子機の入力を最短で親機へ反映する 子機の連続モード を使用するとき、子機の入力から親機の出力までに通常は 30-70ms 程度の遅延が発生します。すばやい応答が必要とされる場面では、この遅延を小さくするためにインタラクティブモードからオプションビット0x00000001:低レイテンシモード を設定します。
子機の設定 TWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00000001 を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了
ほぼ同時に複数の入力が変化した際は、順番に送信します。そのため、次に処理される入力は遅延してしまうことに注意してください。
また、入力にチャタリングが発生した場合、そのまま出力へ反映されてしまう場合があることにも注意してください。
低レイテンシモードを子機の間欠モード へ適用したときの振る舞いは、連続モードと異なります。
割り込みから起床した際は、対象の割り込みポートの値だけを送信します あるポートを割り込み起床ピンとして利用し、起床した際に他のポートの状態を同時に読むことはできません スリープから復帰した際は、IOポートの状態を通常の1/4の時間で確定させます
チャタリングのあるボタンではなく、センサのデジタル出力を送信する用途に適しています!
パケットの断絶時に信号を復帰させる いずれかの入力がLoの状態のまま電波が途切れた場合には、実際の入力がLoからHiへ戻っても出力はLoを維持します。
パケットが断絶した際に信号を元の状態へ戻すには、リモコン長押しモード を適用します。リモコン長押しモードでは、送信側の入力が変化してからしばらくの間、継続的に信号を送信します。受信側では、Lo 状態を示すパケットが断絶してから一定の時間が経過すると、タイムアウトして出力を Hi へ戻します。
子機の設定 M1/M2/M3を開放し、子機:連続モード を設定するTWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00000100 を入力してEnterを押下するd(小文字)を入力し、ホールド/長押しモードの対象 (000000001010ならI2とI4、長押し時に連続送信するポート)を入力してEnterを押下するD(大文字)を入力し、ホールド/長押しモードの時間 (すべての入力がLoからHiへ戻ったあとに送信を続ける時間)を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了親機の設定 M1/M2/M3を開放し、子機:連続モード を設定するTWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00000100 を入力してEnterを押下するd(小文字)を入力し、ホールド/長押しモードの対象 (000000001010ならO2とO4、断絶時にタイムアウトするポート)を入力してEnterを押下するD(大文字)を入力し、ホールド/長押しモードの時間 (Loの信号が途切れてからHiへ戻すまでの時間)を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了
リモコンからモータを遠隔制御するような用途に適しています!
子機を省電力リモコンとする 子機を電池で駆動させる場合には、スリープと起床を繰り返す間欠モード が有効です。低レイテンシモード およびホールドモード を併用することで、子機のボタンを押した際に親機の出力を設定した時間にわたって維持する動作を実現できます。
子機の設定 M1/M2/M3をGNDへ接続し、子機:間欠10秒モード を設定するTWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00000001 を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了親機の設定 M1/M2/M3を開放し、子機:連続モード を設定するTWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するd(小文字)を入力し、ホールド/長押しモードの対象 (000000001010ならO2とO4、ホールドするポート)を入力してEnterを押下するD(大文字)を入力し、ホールド/長押しモードの時間 (ホールドする時間)を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了
ホールド/長押しモードの時間 は、リモコンの要件に合わせてください。例えば、ボタンが押されたときにランプを一定時間光らせるなら3000ミリ秒といった長めの時間、頻繁にボタンを操作する場合は50ミリ秒といったの短めの時間がよいでしょう。
省電力性能に優れたリモコンから LED を遠隔制御するような用途に適しています!
子機を長押し省電力リモコンとする 子機を電池で駆動させる場合には、スリープと起床を繰り返す間欠モード が有効です。低レイテンシモード およびリモコン長押しモード を併用することで、子機のボタンを押している間に親機への送信を連続的に行うことができます。また、子機のボタンを離したあとに一定の時間にわたって送信を続け、親機側では子機のボタンを押した状態の電波が途切れてから一定の時間が経過した場合に出力を元に戻します。このため、省電力性能に優れた子機の入力をより確実に親機へ届けることができます。
子機の設定 M1/M2/M3をGNDへ接続し、子機:間欠10秒モード を設定するTWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00000103(00000100 +00000001 +00000002 ) を入力してEnterを押下するd(小文字)を入力し、ホールド/長押しモードの対象 (000000001010ならI2とI4、長押し時に連続送信するポート)を入力してEnterを押下するD(大文字)を入力し、ホールド/長押しモードの時間 (すべての入力がLoからHiへ戻ったあとに送信を続ける時間)を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了親機の設定 M1/M2/M3を開放し、子機:連続モード を設定するTWELITE STAGE アプリ を立ち上げるシリアルポート選択 から接続したデバイスを選択する「メインメニュー 」から「3: インタラクティブモード 」を選択する Enterを押し、設定項目 が表示されることを確認するo(小文字)を入力し、オプションビットの値 00000100 を入力してEnterを押下するd(小文字)を入力し、ホールド/長押しモードの対象 (000000001010ならO2とO4、断絶時にタイムアウトするポート)を入力してEnterを押下するD(大文字)を入力し、ホールド/長押しモードの時間 (Loの信号が途切れてからHiへ戻すまでの時間)を入力してEnterを押下するS(大文字)を入力して保存し、ESCを押下して終了
省電力性能に優れたリモコンからモータを遠隔制御するような用途に適しています!
2 - TWELITE STICK USBドングルでTWELITEをPCを連携させる
USBドングル TWELITE STICK は、TWELITE の本体とアンテナ、TWELITE R3 の機能を一つのケースに収めた製品です。MONOSTICK シリーズの後継として、TWELITE と PC を連携させたいときに活躍します。
TWELITE STICK
USBドングル TWELITE STICK は、TWELITE の本体とアンテナに、USB アダプター TWELITE R シリーズの機能を組み合わせた製品です。
TWELITE STICK の構成
ほかの TWELITE から受信したデータを PC へ送信したり、PC から受信したデータをほかの TWELITE へ送信したり、USB 電源に接続して TWELITE のパケットを中継することもできます。
MONOSTICK との違い TWELITE STICK は従来製品の MONOSTICK と同じパケットを扱うことができ、上位互換に相当します。
一般的な USB メモリと遜色ない大きさに小型化したことで、隣の USB ポートとの干渉を起こしづらくなっています。
MONOSTICK と TWELITE STICK の大きさの比較
また、TWELITE 本体を第二世代の GOLD シリーズ としたことで、従来の RED シリーズよりも受信待機時の消費電流を約10mA削減しながら、同等の送信出力と僅かに上回る受信感度を実現しました。
TWELITE STICK の受信待機→送信時の消費電流 (再送4回中継、LED無効)
MONOSTICK RED の消費電流の受信待機→送信時の消費電流 (再送4回中継)
TWELITE BLUE / RED / GOLD シリーズの無線パケットは互換性があり、相互に通信できます。
TWELITE APPS 工場出荷時の TWELITE STICK には TWELITE APPS 統合版 をインストールしています。TWELITE APPS 統合版は、TWELITE GOLD シリーズのプログラム容量を活かして、従来の機能を一つのファームウェアに収めたものです。
インタラクティブモードの操作 を行うことで、ファームウェアの書き換えを行わずに、これらの機能を瞬時に切り替えて使うことができます。一部のアプリでは、状態に応じてロゴマークの点灯色が変化するほか、パケットの受信を受けて点滅します。
初期状態では MONOSTICK と同様に、親機モードの
親機・中継機アプリ (点灯色:🩷)が動作します。
シンプルな無線通信 TWELITE は、起動直後から通信できます。Bluetooth のようなペアリングを行いません。
周波数チャネルを合わせた端末同士で同報通信を行います。したがって、同一の周波数チャネルでは、同時に複数の端末が送信を行うことはできません。自分宛でないパケットは無視します。トランシーバやインカムの動作をイメージすると分かりやすいかもしれません。
親機や中継機は、同じ周波数チャネルの端末から送信されるパケットを待ち受けます。
無線通信の規格は? TWELITE は 2.4GHz 帯の電波を使用する無線モジュールですが、Bluetooth (IEEE 802.15.1) とは異なる規格の IEEE 802.15.4 へ準拠しています。
IEEE 802.15.4 へ準拠した他の製品には Zigbee モジュールがありますが、TWELITE は Zigbee モジュールではありません 。Zigbee モジュールは IEEE 802.15.4 の上層に Zigbee プロトコルスタックを採用していますが、TWELITE はシンプルな独自のプロトコルスタックを代わりに実装しています。
データ量の多い通信には適していないものの、単純な信号伝送といった用途には最適です。
2.1 - TWELITE STAGE APP による動作確認と設定 TWELITE STAGE APP を使って通信動作の確認や設定変更を行う方法
評価開発環境 TWELITE STAGE SDK に含まれる TWELITE STAGE APP を使うことで、通信動作の確認や設定変更を行うことができます。
このページの内容の多くは、MONOSTICK シリーズにも適用できます。
基本的な動作確認 TWELITE STICK を接続 PC の USB ポートに TWELITE STICK を接続してください。
工場出荷時の TWELITE は、親機・中継機アプリ の親機モードに設定されています。TWELITE シリーズの子機との間で送受信を行うことができ、ロゴマークはマゼンタに光るはずです。
工場出荷時の様子
起動メッセージを確認 TWELITE STICK の動作を確かめるために、まずは起動時に出力されるメッセージを確認してください。
TWELITE STICK は、115200bps / 8-N-1 の UART 通信により、PC との通信を行います。
TWELITE STICK を接続した状態で、MWSTAGEフォルダ内のTWELITE_Stageを実行します。シリアルポート選択の画面に、TWELITE STICKが表示されます。
シリアルポート選択
TWELITE STICK が表示されない場合は、FTDI D2XX ドライバ のインストールをお試しください。
Windowsの場合は、デバイスマネージャにCOMポートとして表示されます。それ以外の場合は、/dev/tty*に表示されます。
TWELITE STICK を選択すると、メインメニューに移行します。
メインメニュー
ビューアを選択すると、ビューア選択のメニューに移行します。
ビューア
前の画面に戻るには、画面の左下を長押しするか、ESCキーを押してください。
ターミナル を選択すると、一般的なターミナルソフトと同様に VT-100 互換のターミナル画面を表示します。
ターミナル画面
初期状態では、上記のように TWELITE STICK が受信したパケットのデータを出力しているかもしれません。
右下にあるファーム書換/リセットを長押しして、TWELITE をリセットしてください。
右下を長押しでリセット
起動メッセージが出力されます。
起動メッセージの出力例
上記の例では、次のメッセージを出力しています。
!INF MW APP_WINGS(Parent) v1-03-2, SID=0x8300051A このように !INF MW APP_WINGS(Parent) と表示されていれば、親機・中継機アプリ(App_Wings)の親機モードが動作していることが分かります。
TWELITE STICK の正常起動を確認できました!
TWELITE DIP の子機と通信 ここでは、TWELITE DIP の子機との通信動作を確認する方法をご紹介します。
TWELITE DIP は、工場出荷時に書き込まれている 超簡単!標準アプリ(App_Twelite) が動作しているものとします。
TWELITE DIP の準備 TWELITE DIP の子機の DI1 と GND の間にスイッチを、DO1 と VCC の間に LED を接続してください。子機は超簡単!標準アプリの端末どうしの通信を確認する場合 と同じ構成です。
子機の配線例
TWELITE DIP の親機の代わりに TWELITE STICK を使うことで、ボタンの状態を PC 側で検知したり、LED を PC から光らせることができます。
TWELITE STICK の接続 TWELITE STICK を PC の USBポートに接続してください。
親機・中継機アプリの親機モードに設定されていれば、マゼンタに光ります。
親機モードの待機状態
端末の設定 端末の設定変更は不要です。工場出荷時の状態のまま、すぐに通信を開始できます。
しかし、ここでは念のため設定値を確認しておきましょう。
TWELITE シリーズの設定変更を UART 通信によって行うには、端末をインタラクティブモード で起動します。TWELITE STAGE APP には、インタラクティブモードを扱うための機能があります。
メインメニューからインタラクティブモードを選択します。
メインメニュー
次の画面では、任意の場所をクリックするかEnterキーを押すことで次に進みます。
確認画面
以下のような画面が表示されたら成功です。
インタラクティブモード
物理的にネットワークを分離する周波数チャネル の値が18、論理的にネットワークを分離するアプリケーションID の値が67720102となっていれば、工場出荷時の TWELITE DIP と通信できます。
インタラクティブモードの操作方法
左側のIDを入力することで、各項目の値を編集できます(アプリケーションIDならa) 項目を選択したら、値を入力してEnterキーを押して確定するか、ESCキーでキャンセルします 入力した設定はSキーを押すことで適用できます すべての設定を初期状態に戻すには、Rキーを押して値をリセットしたのち、Sキーで適用します 設定項目の詳細については、親機・中継機アプリ(App_Wings)の資料 をご覧ください。
ロゴマークの点灯 TWELITE STICK を PC に接続した状態で、TWELITE DIP の DI1 に接続したスイッチを押してください。
正常に動作していれば、ボタンを押している間はより明るく、赤色に光ります。
DI1を押すと赤く点灯する
もしDI2にスイッチを接続したなら、TWELITE STICK は緑色に光ります。AI1をVCCから切断して 0-2V の電圧を供給すると、DI1やDI2のスイッチを押した際の明るさが変化します。
標準アプリビューア TWELITE STAGE APP には、超簡単!標準アプリの子機から受信したデータを表示する機能があります。
DI1へ接続したスイッチの状態を取得しましょう。
メインメニューからビューアを選択します。
メインメニュー
ビューア選択の画面から、標準アプリ ビューア を選んでください。
ビューア選択
標準アプリビューアの画面では、TWELITE STICK が受信した最新の超簡単!標準アプリからのデータを表示します。
標準アプリビューア
TWELITE DIP の DI1 に接続したスイッチを押すと、D1の項目が赤く光ります。
標準アプリビューアの項目
タイムCT:パケットのタイムスタンプId#:子機の論理デバイスID シリアル番号:子機のシリアルID(本体の缶に刻印)Dx:DIxピンの状態Ax:AIxピンの入力電圧(mV単位、0mV-2000mV)標準アプリコマンダー TWELITE STAGE APP には、超簡単!標準アプリの子機へデータを送信する機能もあります。DO1へ接続した LED を制御してみましょう。
メインメニューからビューアを開きます。
メインメニュー
ビューア選択の画面から、コマンダーを選んでください。
ビューア選択
App_Twelite 0x80コマンド を選びます。
標準アプリのコマンダー
DI1(1)をクリックするか、1キーを押すことでDI1の点灯状態を制御できます。
コマンダーの画面
標準アプリコマンダーの項目
宛先ID:状態変更のデータを送る宛先の端末の論理デバイスIDDIx(x):宛先のDOxピンの状態変更SEL(x):DIx(x)の有効フラグPWMx(x):宛先のPWMxピンのデューティ比の変更送信(SPACE):現在の状態で再送信
TWELITE STICK の設定方法と、TWELITE DIP の子機との通信動作を確認できました!
TWELITE ARIA と通信 ここでは、温湿度センサータグ TWELITE ARIA との通信動作を確認する方法をご紹介します。
TWELITE ARIA は、工場出荷時に書き込まれている アリアアプリ(App_ARIA) が動作しているものとします。
TWELITE ARIA の準備 TWELITE ARIA に CR2032 電池を挿入してください。
CR2032電池を挿入
TWELITE ARIA の親機に TWELITE STICK を使うことで、温湿度や磁石が接近した情報を PC 側で取得できます。
TWELITE STICK の接続 TWELITE STICK を PC の USBポートに接続してください。
親機・中継機アプリの親機モードに設定されていれば、マゼンタに光ります。
親機モードの待機状態
端末の設定 端末の設定変更は不要です。工場出荷時の状態のまま、すぐに通信を開始できます。
物理的にネットワークを分離する周波数チャネル の値が18、論理的にネットワークを分離するアプリケーションID の値が67720102となっていれば、工場出荷時の TWELITE ARIA と通信できます。
ロゴマークの点灯 TWELITE STICK を PC に接続した状態で、TWELITE ARIA のホールセンサに磁石を近づけてください。
正常に動作していれば、TWELITE ARIA は磁石を近づけるたびにパケットを送信し、TWELITE STICK のロゴマークがそれを受けて点滅します。
その他のパケットであっても、同一の周波数チャネルおよびアプリケーションIDのパケットを受信するたびに点滅します。
簡易モニタ TWELITE STAGE APP には、TWELITE ARIA から受信したデータをシンプルに表示する機能があります。
メインメニューからビューアを選択します。
メインメニュー
ビューア選択の画面から、簡易モニタ(CUE/ARIA/Glancer) を選んでください。
ビューア選択
続いて、TWELITE ARIA の簡易モニタ を選択します。
簡易モニタ選択画面
簡易モニタの画面では、TWELITE STICK が受信した最新の TWELITE ARIA のデータを表示します。
簡易モニタ
TWELITE ARIA に磁石を近づけると、新たなパケットが届きます。
簡易モニタの項目
パケット:最新のパケットの情報#:パケットの通し番号(全ての種別が対象)種別:パケットの種別ID(02固定)ID:論理デバイスID AD:シリアルID(本体の缶に刻印)LQ:電波通信品質(LQI、0-255で大きいほど良い)SQ:パケットの通し番号(TWELITE ARIAのデータに基づく)履歴時間:受信時のタイムスタンプ(パケットには含まれない)ID:論理デバイスID VCC(mV):TWELITE ARIA の電源電圧温度(C):温度湿度(%):相対湿度磁石:ホールセンサの判定(なし [N極] [S極]) センサーグラフ TWELITE STAGE APP には、子機から受信した温湿度データなどをグラフとして表示する機能もあります。
メインメニューからビューアを開きます。
メインメニュー
ビューア選択の画面から、グラフ表示(加速度リアルタイム/センサー)を選んでください。
ビューア選択
続いて、センサーグラフ を選択します。
グラフ選択画面
右側のノード一覧から、ARAで始まるものを選択してください。
ノード選択
初期状態では、24時間分のデータが表示されます。直近のデータを確認するために、[ライブ>>]をクリックしてください。
24時間データ
直近のデータが表示されます。磁石を近づける、7Pインタフェース近くのセンサを温めるなどして、値が変化する様子を確認してください。
ライブデータ
TWELITE ARIA との通信動作を確認できました!
2.2 - Python による子機との通信(基本編) Python を使って子機との通信を行う方法
専用のライブラリを使うことで、Python から TWELITE STICK を通して TWELITE の子機と通信することができます。
このページの内容の多くは、MONOSTICK シリーズにも適用できます。
基本的な動作確認 TWELITE STICK を接続 PC の USB ポートに TWELITE STICK を接続してください。
工場出荷時の TWELITE は、親機・中継機アプリ の親機モードに設定されています。TWELITE シリーズの子機との間で送受信を行うことができ、ロゴマークはマゼンタに光るはずです。
工場出荷時の様子
MWings ライブラリの導入 Python 3.12 以降の環境を用意してください。
親機・中継機アプリの出力を解釈するための MWings モジュール を導入します。
MWings モジュールは、ホストへ接続された TWELITE の親機を通じて、TWELITE の子機と通信できます。
親機から受信したデータを解釈して、辞書や JSON のほか pandas データフレームへ変換※ 辞書から生成したコマンドを親機へ送信 ※ Lite 版は pandas に非対応
詳しい導入方法や機能の詳細については、MWings for Python マニュアル をご覧ください。
モダンなPython開発においては、Pythonのバージョンとプロジェクト単位の依存関係の管理が必要とされます。上記のマニュアルでは、pyenv と poetry を使った環境整備の方法を紹介しています。
Raspberry Pi の場合は、Lite 版 の mwingslite モジュール を使用してください。
pandasへの依存を廃したバージョンであり、numpyの競合による問題を避けることができます。データフレームの出力は行えませんが、辞書形式やJSON文字列の出力機能は残しています。
軽量であるため、通常のPCであっても pandas を必要としない場合は、こちらをご利用ください。
データの受信を確認 TWELITE STICK が受信したデータを解釈できることを確認します。
GitHub で公開しているサンプルスクリプト rx_print_json.py を実行してください。
TWELITE STICK が受信した全種類のパケットの内容を、ターミナルに出力される JSON 形式の文字列によって確認できます。
# -*- coding:utf-8 -*-
# Written for Python 3.12
# Formatted with Black
# MWings example: Receive data, print JSON, typed
from zoneinfo import ZoneInfo
import mwings as mw
# Main function
def main () -> None :
# Create a twelite object
twelite = mw. Twelite(mw. utils. ask_user_for_port())
# Use JST for received data
twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Register event handlers
@twelite.on (mw. common. PacketType. APP_ARIA)
def on_app_aria (packet: mw. parsers. app_aria. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_CUE)
def on_app_cue (packet: mw. parsers. app_cue. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_CUE_PAL_EVENT)
def on_app_cue_pal_event (packet: mw. parsers. app_cue_pal_event. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_IO)
def on_app_io (packet: mw. parsers. app_io. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet: mw. parsers. app_twelite. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_PAL_AMB)
def on_app_pal_amb (packet: mw. parsers. app_pal_amb. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_PAL_MOT)
def on_app_pal_mot (packet: mw. parsers. app_pal_mot. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_PAL_OPENCLOSE)
def on_app_pal_openclose (packet: mw. parsers. app_pal_openclose. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_UART_ASCII)
def on_app_uart_ascii (packet: mw. parsers. app_uart_ascii. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. APP_UART_ASCII_EXTENDED)
def on_app_uart_ascii_extended (
packet: mw. parsers. app_uart_ascii_extended. ParsedPacket,
) -> None :
print(packet. to_json(verbose= False , spread= True ))
@twelite.on (mw. common. PacketType. ACT)
def on_act (packet: mw. parsers. act. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
# Start receiving
try :
# Set as daemon thread
twelite. daemon = True
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 )
except KeyboardInterrupt :
# Stop the thread
print("Flushing..." )
twelite. stop()
print("Completed" )
if __name__ == "__main__" :
# Call the main function
main() 例えば、前項のTWELITE STAGE APP の場合 と同様に、工場出荷時の TWELITE DIP(超簡単!標準アプリ)の子機を用意していたなら、次のような出力を確認できるはずです。終了するには Ctrl+C を入力してください。
{
"time_parsed": "2025-07-11T11:45:02.067804+09:00",
"packet_type": "APP_TWELITE",
"sequence_number": 4713,
"source_serial_id": "8201007F",
"source_logical_id": 120,
"lqi": 166,
"supply_voltage": 3254,
"destination_logical_id": 0,
"relay_count": 0,
"periodic": true,
"di_changed_1": false,
"di_changed_2": false,
"di_changed_3": false,
"di_changed_4": false,
"di_state_1": false,
"di_state_2": false,
"di_state_3": false,
"di_state_4": false,
"ai_voltage_1": 2000,
"ai_voltage_2": 2000,
"ai_voltage_3": 2000,
"ai_voltage_4": 2000
}
JSON 文字列の内容 mwings.parsers.app_twelite.ParsedPacket
キー 値 time_parsed受信時刻(デフォルトはUTC, ISO8601形式) packet_typeパケット種別 sequence_numberシーケンス番号(App_Tweliteの場合は時間) source_serial_id送信元シリアルID source_logical_id送信元論理デバイスID lqi電波通信品質(8bit) supply_voltage電源電圧(mV) destination_logical_id送信先論理デバイスID relay_count中継回数 periodic定期送信パケットか否か di_changed各デジタルインタフェースの入力変化の有無 di_state各デジタルインタフェースの入力状態 ai_voltage各アナログインタフェースの入力電圧 mwings_implementationMWings の実装(将来のための情報) mwings_versionMWings のバージョン hostname受信したホストの名称 system_type受信したホストのシステムの種別
spread=Trueの場合は、リスト形式を使わずに _1, _2 といった形で値を分割します。
データを CSV ファイルに記録するサンプル rx_export_csv_durable.py もございます。
コマンドラインツールとして、長期間の受信データの記録にそのまま使うことができて便利です。
python rx_export_csv_durable.py -h
usage: rx_export_csv_durable.py [ -h] [ -v] [ -s]
Log packets from App_Wings to csv, line by line
options:
-h, --help show this help message and exit
-v, --verbose include system information
-s, --sort sort columns in the output 任意のデータを送受信 ここでは、TWELITE STAGE APP の場合 と同様に準備した TWELITE DIP の子機との通信に特化したスクリプトを作成してみましょう。
TWELITE DIP 子機の配線例
TWELITE DIP の DI1 ピンに接続したスイッチの状態表示と、DO1 ピンに接続した LED の制御を目標とします。
超簡単!標準アプリのデータのみ受信 rx_print_json.py を改変し、超簡単!標準アプリのデータだけを受信するように単純化したスクリプトを作成します。
# -*- coding:utf-8 -*-
from zoneinfo import ZoneInfo
import mwings as mw
# Main function
def main () -> None :
# Create a twelite object
twelite = mw. Twelite(mw. utils. ask_user_for_port())
# Use JST for received data
twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Register event handlers
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet: mw. parsers. app_twelite. ParsedPacket) -> None :
print(packet. to_json(verbose= False , spread= True ))
# Start receiving
try :
# Set as daemon thread
twelite. daemon = True
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 )
except KeyboardInterrupt :
# Stop the thread
print("Flushing..." )
twelite. stop()
print("Completed" )
if __name__ == "__main__" :
# Call the main function
main() 特定の値を取得 これまでのスクリプトでは、to_json() メソッドによって、すべてのデータを JSON 文字列として出力していました。
ここでは、DI1ピンの状態だけをparsers.app_twelite.ParsedPacket の di_state から取得し、仮想的なLEDをターミナルに表示します。
on_app_twelite()ハンドラを以下のように書き換えてください。
def on_app_twelite (packet: mw. parsers. app_twelite. ParsedPacket) -> None :
print(f " \r DO1 LED: { "🔴" if packet. di_state[0 ] else "⚪" } " , end= '' , flush= True ) 次のようにして、TWELITE DIP の DI ピンに接続したスイッチを押すたびに赤く光ったら成功です。
表示例
親機にコマンドを送信 TWELITE STICK が受信したデータを表示するだけではなく、TWELITE STICK からデータを送信することもできます。
スクリプトのメインループでは、threading.Thread.join() を0.5秒おきに呼び出すことで、メインスレッドの終了を検知した際に受信スレッドも終了できるようにしています。
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 ) この仕組みを利用して、メインループから TWELITE DIP の DO1 ピンを制御し、0.5秒おきに LED を点滅させてみましょう。
先のスクリプトを、次のように改変してください。これまでの変更も適用した全体を示します。
# -*- coding:utf-8 -*-
from zoneinfo import ZoneInfo
from typing import Any
import mwings as mw
# Main function
def main () -> None :
# Create a twelite object
twelite = mw. Twelite(mw. utils. ask_user_for_port())
# Use JST for received data
twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Register event handlers
@twelite.on (mw. common. PacketType. APP_TWELITE)
def on_app_twelite (packet: mw. parsers. app_twelite. ParsedPacket) -> None :
print(f " \r DO1 LED: { "🔴" if packet. di_state[0 ] else "⚪" } " , end= '' , flush= True )
# Initialize command
initial: dict[str, Any] = {
"destination_logical_id" : 0x78 , # All child devices
"di_to_change" : [True , False , False , False ], # Enable DI1
"di_state" : [False , False , False , False ], # Initial state of DIx
}
command = mw. serializers. app_twelite. Command(** initial)
# Toggle the DI1 state
def toggle_di1 () -> None :
command. di_state[0 ] = not command. di_state[0 ]
twelite. send(command)
# Start receiving
try :
# Set as daemon thread
twelite. daemon = True
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
toggle_di1() # Send
twelite. join(0.5 ) # Receive
except KeyboardInterrupt :
# Stop the thread
print("Flushing..." )
twelite. stop()
print("Completed" )
if __name__ == "__main__" :
# Call the main function
main() このスクリプトを実行すると、先ほどと同様に仮想的なLEDを表示します。
表示例
その一方で、TWELITE DIP の DO1 ピンに接続した LED は点滅し続けるはずです。スクリプトを終了すると、点滅は止まります。
パケットの受信とコマンドの送信は、非同期に扱うことができます。
2.2.1 - Python による子機との通信(ウェブサーバIoT編) Python を使って子機のデータをウェブサーバへ送信する
実用に近い応用編として、ウェブサーバを利用した IoT システムを構築します。
このページの内容は、MONOSTICK シリーズにも適用できます。
TWELITE ARIA の温湿度データを収集 温湿度センサータグ TWELITE ARIA から受信した温湿度データをウェブサーバへ送信し、ページ上のグラフに表示する簡単な IoT システムを構築してみましょう。
ThingSpeakの表示例
TWELITE DIP を対象とした基本編のスクリプト では DI1 と DO1 の簡単な操作に留めましたが、実際の IoT システムでは、REST API などを利用して、取得したデータをさらに上位のサーバへ送信する必要があります。
ThingSpeak について ここでは、MathWorks のサービス ThingSpeak と MWings ライブラリ を組み合わせて使います。
ThingSpeak は、MATLAB や Simulink の MathWorks が公開する IoT 分析サービスです。
2025年7月現在、一定未満のデータ量かつ商用サービスに利用しない限りは無料で使用できます。
アカウントの作成 ThingSpeak のサイト へアクセスし、MathWorks のアカウントを作成します。
Channel の作成 “Channel” を作成し、次のように設定します(“Name"や"Description"は適当で構いません)
Channelの設定例
フィールド番号を指定して送信するため、Field x の順番が重要です。
API Keys の取得 Channel ページの “API Keys” タブに移動し、16文字の “Write API key” を控えておきます。
TWELITE ARIA の設定と起動 TWELITE ARIA の設定変更 TWELITE ARIA の設定を変更 し、TWELITE ARIA モード の送信間隔 を20秒以上とします(サーバへの過負荷を避けるため)。
TWELITE ARIA の設定を変更するには、2通りの手段があります。
前者は TWELITE R2/R3 を必要としない反面、後者は作業をスムーズに行えます。
TWELITE ARIA の起動 CR2032 電池を投入し、TWELITE ARIA を起動します。
CR2032電池を挿入
スクリプトの作成と実行 モジュールの導入 Python 3.12 以降と mwings(またはmwingslite)およびrequests モジュールを導入します。
pip install mwings requests スクリプトの作成 後述のスクリプト stick_aria_thingspeak.py を作成してください。mwings.parsers.app_aria を使ってデータを受信し、requestsモジュールを使って ThingSpeak へ HTTP GET リクエストを送信します。
冒頭の API_KEY を先ほど控えたものに置き換える必要があります。
# -*- coding:utf-8 -*-
from zoneinfo import ZoneInfo
from time import perf_counter
import mwings as mw
import requests
API_KEY = "XXXXXXXXXXXXXXXX" # Replace with your ThingSpeak API key
BASE_URL = "https://api.thingspeak.com/update"
SEND_MIN_INTERVAL = 20 # Minimum interval in seconds to send data to ThingSpeak
# Main function
def main () -> None :
# Create a twelite object
twelite = mw. Twelite(mw. utils. ask_user_for_port())
# Use JST for received data
twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Initialize last send time
last_send_time = perf_counter() - SEND_MIN_INTERVAL
# Initialize the target serial ID
target_serial_id = - 1
# Register event handlers
@twelite.on (mw. common. PacketType. APP_ARIA)
def on_app_aria (packet: mw. parsers. app_aria. ParsedPacket) -> None :
# Filter packets by serial ID
if target_serial_id < 0 :
# Set the serial ID from the received packet
target_serial_id = packet. source_serial_id
print(f "Serial ID set to { target_serial_id: 08X } " )
elif packet. source_serial_id != target_serial_id:
# Ignore packets from other serial ID devices
print(
f "Ignoring packet from serial ID { packet. source_serial_id: 08X } , expected { target_serial_id: 08X } "
)
return
# Throttle sending to ThingSpeak
if perf_counter() - last_send_time < SEND_MIN_INTERVAL:
print("Skipping send due to minimum interval" )
return # Skip sending if within the minimum interval
last_send_time = perf_counter() # Update last send time
# Send data to ThingSpeak
payload = {
"api_key" : API_KEY,
"field1" : f " { packet. temp_100x / 100.0 : .2f } " , # Temperature
"field2" : f " { packet. humid_100x / 100.0 : .2f } " , # Humidity
"field3" : f " { packet. supply_voltage} " , # Supply voltage (mV)
"field4" : f " { packet. lqi} " , # Link Quality Indicator
}
response = requests. get(BASE_URL, params= payload)
# Check the response status
if response. status_code == 200 :
print(f "OK: entry ID = { response. text} " )
else :
print(f "NG: status code = { response. status_code} " )
# Start receiving
try :
# Set as daemon thread
twelite. daemon = True
# Start the thread, Join to the main thread
twelite. start()
print("Started receiving" )
while True :
twelite. join(0.5 ) # Receive
except KeyboardInterrupt :
# Stop the thread
print("Flushing..." )
twelite. stop()
print("Completed" )
if __name__ == "__main__" :
# Call the main function
main() スクリプトの実行 スクリプトを実行します。
python stick_aria_thingspeak.py TWELITE ARIA からのデータを受信し、正常にデータを送信できたなら、次のようにして値の続き番号を示す Entry ID が表示されます。
Started receiving
Serial ID set to 8201C2DC
OK: entry ID = 1
OK: entry ID = 2
OK: entry ID = 3
OK: entry ID = 4
OK: entry ID = 5
... ThingSpeak の “Private View” タブをクリックしてください。送信されたデータがグラフに表示されるはずです。
初期状態では、Y軸の範囲が動的に変化します。各グラフの✏️ボタンから最大最小値などを設定できます。
例えば、TWELITE の
動作電圧 に応じて、Field 3 Chart の
Y-Axis Min や
Y-Axis Max を設定することができます。
約2日分のデータを表示する様子
ウェブサーバと連携する、簡単な IoT システムを構築できました!
スクリプトの解説
送受信のフィルタ処理
サーバへの過負荷を避けるため、SEND_MIN_INTERVALの間隔を空けて送信します 複数の端末データの混在を防ぐため、最初の端末のシリアルIDを対象とします サーバへ送信するデータは、次の部分で構成しています。
# Send data to ThingSpeak
payload = {
"api_key" : API_KEY,
"field1" : f " { packet. temp_100x / 100.0 : .2f } " , # Temperature
"field2" : f " { packet. humid_100x / 100.0 : .2f } " , # Humidity
"field3" : f " { packet. supply_voltage} " , # Supply voltage (mV)
"field4" : f " { packet. lqi} " , # Link Quality Indicator
}
response = requests. get(BASE_URL, params= payload) mwings.parsers.app_aria から温湿度とコイン電池の電源電圧、0-255の数値で表現される電波通信品質(LQI)を取得し、文字列に変換したうえで GET リクエストのクエリとしています。
2.2.2 - Python による子機との通信(グラフィカルUI編) Python を使って子機と通信するためのグラフィカルUIを備えたアプリケーションを構築する
実用に近い応用編として、簡単なグラフィカルインタフェースを備えたアプリケーションを作成します。
このページの内容は、MONOSTICK シリーズにも適用できます。
TWELTIE DIP と通信する TWELITE DIP と通信するアプリケーションを、簡単なユーザインタフェースとともに構築してみましょう。
画面の表示例
TWELITE DIP を対象とした基本編のスクリプト では DI1 と DO1 の簡単な操作に留めましたが、実際にモニタリングを行うためのアプリケーションは、TWELITE STAGE APP のようなユーザインタフェースを必要とします。
Dear PyGui について ここでは、Dear PyGui と MWings ライブラリ を組み合わせて使います。
Dear PyGui (DPG) は、C++ で書かれた Dear ImGui と OpenGL をベースにしたUIツールキットです。
開発ツールのUIに利用されることが多く、高度なカスタマイズを苦手とする反面、軽量な動作とシンプルな記述を特徴としています。
TWELITE DIP の配線と起動 このアプリケーションでは、TWELITE DIP の DIx や AIx に入力された信号を受信すると同時に、DOx や PWMx へ信号を出力させます。
VCC と GND のほか、以下に示す16のピン を任意に接続してください。
種別 ピン 1 2 3 4 範囲 備考 デジタル入力 DIx#15#16#17#180.0V - VCC 内部プルアップ アナログ入力 AIx#22#23#24#250.0V - 2.0V 超過で無効扱い デジタル出力 DOx#5#8#9#120.0V - VCC LEDカソード接続 PWM出力 PWMx#4#6#7#110% - 100% 電圧はVCCレベル
スクリプトの作成と実行 モジュールの導入 mwings(またはmwingslite)およびdearpygui モジュールを導入します。
pip install mwings dearpygui スクリプトの作成 後述のスクリプト stick_dip_gui.py を作成してください。mwings.parsers.app_twelite を使ってデータを受信し、mwings.serializers.app_twelite を使ってデータを送信する機能をdearpygui経由で提供します。
# -*- coding:utf-8 -*-
from time import perf_counter
from enum import IntEnum, auto
from zoneinfo import ZoneInfo
from typing import Any, Self, final
from types import TracebackType
from pathlib import Path
from collections import deque
import mwings as mw
import dearpygui.dearpygui as dpg # type: ignore
PLOT_UPDATE_INTERVAL = 1.0 / 100 # 100Hz
PLOT_X_LIMIT = 5.0 # 3 seconds
FONT = "Mplus1Code-Medium.otf"
# MARK: MainViewport
@final
class MainViewport :
@final
class State (IntEnum):
"""Application state enumeration."""
IDLE = auto()
CONNECTING = auto()
selected_port: str
twelite: mw. Twelite
command_app_twelite: mw. serializers. app_twelite. Command
pwm_data: dict[int, int]
pwm_plot_data: dict[int, deque[tuple[float, int]]]
last_plot: float
state: State
theme_disabled: int
def __init__(self) -> None :
"""Initialize the main window and prepare all components."""
self. initialize_viewport()
self. create_themes()
self. create_windows()
self. initialize()
self. update_state(self. State. IDLE)
def create_themes (self) -> None :
"""Create a visual theme for disabled UI elements."""
with dpg. theme() as self. theme_disabled:
with dpg. theme_component(dpg. mvAll):
dpg. add_theme_color(dpg. mvThemeCol_Text, (150 , 150 , 150 , 255 ))
dpg. add_theme_color(dpg. mvThemeCol_TextDisabled, (100 , 100 , 100 , 255 ))
dpg. add_theme_color(dpg. mvThemeCol_FrameBg, (5 , 5 , 5 , 255 ))
# MARK: Initialize Viewport
def initialize_viewport (self) -> None :
"""Set up Dear PyGui context, fonts, and viewport."""
dpg. create_context()
with dpg. font_registry():
font_path = str(Path(__file__). parent / FONT)
with dpg. font(file= font_path, size= 18 ) as default_font:
dpg. add_font_range_hint(dpg. mvFontRangeHint_Japanese)
dpg. bind_font(default_font)
dpg. create_viewport(
title= "TWELITE STICK" , width= 620 , height= 440 , resizable= True
)
dpg. set_viewport_vsync(False )
dpg. setup_dearpygui()
dpg. show_viewport()
def create_windows (self) -> None :
"""Create and configure all Dear PyGui windows and their contents."""
# MARK: Panel Window
with dpg. window(
no_title_bar= True ,
no_close= True ,
no_collapse= True ,
no_move= True ,
no_resize= True ,
pos= (10 , 10 ),
width= 600 ,
height= 100 ,
):
ports = mw. utils. get_ports()
with dpg. group(horizontal= True ):
with dpg. child_window(width= 300 ):
dpg. add_text("シリアルポート" )
dpg. add_combo(
items= ports,
default_value= ports[0 ],
tag= "ports_combo" ,
width= 280 ,
enabled= True ,
callback= self. on_select_port,
)
with dpg. child_window(width= 150 ):
dpg. add_text("シリアル通信" )
with dpg. group(horizontal= True ):
dpg. add_button(
label= "接続" ,
tag= "start_button" ,
enabled= True ,
callback= self. on_start,
)
dpg. add_button(
label= "切断" ,
tag= "stop_button" ,
enabled= False ,
callback= self. on_stop,
)
# MARK: Input Window
with dpg. window(
label= "TWELITE DIP 入力" ,
no_close= True ,
# no_resize=True,
pos= (10 , 120 ),
width= 600 ,
height= 160 ,
tag= "window_twelite_dip_input" ,
):
with dpg. group(horizontal= False ):
# DOx
with dpg. group(horizontal= True ):
for p in range(1 , 5 ):
with dpg. group(horizontal= True ):
with dpg. drawlist(
width= 20 , height= 20 , tag= f "indicator_do { p} "
):
dpg. draw_circle(
center= (10 , 10 ),
radius= 10 ,
fill= (0 , 0 , 0 , 255 ),
tag= f "circle_do { p} " ,
)
dpg. add_text(f "DO { p} " )
dpg. add_spacer()
dpg. add_separator()
dpg. add_spacer()
# PWMx
with dpg. group(horizontal= True ):
for p in range(1 , 5 ):
with dpg. plot(
label= f "PWM { p} " ,
height= 80 ,
width= 140 ,
tag= f "plot_pwm { p} " ,
no_frame= True ,
no_mouse_pos= True ,
):
dpg. add_plot_axis(
dpg. mvXAxis,
tag= f "plot_pwm { p} _x" ,
no_tick_labels= True ,
)
with dpg. plot_axis(
dpg. mvYAxis,
tag= f "plot_pwm { p} _y" ,
no_tick_labels= True ,
no_tick_marks= True ,
no_gridlines= True ,
):
dpg. add_line_series(
[],
[],
tag= f "series_pwm { p} " ,
parent= f "plot_pwm { p} _y" ,
)
# MARK: Output Window
with dpg. window(
label= "TWELITE DIP 出力" ,
no_close= True ,
no_resize= True ,
pos= (10 , 290 ),
width= 600 ,
height= 140 ,
tag= "window_twelite_dip_output" ,
):
with dpg. group(horizontal= False ):
# DIx
with dpg. group(horizontal= True ):
for p in range(1 , 5 ):
dpg. add_checkbox(
label= f "DI { p} " ,
tag= f "checkbox_di { p} " ,
enabled= False ,
callback= self. on_check_di,
user_data= p,
)
dpg. add_spacer()
dpg. add_separator()
dpg. add_spacer()
# AIx
with dpg. group(horizontal= False ):
with dpg. group(horizontal= True ):
for p in range(1 , 5 ):
with dpg. group(horizontal= False ):
dpg. add_text(f "AI { p} " )
dpg. add_slider_int(
label= "" ,
width= 80 ,
default_value= 0 ,
min_value= 0 ,
max_value= 2000 ,
tag= f "slider_ai { p} " ,
enabled= False ,
callback= self. on_change_ai,
user_data= p,
)
def update_state (self, new_state: State) -> None :
"""Update the UI and internal state based on the application's current status."""
# MARK: UI State
self. state = new_state
match new_state:
case self. State. IDLE:
dpg. configure_item("ports_combo" , enabled= True )
dpg. configure_item("start_button" , enabled= True )
dpg. configure_item("stop_button" , enabled= False )
for p in range(1 , 5 ):
dpg. configure_item(f "checkbox_di { p} " , enabled= False )
dpg. configure_item(f "slider_ai { p} " , enabled= False )
dpg. bind_item_theme("window_twelite_dip_input" , self. theme_disabled)
dpg. bind_item_theme("window_twelite_dip_output" , self. theme_disabled)
case self. State. CONNECTING:
dpg. configure_item("ports_combo" , enabled= False )
dpg. configure_item("start_button" , enabled= False )
dpg. configure_item("stop_button" , enabled= True )
for p in range(1 , 5 ):
dpg. configure_item(f "checkbox_di { p} " , enabled= True )
dpg. configure_item(f "slider_ai { p} " , enabled= False )
dpg. bind_item_theme("window_twelite_dip_input" , 0 )
dpg. bind_item_theme("window_twelite_dip_output" , 0 )
# MARK: UI Handlers
def on_select_port (self, sender: Any, app_data: str, user_data: Any) -> None :
"""Handle serial port selection from the combo box."""
self. selected_port = app_data
def on_start (self, sender: Any, app_data: str, user_data: Any) -> None :
"""Handle the start button click and initiate communication."""
self. start()
def on_stop (self, sender: Any, app_data: str, user_data: Any) -> None :
"""Handle the stop button click and terminate communication."""
self. update_state(self. State. IDLE)
self. twelite. close()
def on_check_di (self, sender: Any, app_data: bool, user_data: int) -> None :
"""Handle checkbox state changes for DI output control."""
if 1 <= user_data <= 4 :
self. command_app_twelite. di_state[user_data - 1 ] = app_data
self. twelite. send(self. command_app_twelite)
def on_change_ai (self, sender: Any, app_data: int, user_data: int) -> None :
"""Handle slider changes for AI values and send PWM updates."""
if 1 <= user_data <= 4 :
self. command_app_twelite. pwm_duty[user_data - 1 ] = app_data * 1024 // 2000
self. twelite. send(self. command_app_twelite)
# MARK: Packet handler
def on_app_twelite (self, packet: mw. parsers. app_twelite. ParsedPacket) -> None :
"""Update the GUI based on incoming TWELITE DIP packet data."""
now = perf_counter()
for p in range(1 , 5 ):
# DO
p_state = packet. di_state[p - 1 ]
match p:
case 1 : # RED
color = (255 , 0 , 0 , 255 ) if p_state else (0 , 0 , 0 , 255 )
case 2 : # GREEN
color = (0 , 255 , 0 , 255 ) if p_state else (0 , 0 , 0 , 255 )
case 3 : # YELLOW
color = (255 , 255 , 0 , 255 ) if p_state else (0 , 0 , 0 , 255 )
case 4 : # BLUE
color = (0 , 0 , 255 , 255 ) if p_state else (0 , 0 , 0 , 255 )
dpg. configure_item(f "circle_do { p} " , fill= color)
# PWM
self. pwm_data[p] = packet. ai_voltage[p - 1 ]
self. pwm_plot_data[p]. append((now, self. pwm_data[p]))
# MARK: Plot
def update_plot (self) -> None :
"""Update the plot with the latest PWM data."""
now = perf_counter()
# Throttle plot updates to PLOT_UPDATE_INTERVAL
if now - self. last_plot < PLOT_UPDATE_INTERVAL:
return
self. last_plot = now
for p in range(1 , 5 ):
# If no new value was added recently, duplicate the last value
if self. pwm_plot_data[p]:
last_time, last_val = self. pwm_plot_data[p][- 1 ]
if now - last_time > PLOT_UPDATE_INTERVAL:
self. pwm_plot_data[p]. append((now, last_val))
else :
self. pwm_plot_data[p]. append((now, self. pwm_data[p]))
# Remove old values older than PLOT_X_LIMIT
while (
self. pwm_plot_data[p]
and now - self. pwm_plot_data[p][0 ][0 ] > PLOT_X_LIMIT
):
self. pwm_plot_data[p]. popleft()
x_series, y_series = (
zip(* list(self. pwm_plot_data[p])) if self. pwm_plot_data[p] else ([], [])
)
if x_series and y_series:
dpg. set_value(f "series_pwm { p} " , [x_series, y_series])
dpg. set_axis_limits(f "plot_pwm { p} _x" , x_series[0 ], x_series[- 1 ])
dpg. set_axis_limits(f "plot_pwm { p} _y" , 0 , 2000 )
# MARK: Initialize Variables
def initialize (self) -> None :
"""Initialize internal command structure and default values."""
ports = mw. utils. get_ports()
self. selected_port = ports[0 ] # default
command_app_twelite_initial: dict[str, Any] = {
"destination_logical_id" : 0x78 , # All child devices
"di_to_change" : [True , True , True , True ], # Enable DI1-4
"di_state" : [False , False , False , False ], # Initial state of DIx
"pwm_to_change" : [True , True , True , True ], # Enable AI1-4
"pwm_duty" : [0 , 0 , 0 , 0 ], # Initial state of AIx
}
self. command_app_twelite = mw. serializers. app_twelite. Command(
** command_app_twelite_initial
)
self. pwm_data = {1 : 0 , 2 : 0 , 3 : 0 , 4 : 0 }
self. pwm_plot_data = {1 : deque(), 2 : deque(), 3 : deque(), 4 : deque()}
self. last_plot = 0.0
# MARK: Start
def start (self) -> None :
"""Start TWELITE communication and register listeners."""
# Create a twelite object
self. twelite = mw. Twelite(self. selected_port)
# Use JST for received data
self. twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Register event handler(s)
self. twelite. add_listener(mw. common. PacketType. APP_TWELITE, self. on_app_twelite)
self. update_state(self. State. CONNECTING)
# MARK: loop
def loop (self) -> None :
"""Perform periodic updates while the application is running."""
match self. state:
case self. State. IDLE:
pass
case self. State. CONNECTING:
self. twelite. update()
self. update_plot()
dpg. render_dearpygui_frame()
# MARK: Show
def show (self) -> None :
"""Main execution loop of the application."""
try :
while dpg. is_dearpygui_running():
self. loop()
except KeyboardInterrupt :
pass
finally :
print("Quit..." )
self. close()
# MARK: Lifecycle
def __enter__(self) -> Self:
"""Enter the runtime context related to this object."""
return self
def __exit__(
self,
exc_type: type[BaseException ] | None ,
exc_value: BaseException | None ,
traceback: TracebackType | None ,
) -> bool | None :
"""Exit the runtime context and close the connection."""
self. close()
return None
def __del__(self) -> None :
"""Destructor to ensure resources are cleaned up."""
self. close()
def close (self) -> None :
"""Cleanly shut down TWELITE connection and Dear PyGui context."""
if self. state == self. State. CONNECTING:
self. twelite. close()
dpg. destroy_context()
# MARK: Entry point
if __name__ == "__main__" :
with MainViewport() as viewport:
viewport. show() スクリプトの実行 スクリプトを実行します。
「シリアルポート」のコンボボックスから、使用するポート(COM3, /dev/tty.usb*など)を選択 「シリアル通信」の「接続」ボタンを押して通信を開始 TWELITE DIP の入力を変化させて、「TWELITE DIP 入力」ウィンドウの変化を確認 「TWELITE DIP 出力」ウィンドウのチェックボックスやスライダーを変化させて、TWELITE DIP の出力の変化を確認 「シリアル通信」の「切断」ボタンを押して通信を終了 ウィンドウを閉じる 表示例
正常に通信できていれば、TWELITE DIP の状態をリアルタイムに表示しつつ、TWELITE DIP の出力を任意のタイミングで変更できるはずです。
簡単なグラフィカルUIを備え、TWELITE DIP と通信するアプリケーションを構築できました!
グラフの更新タイミング
PWMxのリアルタイム描画グラフは、過去5秒間の状態を 10ms の間隔で反映します。これはスクリプト冒頭の変数が決めています。
PLOT_UPDATE_INTERVAL = 1.0 / 100 # 100Hz
PLOT_X_LIMIT = 5.0 # 3 seconds スクリプトの解説 Dear PyGui の初期化は initialize_viewport() が行っています。
フォントファイルや、OSのウィンドウ(Viewport と呼ぶ)の大きさはここで登録しています。
def initialize_viewport (self) -> None :
"""Set up Dear PyGui context, fonts, and viewport."""
dpg. create_context()
with dpg. font_registry():
font_path = str(Path(__file__). parent / FONT)
with dpg. font(file= font_path, size= 18 ) as default_font:
dpg. add_font_range_hint(dpg. mvFontRangeHint_Japanese)
dpg. bind_font(default_font)
dpg. create_viewport(
title= "TWELITE STICK" , width= 620 , height= 440 , resizable= True
)
dpg. set_viewport_vsync(False )
dpg. setup_dearpygui()
dpg. show_viewport() OSのウィンドウ内のインタフェースは、create_windows() に定義しています。
画面内の子ウィンドウは dpg.window() によって定義され、配下のコンポーネントを定義していきます。
コンポーネントには tag を登録することで、値や属性をプログラムから変更できます(HTMLのid=のようなイメージ)。
def create_windows (self) -> None :
"""Create and configure all Dear PyGui windows and their contents."""
# MARK: Panel Window
with dpg. window(
no_title_bar= True ,
no_close= True ,
no_collapse= True ,
no_move= True ,
no_resize= True ,
pos= (10 , 10 ),
width= 600 ,
height= 100 ,
):
ports = mw. utils. get_ports()
with dpg. group(horizontal= True ):
with dpg. child_window(width= 300 ):
dpg. add_text("シリアルポート" )
dpg. add_combo(
items= ports,
default_value= ports[0 ],
tag= "ports_combo" ,
width= 280 ,
enabled= True ,
callback= self. on_select_port,
)
... また、入力を受け付けるボタンやコンボボックス、スライダーやチェックボックスでは、callback を登録できます。
def on_select_port (self, sender: Any, app_data: str, user_data: Any) -> None :
"""Handle serial port selection from the combo box."""
self. selected_port = app_data ほかのスクリプトと同様に、TWELITE の子機から受信したデータは、イベントハンドラで受け取ることができます。
Nuitkaで実行ファイルをビルドする場合 Nuitka を使って.exeなどの実行ファイルをビルドする場合、メソッドのバインディングをC言語に変換する際にselfが重複し、引数の数を超過してしまう場合があります。このような場合には、クロージャを返すように実装してください。
from typing import Any, Callable
...
def cb_for_select_port (self) -> Callable[[Any, str, Any], None ]:
"""Make a callback for serial port selection from the combo box."""
def callback (sender: Any, app_data: str, user_data: Any) -> None :
self. selected_port = app_data
return callback
...
dpg. add_combo(
...
callback= self. cb_for_select_port(),
) on_app_twelite() では、DOxに反映するデータを tag によって即座に登録し、PWMxに反映するデータはメンバ変数を通じて update_plot() へ渡しています。
def on_app_twelite (self, packet: mw. parsers. app_twelite. ParsedPacket) -> None :
"""Update the GUI based on incoming TWELITE DIP packet data."""
now = perf_counter()
for p in range(1 , 5 ):
# DO
p_state = packet. di_state[p - 1 ]
match p:
case 1 : # RED
color = (255 , 0 , 0 , 255 ) if p_state else (0 , 0 , 0 , 255 )
case 2 : # GREEN
color = (0 , 255 , 0 , 255 ) if p_state else (0 , 0 , 0 , 255 )
case 3 : # YELLOW
color = (255 , 255 , 0 , 255 ) if p_state else (0 , 0 , 0 , 255 )
case 4 : # BLUE
color = (0 , 0 , 255 , 255 ) if p_state else (0 , 0 , 0 , 255 )
dpg. configure_item(f "circle_do { p} " , fill= color)
# PWM
self. pwm_data[p] = packet. ai_voltage[p - 1 ]
self. pwm_plot_data[p]. append((now, self. pwm_data[p])) 「開始」ボタンを押したときは、start() が呼び出されます。
ここで mwings.Twelite を初期化し、受信ハンドラを登録しています。
def start (self) -> None :
"""Start TWELITE communication and register listeners."""
# Create a twelite object
self. twelite = mw. Twelite(self. selected_port)
# Use JST for received data
self. twelite. set_timezone(ZoneInfo("Asia/Tokyo" ))
# Register event handler(s)
self. twelite. add_listener(mw. common. PacketType. APP_TWELITE, self. on_app_twelite)
self. update_state(self. State. CONNECTING) Dear PyGui は低レベルな API を使って構築されているため、各フレームの描画をアプリケーションから指示し、描画ループを自前で定義することができます。OS のウィンドウが表示されている間、loop()は無限に呼び出されます。
シリアルポートへ接続したのち、loop() が行う処理は3つあります。
def loop (self) -> None :
"""Perform periodic updates while the application is running."""
match self. state:
case self. State. IDLE:
pass
case self. State. CONNECTING:
self. twelite. update()
self. update_plot()
dpg. render_dearpygui_frame() 画面全体の処理は、show() を呼び出すことで開始されます。
def show (self) -> None :
"""Main execution loop of the application."""
try :
while dpg. is_dearpygui_running():
self. loop()
except KeyboardInterrupt :
pass
finally :
print("Quit..." )
self. close() プログラムは、画面を閉じる dpg.is_dearpygui_running()== False か、Ctrl+Cを入力する KeyboardInterrupt ことで描画ループを抜け、mwings.Twelite や dearpygui のクローズ処理を経て終了します。
3 - TWELITE SPOT TWELITE と Wi-Fi のネットワークを連携させる
無線LANゲートウェイ
TWELITE SPOT は、低消費電力が特徴の無線マイコンモジュール
TWELITE と 無線 LAN マイコンモジュール
ESP32 を組み合わせた製品です。ESP32 のファームウェアを開発することで、
TWELITE のネットワーク と Wi-Fi ネットワークを連携させることができます。
TWELITE と ESP32 で広がる世界 TWELITE SPOT は、小型で省電力、さらにペアリングをしないため多くの端末を同時に使用できる TWELITE シリーズと無線 LAN マイコンモジュール ESP32 を組み合わせた製品です。
外観
内部構成
TWELITE シリーズを愛用されているお客さまへ
周波数チャネルなどの設定変更は ESP32 から行います。他製品のように 7Pインタフェースからインタラクティブモードを使用することはできません 。ESP32 向けに用意された TWELITE 専用の Arduino ライブラリを使って設定 します。
※ TWELITE 側の 7P インタフェースは、SPOT 専用の親機アプリのアップデートにのみ使用します。
ESP32 のファームウェアを開発することで、例えば下記のようなシステムを実現できます。
ローカルサーバ ESP32 をサーバとして使用します。例えば、TWELITE CUE が計測した加速度データをスマートフォンに表示したり、TWELITE DIP の出力ポートをスマートフォンで操作したりすることができます。
ローカルゲートウェイ ESP32 を LAN に接続します。例えば、ビル全体に設置した TWELITE ARIA が送るデータを各フロアの TWELITE SPOT で受信し、LAN 上のサーバに全フロアの温湿度データを集約することができます。
IoT ゲートウェイ ESP32 をインターネットに接続します。例えば、TWELITE CUE と磁石をドアに取り付け、取得したドアの開閉状態から、ドアが開いたままであることをクラウド上で検知できます。
Arduino IDE と専用ライブラリによる開発 TWELITE SPOT によるシステムを構築するには、ESP32 のファームウェアを開発する必要があります。
このとき、ESP32 のファームウェア開発には Arduino IDE が使用できます。
Arduino IDE を使った開発の様子
Web 上には、Arduino IDE によるファームウェア開発についての膨大な情報があります。
例えば、esp32 arduino と検索してみてください。
Arduino ライブラリマネージャで配布中の MWings ライブラリ により、TWELITE 子機からのパケット受信や TWELITE 子機へのコマンド送信を簡単に行うことができます。
スタートガイドの流れ このスタートガイドでは、TWELITE SPOT の動作確認、ESP32 開発環境の構築、簡単なスケッチの作成および書き込みを行います。
1. TWELITE SPOT の動作を確認する まずは使ってみる
内容 TWELITE SPOT にプリインストールされているアプリを使って、加速度センサー無線タグ TWELITE CUE のデータをスマートフォンで閲覧してみます。
必要なもの 2. ESP32 の Hello World を行う ESP32 を使ったファームウェア開発の基礎
内容 開発環境の構築、Hello World スケッチの作成・書き込み、動作確認を行ってみます。
必要なもの 3. TWELITE CUE からデータを取得する TWELITE との通信
内容 TWELITE CUE の加速度データを ESP32 から出力してみます。
必要なもの
スタートガイドでは、サードパーティのオープンソースソフトウェアを使用します。
サードパーティのソフトウェアについて、その詳しい使用方法を弊社からご案内することはいたしかねます。また、サードパーティのソフトウェアを使用されたことによるいかなる損害についても、弊社は一切の責任を負いません。
3.1 - まずは使ってみる TWELITE SPOT と TWELITE CUE を使って、スマホに加速度情報を表示してみる
TWELITE SPOT では、ESP32 上の Web サーバに動的なページをホストすることで、TWELITE 子機から受信したデータをネットワーク内に配信できます。
動作イメージ
ここでは、TWELITE SPOT が無線 LAN のアクセスポイントとして機能します。
用意するもの TWELITE SPOT の動作を確認する 1. 本体を起動する ⚡ TWELITE SPOT の側面に USB-C ケーブルを接続し、USB AC アダプタから電源を供給してください。
USB 電源の接続
2. TWELITE CUE を起動する ⚡ TWELITE CUE に CR2032 型コイン電池を挿入してください。ただちに動作を開始します。
コイン電池の挿入
TWELITE CUE が正常に起動すると、ロゴのある面に実装された LED が点滅します。
TWELITE CUE が初期設定でないと、TWELITE SPOT と通信できません。
TWELITE CUE の設定を変更している場合は、再度設定変更を行い 、工場出荷時の状態に戻してください
3. スマートフォンを接続する 📱 スマートフォンの Wi-Fi 設定からネットワーク TWELITE SPOT (XXXX) に接続してください。
パスワードは twelitespot です。また SSID の XXXX は機種ごとの識別子です。
4. Webブラウザを開く 🌐 スマートフォンのWebブラウザを開き、spot.local へアクセスしてください。
接続できない場合は、192.168.1.1 へのアクセスをお試しください。
それでも接続できない場合は、http://192.168.1.1/ へのアクセスをお試しください。
以下のような画面が表示されます。
トップページ
5. CUE ビューアを開く 📈 CUE Viewer をタップして、CUE ビューアの画面を開いてください。
以下のような画面が表示されます。
TWELITE CUE の向きを変えてみてください。
CUE ビューアは、TWELITE CUE に表記されたサイコロの目を表示します。
TWELITE NET と 無線 LAN を使った TWELITE SPOT の動作を確認できました!
3.2 - ESP32 を使ったファームウェア開発の基礎 TWELITE SPOT のファームウェア開発に向けて、ESP32 の Hello World を試す
ESP32 は、単体でも無線 LAN によるシステムを構築することができます。例えば、ホストした Web ページにデータを表示したり、データを WebSocket で LAN 内のサーバに送信したり、クラウドサービスへ REST API を投げたりすることができます。
TWELITE SPOT は、この ESP32 に TWELITE を組み合わせることで、多数の小型で省電力な無線タグを利用できるようにした製品です。
まずは ESP32 のファームウェア開発の基礎を習得するため、Hello World を行ってみましょう。
開発環境の構築、Hello World スケッチの作成・書き込み、動作確認を行います。
本稿の内容は、TWELITE SPOT の動作確認を兼ねています。Arduino IDE による ESP32 向けファームウェアの開発経験がある方も、下記の内容を確認してください。
TWELITE SPOT には TWELITE と ESP32 を搭載していますが、通常は後者のファームウェアのみ開発します。TWELITE のファームウェアには、 プリインストールされている
親機・中継機アプリ を利用してください。
用意するもの 環境を構築する 1. IDE を導入する 🚛 コンピュータに Arduino IDE を導入していない場合は、Arduino 公式ダウンロードページ からファイルを入手し、これをインストールしてください(IDE 1.x または 2.x)。
Arduino IDE 1.x を導入してください。
最新の Arduino IDE 2.x でも Arduino IDE 1.x と同様にスケッチを書き込めますが、2023年5月現在 Java 製プラグインが動作しないため、Legacy IDE を推奨しています。
2. ツールチェインを導入する 🚚 Arduino IDE に Arduino core for the ESP32 を導入していない場合は、ボードマネージャの URL に下記を追加し、esp32 ボード定義をインストールしてください。
https://espressif.github.io/arduino-esp32/package_esp32_index.json 3. ボード設定を行う ⚙️
ここからは TWELITE SPOT に固有の内容です。
TWELITE SPOT に合わせて、Arduino core for the ESP32 の設定を行います。
ボード種別を選択する ツールバーの ツール -> ボード -> ESP32 Arduino -> ESP32 Dev Module を選択してください。
ESP32 Dev Module の場所
ボード設定を行う 下図と同様に設定してください。
設定後の内容
Flash size を 4MB (32Mb) から 16MB (128Mb) に変更してください。
TWELITE SPOT を準備する 1. フタをはずす ⛏️ TWELITE SPOT のケース上面のフタをはずしてください。
スイッチやコネクタ類が露出します。
各部の名称
2. TWELITE R3 / R2 をつなぐ 🔌 ESP32用 7P インターフェイス(ESP32 と記載)に TWELITE R3 / R2 を接続してください。
接続例 (ESP32)
TWELITE R3 / R2 は、必ず上図と同じ向きで TWELITE SPOT に接続してください。誤った向きで接続すると、 TWELITE SPOT や TWELITE R3 / R2 が破損する恐れがあります。
覚え方 👉 TWELITE R3 / R2 の表面を接続対象に向けるようにします。
各 7P インタフェースの VCC ピンは接続されていません。TWELITE R シリーズからは電源を供給できないため、側面の USB-C コネクタから電源を供給する必要があります。
3. USB-C 電源をつなぐ ⚡ 側面の USB-C コネクタ に 5V 電源を供給してください。
スケッチを動かす Arduino では、プログラムコード/プロジェクトのことをスケッチと呼びます。
1. スケッチを作成する 👨💻 ESP32 から文字列をシリアル出力し、Arduino IDE のシリアルモニタに出力する Hello World スケッチを作成します。
スケッチ作成画面
Arduino IDE を起動して、下記のコードを入力してください。
void setup () {
Serial.begin(115200 );
Serial.println("Hello, World!" );
}
void loop () {
} setup() の内容は起動時に一度だけ実行されます。一方、loop() の内容は際限なく繰り返し実行されます。
2行目では、シリアルポートのボーレート(通信速度)を 115200bps に設定しています。
このボーレートは、後述のシリアルモニタのボーレートと合わせる必要があります。
3行目では、"Hello, World!" という文字列をシリアルポートに出力しています。
Serial.println("Hello, World!" );
Serial.println() では、末尾に改行 (CRLF) が自動的に付与されます。
2. スケッチを書き込む ⚒️ シリアルポートを選択する ツール -> シリアルポート メニューから、 接続したデバイス(TWELITE R シリーズ)のポートを選択してください。
シリアルポート選択
シリアルポートは、Windows では COM? といった名称に、macOS / Linux では /dev/tty? といった名称になります。
ESP32 を起動する ESP32 をプログラムモードで起動します。
ESP32 リセットスイッチ EN(RST) と ESP32 ブートスイッチ BOOT を押し、EN(RST) -> BOOT の順で離してください。
ボタンの位置
BOOT を押した状態でリセットすることが重要です。
スケッチを書き込む Arduino IDE 上部の マイコンボードに書き込む ボタンをクリックしてください。
書き込み完了画面
3. シリアルモニタを開く 🖥️ 画面を開く Arduino IDE 右上の シリアルモニタ ボタンをクリックしてください。
右上にシリアルモニタボタンがある
設定する シリアルモニタ画面の右下のボーレートを 115200 に設定してください。
ボーレート設定
4. スケッチを動かす 🚀 ESP32 を再起動する 書き込みが完了したら、TWELITE SPOT の ESP32 リセットスイッチ EN(RST) を押して離し、ESP32 をリセットしてください。
リセットスイッチの位置
シリアルモニタを確認する シリアルモニタに以下の文字列が表示されたら成功です。
Hello World に成功した様子
TWELITE SPOT に搭載された ESP32 のファームウェア開発環境が整いました!
3.3 - TWELITE 子機からのデータ受信 TWELITE CUE から受信した加速度データをシリアルモニタに出力してみる
TWELITE SPOT は、ESP32 に TWELITE を組み合わせることで、多数の小型で省電力な無線タグを利用できるようにしています。
手始めに、TWELITE CUE の加速度データを ESP32 から出力してみましょう。
用意するもの 環境を構築する 1. 開発環境を導入する 🚛 ESP32 を使ったファームウェア開発の基礎 の環境構築を行っていない場合は、これを実施してください。
2. ボード設定を行う ⚙️ ボード種別を ESP32 Dev Module としたうえで、下記のように設定してください。
設定後の内容
3. ライブラリを導入する 🚚 ESP32 から TWELITE を使うために必要となる MWings ライブラリ をインストールします。
スケッチ -> ライブラリをインクルード -> ライブラリを管理… を開いてください。
ライブラリマネージャの場所
検索ボックスに MWings と入力し、MWings をインストールしてください。
ライブラリマネージャ
TWELITE SPOT を準備する 1. フタをはずす ⛏️ TWELITE SPOT のケース上面のフタをはずしてください。
2. ケーブルをつなぐ 🔌 ESP32用 7P インターフェイス(ESP32 と記載)に TWELITE R3 / R2 を接続したうえで、側面の USB-C コネクタ に 5V 電源を供給してください。
接続例 (ESP32)
まずはスケッチを動かしてみる 1. サンプルを開く 📂 Arduino IDE を起動し、ファイル -> スケッチ例 -> MWings -> monitor_spot_app_cue を選択してください。
TWELITE ARIA の場合は、monitor_spot_app_aria を選択します。
2. シリアルポートを選ぶ ⚙️ ツール -> シリアルポート メニューから、 接続したデバイス(TWELITE R シリーズ)のポートを選択してください。
シリアルポート選択
3. ESP32 を起動する 👇 ESP32 をプログラムモードで起動します。
リセットスイッチ EN(RST) と ESP32 ブートスイッチ BOOT を押し、EN(RST) -> BOOT の順で離してください。
ボタンの位置
4. スケッチを書き込む ⚒️ Arduino IDE 上部の マイコンボードに書き込む ボタンをクリックしてください。
書き込み完了画面
5. シリアルモニタを開く 🖥️ 画面を開く Arduino IDE 右上の シリアルモニタ ボタンをクリックしてください。
右上にシリアルモニタボタンがある
設定する シリアルモニタのボーレートを 115200 に設定してください。
6. ESP32 を再起動する 🚀 書き込みが完了したら、TWELITE SPOT の ESP32 リセットスイッチ EN(RST) を押して離し、ESP32 をリセットしてください。
リセットスイッチの位置
ESP32 を再起動すると、TWELITE も再起動します。
ESP32 が起動すると、基板の ESP32 側に実装された LED が点滅します。 TWELITE が起動すると、基板の TWELITE 側に実装された LED が1秒間点灯します。 7. 起動を確認する 💬 シリアルモニタに以下の文字列が表示されたら、起動に成功しています。
Monitor example for TWELITE SPOT: App_CUE (CUE Mode) 起動に成功した様子
TWELITE ARIA の場合は、下記のように表示されます。
Monitor example for TWELITE SPOT: App_ARIA (ARIA Mode) 8. TWELITE CUE を起動する ⚡ TWELITE CUE に CR2032 型コイン電池を挿入してください。ただちに動作を開始します。
コイン電池の挿入
TWELITE CUE が正常に起動すると、ロゴのある面に実装された LED が点滅します。
9. 受信を確認する 💬 シリアルモニタに以下のような文字列が表示されたら、TWELITE CUE からのデータ受信に成功しています。
Packet Number: #3
Source Logical ID: 0x1
LQI: 147
Supply Voltage: 3310 mV
Accel Event: Dice (1)
Accel X Axis [0]: 72 mG
Accel Y Axis [0]: -64 mG
Accel Z Axis [0]: 1000 mG
Magnet State: Leaving or Not found 受信に成功した様子
TWELITE ARIA の場合は加速度データの代わりに温湿度データを出力するため、一部の表示が異なります。
TWELITE SPOT に搭載された TWELITE を通じて、TWELITE CUE の加速度データを読み出すことができました!
スケッチの解説 サンプルスケッチ(monitor_spot_app_cue.ino )の内容を簡単に解説します。
ライブラリのインクルード 4行目では、さきほど導入した MWings ライブラリ をインクルードしています。
ピン番号の定義 6-8行目では、ピン番号を定義しています。
const int RST_PIN = 5 ;
const int PRG_PIN = 4 ;
const int LED_PIN = 18 ; 名称 内容 RST_PINTWELITE の RST ピンが接続されているピンの番号 PRG_PINTWELITE の PRG ピンが接続されているピンの番号 LED_PIN基板上の ESP32 用 LED が接続されているピンの番号
RST_PIN および PRG_PIN の番号は変更しないでください。
これらを変更してしまうと、TWELITE を正しく起動することができません。
TWELITE 設定の定義 10-11行目では、TWELITE SPOT に搭載された TWELITE 親機に適用する設定を定義しています。
const uint8_t TWE_CHANNEL = 18 ;
const uint32_t TWE_APP_ID = 0x67720102 ; 名称 内容 TWE_CHANNELTWELITE の 周波数チャネル TWE_APP_IDTWELITE の アプリケーション ID
シリアルポートの設定 19-21行目では、使用するシリアルポートを初期化するとともに、シリアルモニタへ起動メッセージを出力しています。
Serial.begin(115200 );
Serial.println("Monitor example for TWELITE SPOT: App_CUE (CUE Mode)" );
Serial2.begin(115200 ); Serial は、Arduino IDE の シリアルモニタとの通信に使います。シリアルモニタの設定に合わせて、ボーレートを 115200 bps としています。
一方、Serial2 は、TWELITE SPOT に搭載された TWELITE 親機との通信に使います。こちらも TWELITE 親機の初期設定に合わせて、ボーレートを 115200 bps としています。
TWELITE 親機のシリアル通信の初期設定は 115200 bps / 8N1 です。
TWELITE の設定 24-26行目では、Twelite.begin() を呼び出し、TWELITE SPOT に搭載された TWELITE 親機の設定と起動を行っています。
Twelite.begin(Serial2,
LED_PIN, RST_PIN, PRG_PIN,
TWE_CHANNEL, TWE_APP_ID); 引数 型 内容 Serial2HardwareSerial&TWELITE との通信に使うシリアルポート LED_PINintステータス LED を接続したピンの番号 RST_PINintTWELITE の RST ピンを接続したピンの番号 PRG_PINintTWELITE の PRG ピンを接続したピンの番号 TWE_CHANNELuint8_tTWELITE の 周波数チャネル TWE_APP_IDuint32_tTWELITE の アプリケーション ID
パケット受信時のイベントの登録 29-49行目では、Twelite.on() を呼び出し、TWELITE CUE から送られたデータに対して行う処理を登録しています。
ここでは、受信したパケットの内容をシリアルモニタに出力しています。
Twelite.on([](const ParsedAppCuePacket& packet) {
Serial.println("" );
Serial.print("Packet Number: #" );
Serial.println(packet.u16SequenceNumber, DEC);
Serial.print("Source Logical ID: 0x" );
Serial.println(packet.u8SourceLogicalId, HEX);
Serial.print("LQI: " );
Serial.println(packet.u8Lqi, DEC);
Serial.print("Supply Voltage: " );
Serial.print(packet.u16SupplyVoltage, DEC); Serial.println(" mV" );
Serial.print("Accel Event: " );
printAccelEvent(packet.u8AccelEvent);
Serial.print("Accel X Axis [0]: " );
Serial.print(packet.i16SamplesX[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Y Axis [0]: " );
Serial.print(packet.i16SamplesY[0 ], DEC); Serial.println(" mG" );
Serial.print("Accel Z Axis [0]: " );
Serial.print(packet.i16SamplesZ[0 ], DEC); Serial.println(" mG" );
Serial.print("Magnet State: " );
printMagnetState(packet.u8MagnetState, packet.bMagnetStateChanged);
}); 上記のイベントは、TWELITE CUEからのパケットを受信したときにだけ呼び出されます。
受信したパケットの内容は ParsedAppCuePacket 型の引数 packet に格納されます。
packet には、下記のデータが含まれています(太字 のデータを上記のコード中で使用しています)。
データ 型 内容 packet.u32SourceSerialIduint32_t送信元のシリアルID packet.u8SourceLogicalIduint8_t送信元の論理デバイスID packet.u16SequenceNumberuint16_tシーケンス番号 packet.u8Lqiuint8_tLQI(電波通信品質の指標) packet.u16SupplyVoltageuint16_t電源電圧 (mV) packet.i16SamplesXint16_t[10]各サンプルの X 軸加速度 (mG) packet.i16SamplesYint16_t[10]各サンプルの Y 軸加速度 (mG) packet.i16SamplesZint16_t[10]各サンプルの Z 軸加速度 (mG) packet.u8SampleCountuint8_tサンプル数 packet.bHasAccelEventbool加速度イベントがあるならtrue packet.u8AccelEventuint8_t加速度イベントID packet.u8MagnetStateuint8_t磁気イベントID packet.bMagnetStateChangedbool磁気センサの状態が変化したならtrue
TWELITE ARIA の場合には、ParsedAppAriaPacket 型を利用します。
Twelite.on() はデータの種別ごとに記述することができ、例えば下記のような記述を追加することで TWELITE ARIA からのデータを受信した際の処理を追加できます。
Twelite.on([](const ParsedAppAriaPacket& packet) {
// Handle packet...
}); 詳しくは API リファレンス をご覧ください。
TWELITE のデータの更新 55行目では、Twelite.update() を呼び出しています。
Twelite.update() は、TWELITE 親機から送信されるパケットデータ(ModBus ASCII 形式)を順次1バイトずつ読み出す関数です。
loop() 内で繰り返し
Twelite.update() を呼ぶことで、TWELITE 親機から送信されるパケットデータの解釈が進みます。パケットデータの解釈を終えた際に
上記 のようなイベントが呼ばれる仕組みです。
delay() などの処理でこの関数の呼び出しをブロックすると、パケットデータ文字列の読み出しが間に合わないことがあります。時間のかかる処理は必ず非同期の実装として、
loop() 関数をできるだけ高速回転させるようにしてください。
TWELITE SPOT に搭載された TWELITE を通じて、TWELITE CUE の加速度データを読み出す方法が分かりました!
ステップアップに向けて、下記のスケッチ解説や 関連情報 をご覧ください。
3.4 - 関連情報 ステップアップに向けて
TWELITE SPOT のファームウェア開発に役立つ資料をまとめました。
MWings ライブラリ TWELITE 製品データシート TWELITE SPOT マニュアル スケッチ解説 その他 外部リンク Arduino ESP32
ESP-IDF は、FreeRTOS を利用した ESP32 の公式開発環境です。
Arduino core for the ESP32 は ESP-IDF をベースに実装されているため、Arduino から ESP-IDF の機能を呼び出すこともできます。
スケッチ spot-google-sheets では、FreeRTOS のマルチタスク機能とキューを利用しています。
例えば、マルチタスクを行うには xTaskCreatePinnedToCore() といった関数が使えます
コミュニティ ライブラリ プラグイン 4 - TWELITE STAGE SDK / act TWELITE のファームウェアを開発する
TWELITE STAGE SDK を使うことで、独自のファームウェアを TWELITE 向けに開発できます。
MWX ライブラリと act MWX ライブラリは、TWELITE 無線モジュールのコード表記を簡素化することを目的としています。MWXで作成されたプログラムをアクト act と呼びます。アクトにはループによる記述と、イベントによる記述(ビヘイビア behavior と呼びます)の二種類があります。
ループによる記述 (setup(), loop()) 小規模な機能を記述する場合に適しています。
#include <TWELITE>
const uint8_t PIN_LED = 5 ;
void setup () {
pinMode(PIN_LED, OUTPUT);
}
void loop () {
if (TickTimer.available()) {
uint32 t_now = millis();
// blink LED every 1024ms
digitalWrite(PIN_LED, (t_now >> 10 ) & 1 ? HIGH : LOW);
}
} イベントドリブンのアプリケーション記述 各種イベント・割り込みハンドラの定義、アプリケーションの複雑な振る舞いを記述するのに適したステートマシンをクラス内に定義して、見通しの良いコードを記述できます。この記述方法をビヘイビアと呼びます。
// myApp.hpp
...
class myApp : MWX_APPDEFS_CRTP(myApp) {
...
void loop() {
// main loop
}
void receive (mwx:: packet_rx& rx) {
// on receive
}
};
// myApp.cpp
...
MWX_DIO_EVENT(12 , uint32_t arg) {
// on event from DIO12
} ペリフェラルの手続きを簡素化 よく使われる UART, I2C, SPI, ADC, DIO, タイマー, パルスカウンタを取り扱うクラスオブジェクトを定義しています。
void loop () {
while (Serial.available() {
auto x = Serial.read(); ... } // serial message
if (Analogue.available() {
auto x = Analogue.read(...); } // adc values
if (Buttons.available() {
Buttons.read(...); } // DIO changes
if (the_twelite.receiver.available()) {
auto && rx = the_twelite.receiver.read(); } // on rx packet
} シンプルな中継ネットワークを定義 この中継ネットワークは TWELITE 標準アプリケーションと同等の実装で、個体アドレスの管理は 8bit の論理IDで行うこと、ネットワーク構築のための通信を行わないため電源投入後すぐにネットワーク宛に無線パケットを送ることができる点が特徴です。
#include <TWELITE>
#include <NWK_SIMPLE>
void setup () {
...
auto && nwksmpl = the_twelite.network.use< NWK_SIMPLE> ();
nwksmpl << NWK_SIMPLE:: logical_id(0xFE )
// set Logical ID. (0xFE means a child device with no ID)
<< NWK_SIMPLE:: repeat_max(3 );
// can repeat a packet up to three times.
}
void loop () {
...
vTransmit();
...
}
void vTransmit () {
if (auto && pkt =
the_twelite.network.use< NWK_SIMPLE> ().prepare_tx_packet();
pkt << tx_addr(0x00 ) // to parent
<< tx_retry(0x3 ); // set retry
pack_bytes(pkt.get_payload() // prepare payload data
, uint8_t (0x01 )
, uint16_t (analogRead(PIN_ANALOGUE:: A1))
, uint16_t (analogRead_mv(PIN_ANALOGUE:: VCC)));
pkt.transmit(); // transmit!
}
TWELITE APPS のパケットとの互換性はありません TWELITE APPS における中継回数は原則として3回に限られますが、act のパケットは64回まで中継できます。
中継回数を増やす際は、中継済みのパケット(重複パケットの管理テーブルがクリアされたもの)であっても、パケットが遠回りして一定時間経過後に戻ってきた際には、再び中継されてしまう場合があることに注意してください。
PAL や MONOSTICK 向けのボード定義 ボード上のセンサーなどを容易に取り扱えます。
#include <TWELITE>
#include <PAL_AMB> // include the board support of PAL_AMB
void setup () {
auto && brd = the_twelite.board.use< PAL_AMB> (); // use PAL AMB
uint8_t u8dip = brd.get_DIP_SW(); // check DIP s/w status
brd.set_led(LED_TIMER:: BLINK, 100 ); // LED switchs on/off every 100ms
...
// start capture of sensors
brd.sns_SHTC3.begin();
}
void loop () {
if (TickTime.available()) { // check every ms
auto && brd = the_twelite.board.use< PAL_AMB> ();
if (brd.sns_LTR308ALS.available()) {
Serial << brd.sns_SHTC3..get_temp();
} else {
// notify sensor that 1ms passed.
brd.sns_SHTC3.process_ev(E_EVENT_TICK_TIMER);
}
}
} 4.1 - 開発環境 開発環境(OSなど)について
開発環境を構築するためには、ソフトウェア群のインストール、またこれらの利用許諾に同意する必要があります。また、PC、ワークステーション上でセキュリティ設定等が必要になる場合があります。
配布時には十分注意しておりますが、ウィルスなどの確認はお客様のほうでも留意いただくようお願いいたします。 お客様のセキュリティの考え方や運用(例:外部アプリケーションのインストールの可否)については、お客様の環境の管理者にご確認ください。 また、開発環境をインストールまた動作するにあたり、OSが介在し設定等必要になる場合があります(例:開発元が不明なアプリケーションの実行。開発環境または紹介するツール群の多くは、アプリケーションは開発元を証明する仕組みが組み込まれせん)。設定方法については、一般の情報を参考いただくようお願いいたします。
MWXライブラリを用いてアプリケーションを記述するには以下が必要です。
MWSDK(ソフトウェア開発環境) 開発用エディタ(Microsoft社のVisual Studio Codeを紹介します) Windows コンパイラのツールチェインなどは比較的環境への依存度が低いため、多くの環境で動作することが期待できますが、現在サポートされている Windows10および11バージョンを推奨します。動作環境の差異により動作しないような場合は、当社で確認している環境を参考に別途環境を用意してください。
以下、開発で使用しているバージョンを挙げます。
Windows11 21H2 (Visual Studio 2019) FTDI社のドライバが動作していること (MONOSTICK, TWELITE Rを動作させるため)
WSL (Windows Subsystem Linux) 環境下でもコンパイラを動作させることが出来ます。ただしコンパイルのみでファームウェアの書き換え等はWindows10上のユーティリティから実施してください。
WSL環境は必須ではありません。
Linux コンパイラのツールチェインなどは比較的環境への依存度が低いため、多くの環境で動作することが期待できますが、現在サポートされているディストリビューションを推奨します。動作環境の差異により動作しないような場合は、当社で確認している環境を参考に別途環境を用意してください。
以下、開発で使用しているバージョンを挙げます。
Ubuntu 18.04 LTS 64bit Ubuntu 20.04 LTS 64bit macOS コンパイラのツールチェインなどは比較的環境への依存度が低いため、多くの環境で動作することが期待できますが、現在サポート中のmacOSバージョンを推奨します。動作環境の差異により動作しないような場合は、当社で確認している環境を参考に別途環境を用意してください。
以下、開発で使用しているバージョンを挙げます。
macOS 10.14 Mojave (Intel) macOS 12 Monterey (Apple Silicon) Visual Studio Code などの開発ツールについて 開発環境を動作させるためのツールや使用方法については、その開発元やコミュニティの情報を参照ください。
コード記述作業の効率面で Visual Studio Code (VSCode) の利用を推奨します。
MWXライブラリでは、C言語の開発に比べ、読み込むヘッダファイルが多くなるため、VSCode上でのコード解釈等にはより多くのPCのリソースを要求します。
なお、VSCodeは必須ではありません。使い慣れたエディタがある場合には、そちらを使用していただいても結構です。
LSP (Language Server Protocol)を使用できる環境 であれば、一般的にVSCodeと同等の作業効率を実現できるものと考えられます。
ビルド環境による差異
Linux/WSL環境下/macOSのビルド結果はWindows10の結果と異なります。通常系の動作で差異が見られることは当社が把握する限りありませんが、特にgccのLTOを無効にしているためバイナリサイズが数%程度大きくなる傾向にあります。
動作等に疑問を感じた際は、必ず Windows10,11 上のビルドを実施し再現することを確認してから、お問い合わせください。
4.2 - SDKのインストール TWELITE SDK のインストール
TWELITE STAGE SDK の導入 TWELITE STAGE SDK 配布アーカイブ(ZIPなど)をダウンロードし、適切なフォルダに展開します。
以下のように展開したら完了です。
フォルダ例
環境変数の設定
コマンドラインでビルドを行う場合には、環境変数を設定してください。TWELITE STAGE アプリは自動で設定するため不要です。
MWSDK_ROOT, MWSDK_ROOT_WINNAME (Windowsのみ)を設定します。
Windows ここでは展開後のフォルダ名を C:\MWSTAGE とします。別のフォルダへインストールした場合は、読み替えてください。
C:\MWSTAGE\Tools\SET_ENV.CMD を実行してください。以下の環境変数を設定します。
MWSDK_ROOTMWSDK_ROOT_WINNAME例えば以下のような設定になります。
MWSDK_ROOT=C:/MWSTAGE/MWSDK/
MW_ROOT_WINNAME=C:\MWSTAGE\MWSDK\
インストールしたPC上からTWELITE STAGE SDKをアンインストールするには以下を行ってください。
UNSET_ENV.cmdを実行してください。環境変数の設定を解除します。MWSTAGEフォルダを削除します。Linux 開発環境やシェルに MWX_ROOT
方法はいくつかありますが、ホームフォルダの.profile(ファイルがなければ新しく作成してください)に以下の設定を追加します。この設定でVSCodeのビルドまで可能です。環境変数が反映されるように設定してください。
MWSDK_ROOT= /foo/bar/MWSTAGE/MWSDK/
export MWSDK_ROOT エディタを使用せずに追加するには以下のようにコマンド入力します。$はプロンプトで環境によって表示が違います。/foo/bar/MWSTAGEの部分はインストールしたフォルダに応じて書き換えてください。
cd $HOME
echo MWSDK_ROOT= /foo/bar/MWSTAGE/MWSDK>>.profile
echo export MWSDK_ROOT>>.profile macOS 開発環境やシェルに MWX_ROOT環境変数が反映されるように設定してください。
方法はいくつかありますが、ホームフォルダの.profile(ファイルがなければ新しく作成してください)に以下の設定を追加します。この設定でVSCodeのビルドまで可能です。
MWSDK_ROOT= /foo/bar/MWSTAGE/MWSDK/
export MWSDK_ROOT エディタを使用せずに追加するには以下のようにコマンド入力します。$はプロンプトで環境によって表示が違います。/foo/bar/MWSTAGEの部分はインストールしたフォルダに応じて書き換えてください
環境全体にMWSDK_ROOTを適用にするには、launchdを用います。
VSCodeの一部の設定で環境変数を参照していますが、ビルドには必須ではありません。
4.3 - アクトのビルド アクト(act)のビルド
MWXライブラリで記述したアプリケーションプログラムをアクト(act)と呼びます。まずは、これをビルドして書き込みます。
ビルドフォルダ構成について Visual Studio Code (VSCodeと記載) でのビルドについて
本ページでは、いくつかのビルド方法を記載していますが、いずれの方法も最終的にはmakeコマンドを実行しています。詳細はMakefileの解説を参照ください。
OS環境によっては各実行プログラム(makeやgccなどビルドツールチェイン)の動作時にセキュリティ警告が出る場合があります。警告を抑制する設定が必要になります。警告を抑制してプログラムを動作する運用を行うか は、お客さま自身またはシステム管理者に相談のうえ、ご判断ください。
ビルドフォルダ構成について MWSDKをインストールしたフォルダMWSDK_ROOT (例 C:\MWSDK)を開きます。以下のような構成になっています。
MWSDK_ROOT
|
+-ChipLib : 半導体ライブラリ
+-License : ソフトウェア使用許諾契約書
+-MkFiles : makefile
+-Tools : コンパイラ等のツール一式
+-TWENET : TWENET/MWXライブラリ
+-Act_samples : アクトサンプル
...
アクトファイルはAct_samples以下に格納しています。(以下は一部割愛しています)
Act_samples
|
+-CoreAppTwelite : App_TweLiteと同じ構成のボード用のアクト
+-PAL_AMB : 環境センス PAL 用のアクト
+-PAL_MAG : 開閉センス PAL 用のアクト
+-PAL_MOT : 動作センス PAL 用のアクト
..
+-Parent-MONOSTICK : 親機アクト、MONOSTICK用
+-PingPong : PingPong アクト
+-PulseCounter : パルスカウンタを利用したアクト
+-act0 : スクラッチ(とりあえず書いてみる)用アクト
これらのアクトは、MWXライブラリの記述の参考となるシンプルな例ですが、多くのアクトは以下の機能を有しています。
センサー値を取得する センサー値取得後、無線パケットを親機宛に送信する 送信完了後、一定時間スリープする(または割り込みを待つ) Parent-MONOSTICKのアクトによりパケットの受信と表示を行っています。この親機用のアクトは、アスキー形式で出力しています。 (:00112233AABBCC...FF[CR][LF] のような : で始まり、途中は16進数のバイトをアスキー文字2字で表現する形式です。末尾の??は同様に2字のバイトとなりますがLRCというチェックサムバイトになります。参考:アスキー形式)
実際に動作させてみるときは、以下の組み合わせを試してみてください。
親 子 解説 BRD_APPTWELITEBRD_APPTWELITE親機はM1ピンをLOW(GNDレベル)にして起動する。通常モード(常時稼働)にて、App_Tweliteのような動作を確認できます。 PingPongPingPong子機2台を使って動作します。片方から Ping パケットを送ると、相手方から Pong パケットが戻ってきます。 Parent-MONOSTICKその他 子機用のアクトのパケット送信を確認できます。
では、アクトの中から PingPong のフォルダの中を見てみましょう。
Act_samples にある他のアクトもビルドできます。その場合、フォルダ名・ファイル名は読み替えるようにしてください。
Act_samples
+-PingPong
+-PingPong.cpp : アクトファイル
+-build : ビルドフォルダ
+-.vscode : VSCode 用の設定ファイル
必ずフォルダ直下にフォルダと同名の .cpp ファイルが必要です。
小規模なアクトならこの.cppファイル内に記述します。規模が大きくなってきたときはMakefileの解説を参考にして複数のファイルに分割してビルドすることが出来ます。
PingPong フォルダ直下にアクトファイル PingPong.cpp があります。フォルダ名を変更した場合は、必ず .cpp ファイルの名前もフォルダ名と同名にします。
次にビルドフォルダを開きます。
Act_samples
+-PingPong
+-build
+-Makefile : makefile
+-build-BLUE.cmd : TWELITE BLUE 用ビルドスクリプト(Windows用)
+-build-RED.cmd : TWELITE RED 用ビルドスクリプト(Windows用)
+-build-clean.cmd : obj_* ファイル削除
ビルドに必要なスクリプトとMakefileが格納されています。
このMakefile のあるフォルダで make TWELITE={BLUEまたはRED} を実行することで、ビルドが行われます。VSCode でのビルドも同様で内部的に make を呼び出します。
TWELITE STAGE アプリでのビルド TWETLITE STAGE アプリを用いて、ビルドから書き込み、実行までを行えます。ここでは、TWELITE STAGE アプリの起動からビルドまでを解説します。
0. TWELITE の接続 MONOSTICKまたはTWELITE Rをお使いのUSBポートに接続します。
TWELITE は繊細な電子部品ですので、取り扱いには十分注意してください。以下に代表的な注意事項を記載します。
特にTWELITE Rを用いている場合は、多くの場合電子基板がケースなどを介さず直接外部に触れる状態で使用するため、意図しないショートやノイズなどUSBデバイスが正常に動作しない状態になる場合があります。
この場合は、アプリケーションを終了させUSBデバイスを抜き差しすることで通常は回復します。最悪、USBデバイスの破損やPCの破損も考えられます。
電子基板の取り扱いには十分注意してください。
回路の間違い電源を入れる前にはもう一度回路を確認してください。 電池の逆差しや過大電圧には注意してください。 静電気人感がない電圧であっても半導体の故障になりえます。大掛かりな対応をしなくとも、金属部に触れてから作業する・リストバンド・専用マットなど簡易にできる対応でも相応の効果はあります。 金属物などが触れることでのショート電子基板の近くには金属物がないようにしてください。クリップなどが散らかっているとこれが原因でショートすることもありますし、電池が大放電して加熱する危険な状況も考えられます。 1. TWELITE STAGE アプリの起動 {TWELITE SDK インストール} フォルダにある実行形式 TWELITE_Stage.{拡張子} を起動します(参考: TWELITE STAGE アプリマニュアル )。
以下は、TWELITE STAGE アプリ動作中の画面例です。左側の主画面とコマンドプロンプト画面がありますが、主画面を操作します。コマンドプロンプト画面は通常使用しませんが、諸情報及びTWELITEマイコンシリアルポートからの入力データが表示されます。
画面例
主画面での主な操作は以下です。
マウス左クリック (選択) マウス右ダブルクリック(前の画面に戻る) 素早く ESC を2回, 一部画面では ESC 1回 (前の画面に戻る) Alt(⌘) キーを押し続ける(ヘルプ画面)通常キーボード入力(画面に従う) (参考: TWELITE STAGE アプリマニュアル )
2. シリアルポートの選択 TWELITE STAGE アプリを起動すると最初に表示される画面です。事前に TWELITE R や MONOSTICK を接続しておけば、この画面に列挙されます。この画面で操作したい TWELITE を選択します。この画面で選択せずに、別の操作で選択することも可能です。
シリアルポート選択画面
(参考: TWELITE STAGE アプリマニュアル )
3. メインメニュー シリアルポート選択画面を抜けると、メインメニューが表示されます。ビルドや書込は「アプリ書換」メニューを選択します。
メインメニュー
(参考: TWELITE STAGE アプリマニュアル )
4. アプリ書換メニュー アプリ書換メニューを選択する前に、TWELITE の接続とシリアルポートの選択を確認しておいてください。シリアルポートの選択状況は Alt(⌘) キーを押し続けると出現するヘルプ画面上で確認できます。
アプリ書換メニュー
TWELITE STAGE アプリから参照できるプロジェクトはいくつかに分類されています。右側のヘルプは関連情報をブラウザで表示します。フォルダはプロジェクトのあるフォルダを表示します。
TWELITE が接続済みであれば、メニューを選択したときに、TWELITE のモデルが判定されます。(TWELITE STAGE アプリ内部では、この判定したTWELITEモデルに応じたビルドを行うようになっています)。
ここでエラーが出た場合は、この画面からメインメニューに戻って、メニューを再選択します。解決しない場合は、必要に応じてTWELITE STAGE アプリ上で Alt(⌘) + 0 を入力してシリアルポート選択を解除を行ったうえで USB 接続を含む各種接続を確認するなどします。USB接続のエラーによっては、お使いのコンピュータを再起動しないと解決しない場合もあります。
(参考: TWELITE STAGE アプリマニュアル )
4. プロジェクトの選択 ここでは「アプリ書換メニュー」から「actビルド&書換」を選択します。
アプリ書換メニュー
5. ビルド&書換 ここでは、先ほどのプロジェクト選択画面中で BRD_APPTWELITE を選択します。
選択すると、以下の画面例のように書き込みが行われます。エラーが表示された場合は、画面の指示に従うか、前の画面戻ってやり直してください。
書き込み中(ベリファイあり設定)
書き込み完了
(参考: TWELITE STAGE アプリマニュアル )
6. インタラクティブモードに移動 書換が正常に終了すると、続けてインタラクティブモード(設定画面)に移行します。ただし、インタラクティブモードに対応するファームウェアでないと画面は表示されません。
インタラクティブモードでは、TWELITE の無線チャネルなど、各種設定を行えます。
インタラクティブモード
(参考: TWELITE STAGE アプリマニュアル )
7. ターミナル画面 ルートメニューに戻って「ビューア」→「ターミナル」を選択します。
ごく簡易的なシリアルターミナルです。TWELITE からのメッセージの確認と、TWELITE に対するメッセージの入力を行えます。
ターミナル画面
画面では、約1秒おきに無線送信したときのメッセージが表示されます。+ + + 入力によるインタラクティブモード画面への遷移も行えます。
(参考: TWELITE STAGE アプリマニュアル )
VSCode でのビルドについて VSCode はソース編集の強力なエディタですが、VSCode上で TWELITE マイコン用のファームウェアをビルドすることも可能です。
VSCode の起動は TWELITE STAGE アプリの「ビルド&書換」メニュー以下のプロジェクト一覧より行います。
ビルドのリスト中の右端 [VSCode] を押してください。
VSCodeの設定
この動作を行うためには TWELITE STAGE アプリの設定が必要です。
STAGE設定で 「code でフォルダを開く(VSCode)」を 1 にしてください。
VSCodeで開く
Windows, Linux, macOS では、デフォルトで上記設定を有効化した TWELITE_Stage_VSCode.{拡張子} の実行形式を配布しています。
すでに VSCode が立ち上がった状態では必要な設定が反映されない場合があります。その場合は、一旦 VSCode を終了して、改めて TWELITE STAGE アプリから VSCode を起動します。
情報の反映のためにシステム環境変数を用いてるため、原理的に、別々のライブラリフォルダを参照する複数の TWELITE STAGE の同時運用では問題が出る場合があります。VSCode 上で Terminal を開き、環境変数 MWSDK_ROOT が適切に設定されている場合はビルドは正常に行われることが期待できます。
VSCode のビルドタスク 最初にビルドしたいワークスペースを開いておきます。TWELITE STAGE SDK添付のワークスペースにはビルドタスクの定義が追加されています。
以下の例では英語インタフェースの画面例で、ワークスペースを開いています。
ワークスペースを開き [Terminal>Run Task...] を選択します。
タスクの実行メニュー
ビルドするTWELITE無線モジュールの種別(BLUE/RED)とアクト名を選択します。以下の例では Build for TWELITE BLUE を選択しています。選択後すぐにビルドが始まります。
ビルドタスクの選択
ビルド中の経過は画面下部のターミナル部分に出力されます。
ビルド経過
正しくビルドできた場合、上記画面例の反転表示部のように .elf ファイルが生成されるメッセージがサイズ情報(text data bss dec hex filenameと記載がある部分)とともに出力されます。
またBINファイル(上記では BRD_APPTWELITE_BLUE_???.bin)ファイルがbuildフォルダ下に出来上がっているはずです。確認してみてください。
VSCodeのタスク定義には Windowsのファイルシステムに適合しないフォルダ名 (例:/c/User/...)を変換する(例:C:/User/...) 定義を追加しています。
下記.vscode/tasks.json 中の変換ルールは完全ではありませんが、出力メッセージ中のドライブ名相当部分の文字列をVSCodeが識別できる形式に書き換えています。この書換によりコンパイルメッセージからエラーが発生しているファイル名と行番号をVSCode中で表示できます。
...
"windows" : {
"command" : "sh" ,
"args" : [
"-c" , "make TWELITE=BLUE 2>&1 | sed -E -e s#\\(/mnt\\)?/\\([a-zA-Z]\\)/#\\\\\\2:/#g"
],
ビルドがうまくいかない場合は、まずエラーメッセージを確認 して下さい。errorという文字列が含まれる行 中のメッセージから、エラー原因が容易に特定できる場合も少なくありません。
また、クリーン(objs_??? フォルダにある中間ファイルの削除)を行い、ビルドを再実行してみてください。(他の環境でビルドした中間ファイルが残っているとmake cleanを含めすべての操作が失敗します)
コマンドラインでのビルド コマンドライン環境でのビルドについて補足します。
コマンドライン(bashやzshなど)の利用についての知識を必要とします。
OS環境によっては各実行プログラムの動作時にセキュリティ警告が出る場合があります。警告を抑制する設定が必要になります。(警告を抑制してプログラムを動作する運用を行うか は、お客自身またはシステム管理者に相談の上、ご判断ください)
Linux, macOS 環境 コマンドラインでのビルドは、bashやzsh(または他のシェル)が動作するウインドウでmakeを実行します。事前に環境変数MWSDK_ROOTが正しく設定されていることを確認してください。例えば/work/MWSDKにインストールした場合は ~/.profile (など)に以下のような設定を行います。
MWSDK_ROOT= /work/MWSDK
export MWSDK_ROOT コマンドラインよりmakeを実行します。makeがない場合はパッケージをインストールする必要があります。
Linuxの場合は、パッケージマネージャからインストールできます(下記はAPTの例)。
または
sudo apt install build-essential macOSの場合は、Command Line Tools for Xcode に同梱されています。
Windows 環境 Windowsでは {MWSTAGE SDK インストール}/MWSDK/WIN_BASH.cmd を実行します。 環境変数や make ユーティリティが設定済みです。
ビルド ビルドは以下のようになります。
cd $MWSDK_ROOT
cd Act_samples/PingPong/build
pwd
/mnt/c/MWSDK/Act_samples/PingPong/build
ls
... ファイル一覧の表示
rm -rfv objs_*
... 念のため中間ファイルを削除
make TWELITE= BLUE
... BLUE用に通常ビルド
make -j8 TWELITE= BLUE
... BLUE用にパラレルビルド( 同時に8プロセス) コマンド例 詳細はMakefileの解説をご覧ください。
make TWELITE=BLUE:TWELITE BLUE用にビルドmake TWELITE=RED:TWELITE RED用にビルドmake cleanall:中間ファイルの削除中間ファイルについて ビルドが行われると objs_??? フォルダが作成され、その中に中間ファイルが生成されます。このファイルはコンパイルした環境に依存しているため、他の環境のファイルが残っているとmakeがエラーとなりビルドが失敗します。
直接 objs_??? フォルダを削除すると make のエラーが解消する場合があります。
4.4 - 新しいプロジェクトの作成 新しいプロジェクトの作成
新しいプロジェクトを作成するには、既存のサンプルアクトのフォルダを別の名前でコピーし、ファイル名の編集を行います。
コピー先のフォルダは MWSDK 配下のフォルダでなくても構いません。ただし、フォルダ名に空白文字や日本語名が含まれてはいけません。
プロジェクトのファイル構造は以下のようになっています(ここでは PingPong を例に挙げます)。
Act_samples
+-PingPong
+-PingPong.cpp : アクトファイル
+-build : ビルドフォルダ
+-.vscode : VSCode 用の設定ファイル
この PingPong フォルダを別の場所(ただしフォルダ名に日本語や空白が含まない)にコピーします。
SomeDir
+-AlphaBravo
+-PingPong.cpp -> AlphaBravo.cpp ※ファイル名を変更
+-build : ビルドフォルダ
+-.vscode : VSCode 用の設定ファイル
編集の必要があるのは、PingPong.cpp のファイル名です。これをフォルダ名と同じAlphaBravo.cppに変更します。
build\build-BLUE.cmd を実行してBINファイルが生成されれば完了です(Windows10)。
Linux/WSL/macOS ではmake TWELITE=BLUEを実行して、ビルドが成功するか確認します。
ビルド定義の編集 ビルド対象のファイルを追加する場合は build/Makefile を編集します。プロジェクト直下にある .c .cpp ファイルは自動で追加されますが、それ以外のファイルについては編集が必要です。
編集方法は Makefile の解説をご覧ください。
VSCode用の設定 VSCode を利用する場合は、必要に応じて .vscode 以下の定義を編集してください。
TWELITE STAGE SDK に含まれるサンプルの多くは、以下のようになっています。
TWELITE STAGE SDK ライブラリのソースコードは ${env:MWSDK_TWENET_LIBSRC}/include/** ${env:MWSDK_TWENET_LIBSRC}/src/** を引用する。この環境変数 MWSDK_TWENET_LIBSRC は TWELITE STAGE アプリから VSCode でプロジェクトを開いた場合には自動で設定されます。 ビルドタスクについては、デフォルトで -D などの追加的なオプション等は設定されていない。 4.5 - actのためのVSCodeのインストール act 開発のために Visual Studio Code をインストールする
このページでは、TWELITE 無線モジュール のファームウェア開発における VSCode の導入について解説しています。汎用的な VSCode の解説はありません。
検索エンジンからお越しいただいたみなさま、申し訳ございません。
超低消費電力が特徴の無線モジュール、TWELITE を覚えていただけると幸いでございます。
act のソースコードの記述を容易に行うために、Visual Studio Code (VSCode) でコード解釈を行うための設定ファイルを同梱しています。
VSCodeはソースファイルやヘッダファイルを読み込み、ソースコードを解釈し、これによりソースコードの記述の助けとなる関数定義情報や、関数・メソッド名の補完などを行うことができます(LSP)。従来のCライブラリと比較して、MWXライブラリでは読み込まれるヘッダファイルの分量が多くなります。環境によってはエディタの動作が重く感じる場合があります。
ソースコードの解析や VSCode からのビルドを行うために、ライブラリソースコードが格納されるフォルダの情報などの情報が必要になります。これらの情報は TWELITE STAGE アプリから VSCode を呼び出すことによって反映されます。(具体的には適切な環境変数を設定して VSCode を始動します。プロジェクトの設定は環境変数を参照しています)
VSCode のインストール
当社サポートでは VSCode のインストール方法、使用方法のお問い合わせについては対応いたしません。一般で得られる情報を参照ください。
環境によっては、インストールのためにセキュリティ設定などが必要になる場合があります。インストールの可否はシステム管理者にご確認の上、手順は配布元や一般の情報を参考にしてください。
VSCode の機能
ソースコードの編集 ソースコード解釈に基づく intellisense(*全ての定義が正確に解釈されることを保証するわけではありません) VSCode は公式サイト より入手してください。
プラグインの導入 Visual Studio Code が C/C++ 言語の記述を解釈できるようにするために、プラグインをインストールします。
C/C++ for Visual Studio Code 各OSでの特記事項 TWELITE STAGE から VSCode を呼び出すために、code コマンドを有効とする必要があります。
以下は code.visualstudio.com の情報です。
注記事項
MWXライブラリのサンプルには .vscode の定義を含めています。この定義は MWSDK_ROOT 環境変数を用い、ライブラリのソースコード({MWSDK_ROOT}/TWENET/current以下)を特定しています。
TWELITE STAGEからVSCodeを始動した場合、上記の環境変数などを設定します。既に始動済みであるような場合など、設定が反映されない場合もあります。
VSCode のソースコードの解釈はコンパイラでの解釈とは完全には一致しません(GCCとclangの違い等による)。またソースコードの編集状況によっては解釈がより不完全な状態になる場合もあります。
4.6 - ビルド定義 Makefile Makefileによるビルド定義
Makefileはbuild/Makefileに格納されています。makeコマンドを実行することで、アクトをビルドするようにあらかじめ定義されています。
MWSDK 2020-04 では、プロジェクトフォルダ中の .cpp ファイルを自動で検出するため、通常は Makefile の修正は不要です。
ソースファイルをサブフォルダに格納するような場合は、編集が必要になります。
MWSDK 2019-12以前では、.cpp ファイルが複数ある場合は、Makefile の編集が必要です。
プロジェクトフォルダを他の環境からコピーしたあとには、必ずbuild/objs_???フォルダを削除してください。他の環境での中間ファイルが残っているとmakeがエラーになります。
(MWSDK 2020-04以降) USE_APPDEPS=0 を付加して clean してから、改めて make コマンドを実行することでエラーを回避できます。
make USE_APPDEPS= 0 TWELITE= BLUE clean
...
make TWELITE= BLUE makeのパラメータ TWELITE= ビルド対象をBLUEまたはREDで指定します。TWELITE BLUEならmake TWELITE=BLUEと指定します。
all ビルドを実行します。通常は省略してmake TWELITE=BLUEのように実行します。
clean ビルドの中間ファイルを削除します。make TWELITE=BLUE cleanのように実行します。
cleanall すべての中間ファイルを削除します。make cleanallのように実行します。buildフォルダのobjs_???フォルダをすべて削除するのと同じです。
USE_APPDEPS=0 または 1 1 (デフォルト) を設定すると、ファイルの依存関係をもとに、ビルドファイルを決定します。例えば、ヘッダファイルに変更があった場合に関連するソースファイルが再コンパイル対象となります。
0 では依存関係を評価しません。0 に設定した場合、矛盾ある中間ファイルが残っていても make がエラーになりません。
Makefile 定義 アクトの規模に応じて、また、ビヘイビアの定義をする場合には、通常はソースファイルを分割してビルドします。
ビルドファイルの一つはプロジェクトフォルダ名.cppです。
他にファイルを定義する場合は、プロジェクトフォルダのbuild/Makefileを編集します。
下記はサンプルPAL_AMB-bihaviorでのMakefileの例です。
##############################################################################
# Copyright (C) 2019 Mono Wireless Inc. All Rights Reserved.
# Released under MW-SLA-*J,*E (MONO WIRELESS SOFTWARE LICENSE
# AGREEMENT).
##############################################################################
# USER PROJECT BUILD DEFINITION.
##############################################################################
#####################################################################
## set TWELITE model
TWELITE ?= BLUE
#TWELITE = RED
#####################################################################
## set application version (MUST SET THIS.)
VERSION_MAIN = 0
VERSION_SUB = 1
VERSION_VAR = 0
#####################################################################
## set an additional source file
## the default file name is dirname.
## for C++ files compiled with g++ (must have .cpp suffix)
APPSRC_CXX += myAppBhvParent.cpp
APPSRC_CXX += myAppBhvParent-handlers.cpp
APPSRC_CXX += myAppBhvChild.cpp
APPSRC_CXX += myAppBhvChild-handlers.cpp
## for C files compiled with gcc (must have .c suffix)
#APPSRC += my_c_file.c
## Additional Src/Include Path
# if set, find source files from given dirs.
#
APP_COMMON_SRC_DIR_ADD1 = ../Parent
APP_COMMON_SRC_DIR_ADD2 = ../Child
#APP_COMMON_SRC_DIR_ADD3 =
#APP_COMMON_SRC_DIR_ADD4 =
#####################################################################
## set misc option for compiler
## C++ flags passed to g++
# e.g. CXXFLAGS += -DMY_DEFS
#CXXFLAGS +=
## C++/C flags passed to g++/gcc
# e.g. CFLAGS += -DMY_DEFS
#CFLAGS +=
## include opts
# e.g. INCFLAGS += -I../my_common_src/
#INCFLAGS +=
## optimize flag (default is -Os, normally no need to change)
#OPTFLAG=-O2
#####################################################################
## must include mwx.mk (the makefile body part.)
MWSDK_PATH?= $( realpath $( MWSDK_ROOT))
include $( MWSDK_PATH) /MkFiles/mwx.mk
#####################################################################
VERSION_??? バージョン番号を指定します。ビルド結果ファイル名に反映されます。
## set application version (MUST SET THIS.)
VERSION_MAIN = 0
VERSION_SUB = 1
VERSION_VAR = 0
コンパイル中は -DVERSION_MAIN=0 -DVERSION_SUB=1 -DVERSION_VAR=0のように定義として渡されます。
ソースファイルの追加
(MWSDK 2020-04以降) サブフォルダにファイルを配置しない場合は、追加指定は不要になりました。プロジェクトファイルにある .c .cpp ファイルがすべて追加されます。
ソースファイルを追加する際に必要なのはAPPSRC_CXXとAPP_COMMON_SRC_DIR_ADD?です。
サブフォルダにソースファイルを配置する場合は必ずフォルダ APP_COMMON_SRC_DIR_ADD? の指定が必要です。
ソースファイル名をAPPSRC_CXXに追記します。このファイル名にはフォルダ名が含まれてはいけません。サブフォルダにあるものもフォルダなしで指定します(つまり同じファイル名がサブフォルダにある場合は、ビルドが失敗します)
APPSRC_CXX += myAppBhvParent.cpp
APPSRC_CXX += myAppBhvParent-handlers.cpp
APPSRC_CXX += myAppBhvChild.cpp
APPSRC_CXX += myAppBhvChild-handlers.cpp
次にソースファイルがプロジェクトフォルダ以外の場所に格納されている場合の検索パスを指定します。最大4つ まで設定できます。
APP_COMMON_SRC_DIR_ADD1 = ../Parent
APP_COMMON_SRC_DIR_ADD2 = ../Child
フォルダの指定はMakefileからの相対パス になります。
コンパイル・リンカオプション その他にもいくつかのオプションをコンパイラ・リンカに渡すことができます。
指定 内容 CXXFLAGSC++ソースファイルに対してコンパイルオプションを指定します。 CFLAGSC/C++ソースファイルに対してコンパイルオプションを指定します。 INCFLAGSヘッダファイルのインクルードファイルを指定します。 OPTFLAGS特別な理由があって-Os以外のコンパイルオプションを適用したい場合に定義します。 LDFLAGSリンカオプションを指定します。(上記Makefileのコメントには記述はありませんが指定できます)
4.7 - 他のプラットフォーム 他のプラットフォームの使用
他のプラットフォームでも一部の機能(serparser, pktparser, コンソール用Serialオブジェクト)をビルドできるように、ビルド定義を用意しています。必要なファイルのみを切り出しています。
ビルド定義は{mwxライブラリ格納}/stdioフォルダに格納しています。ビルド方法はREADME.md (リンクはGitHub上)を参照してください。
C++11でのコンパイルが出来ること。 C++11の標準ライブラリヘッダが利用できること (utility, algorithm, functional, iteratorなど) new/delete/virtualは使用しません。newによるメモリ確保は例外的に使用する場合があります。serparser/pktparserでnew演算子を利用するalloc_heapではdeleteによる処理を行っています。(参考) ただしmwxライブラリとしてはdeleteについては考慮しない前提で設計されている部分もあります。