WindowsでEtherCATマスター

Windows PCでLANポートを用いてEtherCATマスターを動作させる方法のメモ。
(2019/12/29 加筆修正)

SOEMとは?

SOEM (Simple Open EtherCAT Master) とは、Open EtherCAT Society が提供しているオープンソースの小規模なEtherCATマスターのスタック。ソースコードGitHubで公開されている。ちなみにEtherCATスレーブのスタックとして SOES (Simple Open EtherCAT Slave) も提供されている。

SOEMのファイル構成

f:id:licheng:20191229124419p:plain

SOEMのビルド

mkdir build
cd build
cmake .. -G "NMake Makefiles"
nmake
  • 成功するとbuild/test/linux/slaveinfo/slaveinfo.exe などのサンプルプログラムのバイナリができる
    • win32フォルダでなくlinuxフォルダだが気にしない

サンプルプログラム slaveinfo

サンプルプログラム slaveinfo はスレーブ機器の情報を取得するプログラムである。
まず引数なしで実行すると、ネットワークインターフェース一覧が表示される。

cd test\linux\slaveinfo
slaveinfo.exe

【実行結果1】

SOEM (Simple Open EtherCAT Master)
Slaveinfo
Usage: slaveinfo ifname [options]
ifname = eth0 for example
Options :
 -sdo : print SDO info
 -map : print mapping
Available adapters
Description : NICの名前1: \Device\NPF_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
Description : NICの名前2: \Device\NPF_{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY}
Description : NICの名前3: \Device\NPF_{ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ}
End program

次に下記のようにネットワークインターフェースを指定して実行する。

slaveinfo.exe \Device\NPF_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

【実行結果2】
スレーブ機器が未接続の場合は No slaves found! となる。

SOEM (Simple Open EtherCAT Master)
Slaveinfo
Starting slaveinfo
ec_init on \Device\NPF_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} succeeded.
No slaves found!
End slaveinfo, close socket
End program

【実行結果3】
スレーブ機器としてArduino Uno + EasyCAT Shield (詳しくはこちらの記事を参照) を2台接続した場合。
2台のスレーブ機器の情報が表示される。

SOEM (Simple Open EtherCAT Master)
Slaveinfo
Starting slaveinfo
ec_init on \Device\NPF_{B6BA5E14-3DA8-4D53-A579-7557EC6F1195} succeeded.
2 slaves found and configured.
Calculated workcounter 6

Slave:1
 Name:EasyCAT 32+32 rev 1
 Output size: 256bits
 Input size: 256bits
 State: 4
 Delay: 0[ns]
 Has DC: 1
 DCParentport:0
 Activeports:1.1.0.0
 Configured address: 1001
 Man: 0000079a ID: 00defede Rev: 00005a01
 SM0 A:1000 L:  32 F:00010064 Type:3
 SM1 A:1200 L:  32 F:00010020 Type:4
 FMMU0 Ls:00000000 Ll:  32 Lsb:0 Leb:7 Ps:1000 Psb:0 Ty:02 Act:01
 FMMU1 Ls:00000040 Ll:  32 Lsb:0 Leb:7 Ps:1200 Psb:0 Ty:01 Act:01
 FMMUfunc 0:1 1:2 2:0 3:0
 MBX length wr: 0 rd: 0 MBX protocols : 00
 CoE details: 00 FoE details: 00 EoE details: 00 SoE details: 00
 Ebus current: 0[mA]
 only LRD/LWR:0

Slave:2
 Name:EasyCAT 32+32 rev 1
 Output size: 256bits
 Input size: 256bits
 State: 4
 Delay: 740[ns]
 Has DC: 1
 DCParentport:1
 Activeports:1.0.0.0
 Configured address: 1002
 Man: 0000079a ID: 00defede Rev: 00005a01
 SM0 A:1000 L:  32 F:00010064 Type:3
 SM1 A:1200 L:  32 F:00010020 Type:4
 FMMU0 Ls:00000020 Ll:  32 Lsb:0 Leb:7 Ps:1000 Psb:0 Ty:02 Act:01
 FMMU1 Ls:00000060 Ll:  32 Lsb:0 Leb:7 Ps:1200 Psb:0 Ty:01 Act:01
 FMMUfunc 0:1 1:2 2:0 3:0
 MBX length wr: 0 rd: 0 MBX protocols : 00
 CoE details: 00 FoE details: 00 EoE details: 00 SoE details: 00
 Ebus current: 0[mA]
 only LRD/LWR:0
End slaveinfo, close socket
End program

さらに下記のようにオプションに -map を指定して実行する。

simple_test.exe \Device\NPF_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} -map

スレーブ機器の情報に追加してPDOマッピング情報が表示される。

(前略)
Slave:1
 Name:EasyCAT 32+32 rev 1
(中略)
PDO mapping according to SII :
  SM0 RXPDO 0x1600 Outputs
     addr b   index: sub bitl data_type    name
  [0x0000.0] 0x0005:0x01 0x08 UNSIGNED8    Byte0
  [0x0001.0] 0x0005:0x02 0x08 UNSIGNED8    Byte1
  [0x0002.0] 0x0005:0x03 0x08 UNSIGNED8    Byte2
(中略)
  [0x001D.0] 0x0005:0x1E 0x08 UNSIGNED8    Byte29
  [0x001E.0] 0x0005:0x1F 0x08 UNSIGNED8    Byte30
  [0x001F.0] 0x0005:0x20 0x08 UNSIGNED8    Byte31
  SM1 TXPDO 0x1A00 Inputs
     addr b   index: sub bitl data_type    name
  [0x0040.0] 0x0006:0x01 0x08 UNSIGNED8    Byte0
  [0x0041.0] 0x0006:0x02 0x08 UNSIGNED8    Byte1
  [0x0042.0] 0x0006:0x03 0x08 UNSIGNED8    Byte2
(中略)
  [0x005D.0] 0x0006:0x1E 0x08 UNSIGNED8    Byte29
  [0x005E.0] 0x0006:0x1F 0x08 UNSIGNED8    Byte30
  [0x005F.0] 0x0006:0x20 0x08 UNSIGNED8    Byte31

Slave:2
(後略)

サンプルプログラム simple_test

サンプルプログラム simple_test は簡単な通信テストのプログラムである。
下記のようにネットワークインターフェースを指定して実行する。

cd test\linux\simple_test
simple_test.exe \Device\NPF_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}

するとスレーブとの通信が周期的に行われ、その様子が表示される。

SOEM (Simple Open EtherCAT Master)
Simple test
Starting simple test
ec_init on \Device\NPF_{B6BA5E14-3DA8-4D53-A579-7557EC6F1195} succeeded.
2 slaves found and configured.
Slaves mapped, state to SAFE_OP.
segments : 1 : 128 0 0 0
Request operational state for all slaves
Calculated workcounter 6
Operational state reached for all slaves.
^Cocessdata cycle 2818, WKC 6 , O: 00 00 00 00 00 00 00 00 I: 02 14 00 00 02 4b 00 41 T:630773536452882240

…が、正直なところこの表示だけを見てもピンと来ない。
ソースファイルはtest\linux\simple_test\simple_test.cにあるので、ソースを解読したり書き換えて実験したりして理解を深める。

おまけ:ネットワークインターフェース名の取得方法いろいろ

ネットワークインターフェース名は、PowerShellで下記を実行しても取得できる。

Get-NetAdapter | select Name,DeviceName

【実行結果】

Name                DeviceName
----                ----------
NICの名前1 \Device\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
NICの名前2 \Device\{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY}
NICの名前3 \Device\{ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ}

また、ネットワークインターフェース名は、C#アプリからは下記のようにして取得できる。

using System;
using System.Net.NetworkInformation;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var interfaces = NetworkInterface.GetAllNetworkInterfaces();
            foreach (var ni in interfaces)
            {
                Console.WriteLine($"{ni.Id},{ni.Name}");
            }
        }
    }
}

【実行結果】

{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX},NICの名前1
{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY},NICの名前2
{ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ},NICの名前3

Herokuアプリをスリープさせない対策

Herokuアプリの無料枠だとアクセスが30分間無いとスリープしてしまう。
スリープさせない簡単な方法はHeroku Schedulerを使うこと。

手順

  • Herokuにログインする (アプリはすでにあるものとする)
  • Dashboard画面右上のメニューの「Elements」をクリック
  • Heroku Elementsで「Heroku Scheduler」を検索
  • 「Add-ons」の「Heroku Scheduler」を選択
  • 「install Heroku Scheduler」をクリック
  • 「App to provision to」で自分のアプリ名を検索して選択
  • 「Provision add-on」でアプリに追加する
  • アプリの「Resources」の「Add-ons」に「Heroku Scheduler」が追加されている
  • 「Heroku Scheduler」を開いて以下の設定をする
    • $ の欄に「curl https://アプリ名.herokuapp.com/」を設定
    • 「Frequency」に「Every 10 minutes」を設定

Node-REDでMongoDB

ここではHeroku上のNode-REDでのMongoDBの扱い方について説明する。HerokuでのNode-RED環境構築や、HerokuのMongoDBアドオンの使い方については前記事を参照。

MongoDBのノード

Node-REDでMongoDBを扱うためのノードはいくつかある。

このほか、Bluemix用のnode-red-bluemix-nodesにもMongoDBを扱うノードが含まれる。
ここでは比較的多機能なnode-red-contrib-mongodb2を使ってみる。node-red-contrib-mongodb3もAPIのバージョンが異なるもののほぼ使い方は同じと思われる。

パレットにmongodb2ノードを追加

  • Node-RED画面右上のメニューの「パレットの管理」を開く
  • 「ノードの追加」タブで「node-red-contrib-mongodb2」を検索し「ノードを追加」
  • 左側ペインのノードパレットにmongodb2のノードが追加される
  • ノードは1種類しかない。後述するようにノードの設定またはmsgで機能(API)を指定する

f:id:licheng:20190218090808p:plain

データベースサーバーの設定

  • パレットからmongodb2ノードをフローに置く
  • ノードをクリックして設定を開く
  • 「Server」の鉛筆マークをクリックし、MongoDBサーバーの設定を入力して「更新」
    (前記事の要メモ事項を参照)
    • URI」: mongodb://ドメイン名:ポート番号/データベース名
    • 「Name」: 区別のために任意の名前をつける
    • 「Username」: ユーザー名
    • 「Password」: パスワード

f:id:licheng:20190218091942p:plain

ノードの設定

  • 「Service」は「External seivice」を選択
  • 「Server」は上記で設定したデータベースサーバーの名前を選択
  • 「Collection」は処理の対象とするMongoDBのコレクション名を指定
    ※ 空欄にして msg.collection で指定することもできる
  • 「Operation」で機能(API)を選択する
    ※ Dynamic (msg.operation)」を選択して msg.operation で指定することもできる

f:id:licheng:20190218091955p:plain

使い方のサンプル

いくつかの機能(API)の使い方のサンプルを以下に示す。下記JSONファイルの内容をコピーして、Node-REDの右上メニューの「読み込み」>「クリップボード」で貼り付け。データベースの設定は、各自の環境に合わせて前述のように設定のこと。

f:id:licheng:20190217213844p:plain:w800

insert (挿入)

  • mongodb2ノードの「Operation」を「insert」に設定する。
  • ノードの入力の msg.payload に挿入したいドキュメントをオブジェクト形式またはJSON形式で格納する。
  • このサンプルでは https://アプリ名.herokuapp.com/insert にブラウザでアクセスすると insert が実行され、結果がデバッグメッセージとブラウザに表示される。
// 例
// msg.payload = { 'name' : 'Alexander', 'age' : 32 }; // JSON形式
msg.payload = { name : 'Alexander', age : 32 }; // オブジェクト形式
return msg;



以下のAPIの動作確認のため、データベースに下記のようなドキュメントを作成しておく。「_id」は各ドキュメントが必ずユニークな値を持つキーであり、ドキュメント作成時に自動で生成される。
f:id:licheng:20190217212720p:plain

find (検索)

  • mongodb2ノードの「Operation」を「find.toArray」に設定する。
  • ノードの入力の msg.payload に検索条件を格納する。下記の例では age が 60未満のドキュメントを検索する。
  • ノードの出力の msg.payload に見つかったドキュメントの配列が格納される。
  • このサンプルでは https://アプリ名.herokuapp.com/findにブラウザでアクセスすると find.toArray が実行され、結果がデバッグメッセージとブラウザに表示される。
// 例
msg.payload = { age: { $lt: 60 } };
return msg;

findOne (一つだけ検索)

  • mongodb2ノードの「Operation」を「findOne」に設定する。
  • ノードの入力の msg.payload に検索条件を格納する。下記の例では name が Alexanderであるドキュメントを検索する。
  • ノードの出力の msg.payload に見つかったドキュメントが格納される。
  • このサンプルでは https://アプリ名.herokuapp.com/findOneにブラウザでアクセスすると findOne が実行され、結果がデバッグメッセージとブラウザに表示される。
// 例
msg.payload = { name : 'Alexander' };
return msg;

findOneAndUpdate (一つだけ検索し更新)

  • mongodb2ノードの「Operation」を「findOneAndUpdate」に設定する
  • ノードの入力の msg.payload に検索条件と更新値のペアを配列で格納する。下記の例では name が Alexanderであるドキュメントを検索し、age を 33 に更新する。
  • このサンプルでは https://アプリ名.herokuapp.com/updateにブラウザでアクセスすると findOneAndUpdate が実行され、結果がデバッグメッセージとブラウザに表示される。
// 例
msg.payload = [
    { name : 'Alexander'},
    { name : 'Alexander', age : 33 }
    ];
return msg;

concrete5のページをhttpからhttpsへリダイレクト

.htaccessに以下の2行追加するだけ。

RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

.htaccess全体は以下の通り。

DirectoryIndex index.php index.html index.cgi

# -- concrete5 urls start --
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}/index.html !-f
RewriteCond %{REQUEST_FILENAME}/index.php !-f
RewriteRule . index.php [L]
</IfModule>
# -- concrete5 urls end --

MPU-6050系モーションセンサまとめ

6軸モーションセンサではSTマイクロのLSM6DS3とならんでメジャーなTDK InvenSenseのMPU-6050。派生型番がいろいろあってややこしいのでまとめ。

f:id:licheng:20190216221214p:plain:w500

  • MPU-6050はI2Cのみで4mm角QFN。
  • MPU-6500はI2C/SPIで3mm角QFNだけどあまり見かけない。
  • MPU-9150 = MPU-6050 + AKM8975 の9軸だけど既にディスコン
  • MPU-9250 = MPU-6500 + AKM8963 の9軸。

これらMPU-xxxxがたぶん旧InvenSenseの型番でスイッチサイエンスとかでモジュール基板が手に入りやすい。しかし、新規に基板を起こすなら非推奨。以下のようなICM-xxxx型番のものを採用すべし。ただ、ICM型番のものはまだモジュール基板はあまり出回っていないようだ。

  • ICM-20689はMPU-6050と同じ4㎜角QFNの6軸でI2C/SPI、ただしDMP無し。
  • ICM-20648/20948はMPU-6500/9250と同じ3㎜角QFNの6軸/9軸。
  • ICM-20602は3mm角LGA(手ハンダ不可能!)の6軸、DMP無し 。

おもなピンの配置はおおむね同じだけど若干異同あり。また、特性のパラメータにも異同あるので必ずメーカーのカタログとデータシートを参照のこと。

HerokuのMongoDBアドオン

データベースのPaaSというと、選択肢はここに書ききれないくらい多いと思う。また、Node-REDでノードが用意されているデータベースというのも1ダースくらいはある。(こちらの記事を参照→Node-REDで扱えるDBノード総まとめ - Qiita)
ここではHerokuのアドオンでmLab MongoDBを使う方法を紹介する。mLab MongoDBはMongoDBのPaaSである。ちなみにHerokuボタンでNode-REDをデプロイすると、もれなくmLab MongoDBのアドオンがついてくる。また、Node-REDにはMongoDBのノードが用意されている。(これについては別記事 Node-REDでMongoDB - 滴了庵日録 を参照。)

MongoDBとは

  • いわゆるNoSQLのひとつ。つまりRDBではない。
  • スキーマレスである。つまり好きなときに動的にフィールドを追加できる。
  • つまり正規化もなにもあったもんじゃない。
  • データはJSON形式で保存される。(正確にはBSON=バイナリ型JSON)
  • RDB用語との対応は下表のようなかんじ。
RDB MongDB
テーブル コレクション
レコード ドキュメント
カラム フィールド

手順

※ HerokuボタンでNode-REDをデプロイした場合、7までの手順は不要

  1. Herokuにログインする (アプリはすでにあるものとする)
  2. Dashboard画面右上のメニューの「Elements」をクリック
  3. Heroku Elementsで「MongoDB」を検索
  4. 「Add-ons」の mLab MongDB を選択
  5. 「install mLab MongoDB」をクリック
  6. 「App to provision to」で自分のアプリ名を検索して選択
  7. 「Provision add-on」でアプリに追加する
  8. アプリの「Resources」の「Add-ons」に「mLab MongoDB」が追加されている
  9. 「mLab MongoDB」を開くと詳細が表示される
  10. データベース名、サーバーURI、ユーザー名を確認する
    ※ デフォルトのユーザーはデータベース名と同名である
  11. 画面右上の「user: ユーザー名」からユーザー設定画面を開き、パスワードを設定する
  12. または、「Users」の「Add database user」で適宜ユーザー名/パスワードを設定する
    ※ なぜかデフォルトのユーザーではNode-REDからアクセスできなかった (要調査)
  13. 「Collections」の「Add collection」で適宜コレクションを作成する

要メモ事項

  • データベース名: heroku_mg??????
  • サーバーURI: mongodb://ds??????.mlab.com:ポート番号/データベース名
  • ユーザー名 / パスワード
  • コレクション名

※ ユーザー名 / パスワードをURIに含める場合は、
mongodb://ユーザー名:パスワード@ds??????.mlab.com:ポート番号/データベース名

参考サイト

qiita.com

HerokuのCloudMQTTアドオン

MQTTブローカーのPaaSはCloudMQTTが手軽で便利。ふつうにユーザー登録して使ってももちろんいいけど、Heroku上のアプリからCloudMQTTを使うならアドオンを利用すれば登録の手間がなくてなお便利。

手順

  1. Herokuにログインする (アプリはすでにあるものとする)
  2. Dashboard画面右上のメニューの「Elements」をクリック
  3. Heroku Elementsで「CloudMQTT」を検索
  4. 「Add-ons」の CloudMQTT を選択
  5. 「install CloudMQTT」をクリック
  6. 「App to provision to」で自分のアプリ名を検索して選択
  7. 「Provision add-on」でアプリに追加する
  8. アプリの「Resources」の「Add-ons」に「CloudMQTT」が追加されている
  9. 「CloudMQTT 」を開くと詳細が表示される
  10. 下記の要メモ事項を確認する

要メモ事項

  • サーバー: m??.cloudmqtt.com
  • ユーザー名 / パスワード
  • SSLポート番号
  • WebSocketポート番号 (WebSocketで使う場合)