オブジェクト初期化子

C#って、

    class Hoge
    {
        public int a;
        public int b;
        public int c;
    }

というクラスに対して

    var hoge = new Hoge() { a = 1, b = 2, c = 3 };

という初期化の書き方ができるらしい。いま知った。
オブジェクト初期化子というらしい。

    var hoge = new Hoge { a = 1, b = 2, c = 3 };

とも書けるようだ。
いや、意味はパッと見で分かるんだけど、文法知らないといささか面食らう。

EtherCATネタまとめ

個人的に今年取り組んだ最大のネタはEtherCATでした。今年の成果をまとめます。

f:id:licheng:20191228114758j:plain

EtherCATのSDOとかPDOとか

EtherCATに関する文章を読んでいて、何のことわりもなく唐突にSDOとかPDOとかいう異質な言葉が出て来て面食らったことはないですか?

SDOとかPDOとかってCANの用語じゃないの?

SDOとかPDOとかいうのは、EtherCAT用語というよりは本来はCANopen用語のはず。EtherCATの上位層プロトコルのひとつであるCoE(CANopen over EtherCAT)において用いられる概念です。…いや、たぶんそのはずなのですが、EtherCATの話の中で特にCoEとことわることなくSDOとかPDOとかいう言葉が使われることが多い感じがします。

そもそもCANopenというのは、その名から分かるようにCANの上位層プロトコルとして作られたものですが、EtherCATの上にも載ります。それがCoE(CANopen over EtherCAT)です。さらにCANopenの上位層として、例えばモータ等を制御するCiA402ドライブプロファイルなどがあります。

イメージとしては下図のような感じです。(わりとテキトーに描いた図なのでレイヤーの高さはいいかげんかも…)

f:id:licheng:20191225123152p:plain

SDOとPDOのちがい

まあ、SDOとPDOについての説明はさんざん既出だと思うので、こんな辺鄙なブログでわざわざ語るようなことでもありませんが、いちおう簡単に触れておきます。SDOはマスターが通信したいときに通信したいスレーブに要求を投げてデータを書いたり読んだりする通信です。それに対してPDOはマスターと全スレーブが予め示し合わせて周期的に一斉に読み書きをする通信です。言うまでもなく、PDOを使ってこそEtherCATの本領である低レイテンシ・低ジッタを発揮できます。

CiA402

モータ等を制御するCiA402ドライブプロファイルを例にとってみましょう。CiA402には以下のようなOD(オブジェクトディクショナリー)が定義されています。まあ、BLEでいうキャラクタリスティックの定義のようなものです。IndexというのはBLEでいうUUIDのようなものです。そして各ODにはデータ型(整数型や浮動小数点型など)、アクセス(Read&WriteかRead Onlyか)、名前(それが何のデータか)が定義されています。
そして、SDOでは全てのODのデータにアクセスできますが、PDOではすべてのODのデータを周期通信データにマッピングできるわけではありません。 CiA402のODから一部抜粋して下表に示します。

Index(Hex) Name Type Access PDO Mappable?
6040/0 コントロールワード UINT16 RW Yes
6041/0 ステータスワード UINT16 RO Yes
6060/0 動作モード INT8 RW Yes
6071/0 目標トルク INT16 RW Yes
6072/0 最大トルク UINT16 RW No
6077/0 現在トルク INT16 RO Yes

お分かりでしょうか? この中では最大トルクがPDOにマッピングできませんね。目標トルクや現在トルクは常々設定・取得し続けなければならないものでPDOで通信すべきです。それに対して、最大トルクというのはふつうは一度設定すればそうそう変更するものではありません。だから最大トルクはSDOでのみアクセスとなっているのでしょう。まあ、それ言うと動作モード(トルク制御、速度制御、位置制御などのモード)だってそうそう変更するものではないと思いますが…?

今日の駄文はここまでです。わりとテキトーなことを書いたので詳しくはちゃんとした仕様書を読んでください。

ExcelマクロでEtherCATの制御

EtherCATについて語る Advent Calendar 2019 はもう埋まりそうなので、こちらはニッチすぎる番外編記事です。

やりたいこと

オープンソースのEtherCATマスターであるSOEMをDLL化し、ExcelVBAマクロから呼び出せるようにする。これによって、ExcelからEtherCATスレーブの制御が可能となり、Excel上で自動計測とデータ処理ができるようになる。

SOEMのDLL化

SOEMのDLL化については、以前の記事「EtherCATマスターSOEMを.NETで使う」に書いた。ここで作成したsoemlib.dllを使用する。(ただし、今回DLLをExcelから呼び出すにあたって不都合があったので少し加筆修正した。)
lipoyang.hatenablog.com

Excelマクロからの呼び出し

VBAで下記のようにDLL(soemlib.dll)のAPIを宣言する。

' soemlib.dll のAPI
Declare Function soem_open Lib "soemlib.dll" (ByVal nic As String) As Integer
Declare Sub soem_close Lib "soemlib.dll" ()
Declare Function soem_config Lib "soemlib.dll" () As Integer
Declare Function soem_transferPDO Lib "soemlib.dll" () As Integer

ただし、DLLはパスの通っているディレクトリにないと読み込めない。パスの通ってないディレクトリにDLLを置く場合には下記のようにしてDLLを読み込む必要がある。

Private Declare PtrSafe Function LoadLibrary Lib "kernel32.dll" _
            Alias "LoadLibraryA" (ByVal fileName As String) As Long

' 初期化
Sub ethercat_init()
    ' soemlib.dll の読み込み
    LoadLibrary ("C:\tool\SOEM\build\test\linux\soemlib\soemlib.dll")
    
End Sub

あとは、ふつうにVBAからDLLのAPIを呼び出すことができる。

    ret = soem_findAdapters()
    If ret = 0 Then
        MsgBox ("ネットワークアダプタが見つかりません")
        Exit Sub
    End If

自動計測の実験

ためしに簡単な自動計測装置を作ってみた。Arduinoで作ったEtherCATスレーブ(上記記事を参照)にマイクロサーボと可変抵抗を接続し、マイクロサーボと可変抵抗の回転軸を連結した。

f:id:licheng:20191220221316p:plain

f:id:licheng:20191220232828j:plain:w480

サーボの角度を0°から180°まで10°ずつ変化させ、そのときの可変抵抗のADC値を測定するマクロを以下に示す。

' 計測
Sub ethecat_measure()
    
    ' サーボの角度 0°から180°まで10°ずつ
    For i = 0 To 18
        ' 10msec周期で100回繰り返す
        For j = 0 To 100
            ' サーボの角度
            deg = i * 10
            soem_setOutputPDO 1, 0, deg
            ' 転送
            ret = soem_transferPDO()
            ' 可変抵抗のADC値
            h = soem_getInputPDO(1, 0)
            l = soem_getInputPDO(1, 1)
            volume = (h * (2 ^ 8)) + l
            ' 10msec待つ
            Sleep (10)
            ' これを入れないと画面が固まる
            DoEvents
        Next
        ' 表へ記入
        Cells(2 + i, 1).value = deg
        Cells(2 + i, 2).value = volume
    Next
End Sub


これを実行すると自動計測がおこなわれ、下図のようなグラフが得られた。

f:id:licheng:20191220223705p:plain

注意事項

  • VBAは昔のVB6と同じでスレッドは使えない。なので時間のかかるループ処理ではDoEventsを入れないと画面が固まる。
  • 上の例では10msecごとに通信をおこないつつ、サーボの(メカ的な)応答待ちのために1秒待っている。通信せずに1秒待つとなぜかOutputPDOの値がリセットされてしまう。マスター側でリセットされるのかスレーブ側でリセットされるのか、不具合なのか仕様なのか、要調査。

動画


ソース

今回作成したマクロ入りExcelシートを参考までに置いておく。

また、EtherCATスレーブのソースは下記のものを使用した。
github.com

ロボットの体内ネットワークとしてのEtherCAT

この記事は EtherCATについて語る Advent Calendar 2019 の19日目です。

昨日は@nonNoiseさんの EtherCAT 動画集(デモストレーション編) でした。


【注意!】 今日の記事はかなり偏った見解を含んでいる可能性があります。

今日はロボットに使われる通信方式のお話です。多足歩行ロボットや車輪走行ロボットのようなロボットの体内にはさまざまなセンサ、モータ、マイコン、無線モジュールなどが搭載され、それらは互いに有線で接続され通信しあって動作します。そのような通信網をここではロボットの体内ネットワークと呼ぶことにします。ロボットの体内ネットワークには種々の通信方式が用いられます。

f:id:licheng:20191217202917p:plain

ロボットの体内ネットワークによく用いられる通信方式を以下に示します。

通信方式 通信速度 リアルタイム性 通信距離 コスト・
難易度
上位層
プロトコル
UART ~数Mbps程度 ~1m程度
I2C ~400kbps ~1m程度
SPI ~20Mpbs程度 ~1m程度
RS-485 ~10Mpbs程度 ~1200m
(@100kbps)
CAN ~1Mbps ~40m
(@1Mbps)
Ethernet
(TCP/IP)
~1000Mbps × ~100m
EtherCAT ~100Mbps ~100m

UART

f:id:licheng:20191216203031p:plain

いわゆる「シリアル通信」です。昔からある通信方式で、今でもほとんどのマイコンに搭載されています。

基本的には一対一の双方向通信となります。マイコンうしの通信や、無線モジュールとの通信に用いられることが多いです。デバッグや実験のためのログ出力に用いることも多いでしょう。

USBシリアル変換ICをUSBハブに挿しまくって仮想シリアルポートだらけの一対多通信(?)をするという荒業もあります(笑)

I2C / SPI

f:id:licheng:20191216203051p:plain

I2CとSPIはUARTとならんでよく使う通信方式です。これらもほとんどのマイコンに搭載されています。

近ごろではI2CやSPIのインターフェースを持ったセンサICやモータドライバICなどが安く手に入るようになり、Arduinoとかでライブラリが用意されることが多いので趣味のロボット開発でもよく使われています。

しかし、I2Cはオープンドレインという電気的な仕様上、高速通信には向きませんしノイズにも弱いです。また、I2Cは1個のスレーブがトチ狂ってバスを握ってしまうとネットワーク全体が死ぬという弱点があります。I2Cは基板上の通信かごく短い基板間の通信に使うものです。長く伸ばしたI2Cケーブルをモータの電源ケーブルと束ねたりするのはホントにやめてください!

SPIはI2Cに比べれば高速で、ノイズ耐性もマシとはいえ決して強いとはいえません。

RS-485

f:id:licheng:20191216203108p:plain

UARTにRS-485トランシーバを接続することで実現できます。半二重通信になるので通常のUARTよりやや処理が面倒になりますが、さほどの難易度ではありません。

差動信号を用いるので通常のUARTやI2C、SPIに比べてノイズ耐性は高く、通信距離を長く伸ばせます。ホビーロボットではあまり用いることがありませんが、ある程度本格的なロボットではよく用いられます。一部のシリアルサーボにはRS-485を用いるものがあります。

上位層のプロトコルは特に標準化されてないので、オレオレプロトコルになりがちです。オレオレプロトコルの問題点は同一バス上で共存できないことです。いちおうModbusというFA業界でデファクトスタンダートなプロトコルもあるにはあります。

CAN

f:id:licheng:20191216203126p:plain

車載で用いられる通信方式です。最近ではマイコンに搭載されることも多くなりましたが、やはりCANを搭載するのはミドルレンジ以上のマイコンが多いように思います。

今まで挙げた通信方式と比べてソフトウェアの処理がすこし複雑です。上位層のプロトコルとしてCANopenが存在します。ハイエンドなモータドライバにはCAN/CANopenに対応したものがあります。RS-485と同様に、ホビーロボットではあまり用いることがありませんが、ある程度本格的なロボットではよく用いられます。

ただし、最大1Mbpsと通信速度が低いのが難点です。

Ethernet (TCP/IP)

f:id:licheng:20191216203140p:plain

Ethernetについては説明不要でしょう。やはりEthernetを搭載するマイコンというとハイエンド寄りのものに限られます。ソフトウェア処理の負荷も、今まで挙げた通信方式と比べて各段に高いです。加えてリアルタイム性が無いというのがロボットの制御にとっては致命的な欠点です。スループットこそ抜群に高いEthernetですが、ロボットの制御においてはスループットの高さよりもリアルタイム性 (レイテンシの低さ)こそが命です。

EtherCAT

f:id:licheng:20191216203158p:plain

そこで我らがEtherCATです。

Ethernet(100BASE-T)に基づく100Mbpsの通信容量を無駄なく使う高いスループットと低いレイテンシを両立し、通信距離もノード間最大100mとロボットの体内ネットワークとしては十分すぎる長さであり、差動信号のためノイズ耐性もあり、そしてCoE(CANopen over EtherCAT)という標準化された上位層プロトコルが用意されています。ハイエンドなモータドライバにはEtherCATに対応したものがあります。

欠点は、部品コストが高いこと、ソフトウェア負荷が高いこと、技術的な難易度が高いこと、そして、やってる人が少ない (=情報が少ない) ことです(涙)。

なぜそんなにEtherCATを使いたいか?

ロボットの制御とは物理の計算であり、物理の計算とは微積分です。時間微分・時間積分を正確に計算するためには⊿Tが可能な限り正確で可能な限り小さいことが求められるのです。⊿Tとはすなわちデータ更新周期であり、すなわちそれは通信周期です。

f:id:licheng:20191217231425p:plain

そしてロボットは多数のセンサとモータのかたまりです。そのため通信量も大きくなります。かりに10個のモータ、10個のセンサと各々16バイトずつの通信をしたいとします。通信周期を1msec(1000Hz)にするには、(10+10)×16×8×1000 bps = 10.24Mbps以上の速度が最低限必要になります。

こうした理由で、低レイテンシ・低ジッタと高スループットを両立できるEtherCATが望まれるのです。

EtherCATが使われるケース

現状、EtherCATが用いられるロボットというのは、大きさでいえば大型犬サイズ以上、ご予算でいえば少なくとも100万円超えの規模になると思います。例えば3万円のモータと3万円のモータドライバを16軸使ったロボットを作ろうとするとそれだけで(3+3)万円×16軸=96万円になりますよね。

投げ売り2万円のプリメイドAIに群がってサーボモータをむしり取るような私たちとは次元の違う世界です。産業用ロボットを除けば、ほぼ研究開発用ロボットにかぎられるんじゃないかと思います。数万円~数十万円台のホビーロボットにEtherCATを用いることは今のところ非現実的です。

…が、10年後においては定かではない。(願望)

参考文献

  • 神永拓, 中村仁彦「油圧駆動ヒューマノイドロボットHydraのエレクトロニクス」
    第33回日本ロボット学会学術講演会, 2015

GR-SAKURAでEtherCAT

この記事は EtherCATについて語る Advent Calendar 2019 の16日目です。

昨日は@nonNoiseさんの EtherCATでステッピングモータ を動かしてみる でした。

さて、12月14日に開催されたルネサスナイト15にて「GR-SAKURAでEtherCAT」と題してLTしてきました。今日はその内容をご紹介いたします。(アドベントカレンダーをご覧の皆さんには今さらな内容を含みます。)

スライド資料

EtherCATとは?

さて、みなさんはEtherCATというものをご存知でしょうか?

f:id:licheng:20191215193026p:plain

EtherCATというのはEthernetベースのフィールドバスの規格です。要は、工場のFA機器をLANケーブルで接続して制御しようというものでして、通常のLANに比べてリアルタイム性が非常に高いという特長があります。

通常のLANとどう違うかと言いますと、まず、そもそもIPアドレスを使いません。ネットワークはマスターとスレーブで構成されまして、それらをデイジーチェーン接続します。そして全てのノードが一つのEthernetフレームを共有して同時に読み書きします。これによって高いリアルタイム性を実現しています。

だいじなポイントとして、マスターのほうは汎用のEthernetコントローラで実現できるんですが、スレーブのほうにはEtherCAT専用のハードウェアが必要となります。

GR-SAKURAとは?

f:id:licheng:20191215194513j:plain

GR-SAKURAとは、ルネサスRX63Nマイコンを搭載したArduino互換マイコンボードです。Arduino Unoサイズのボードに強力なRXマイコンEthernetコネクタ、USBホストコネクタ、micro SDカードスロットを搭載した「全部入り」なボードです。

GR-SAKURAでEtherCAT

f:id:licheng:20191212210146p:plain

で、今回は、GR-SAKURAでEtherCATのシステムを作ってみました。

マスター1台にスレーブ2台が接続されてます。片方のスレーブには4軸のロボットアームが接続されてまして、もう片方のスレーブにはロボットアームを操作するためのコントローラが接続されてます。

マスターはGR-SAKURAだけでできてます。ソフトウェアはSOEMというのを使ってます。SOEMというのはオープンソースのEtherCATマスターのスタックです。Windows/Mac/Linuxなどに対応しています。このSOEMを、Arduinoに移植しちゃいました。今のところ、Arduino DueとGR-SAKURAに対応してます。

ただし、GR-SAKURAでは不具合がありレスポンスが悪いです。まあ、これはEthernetのライブラリをよくわからずむりやりハックして使ってるためでしょう。 (この件はルネサスさんから詳細を聞きたいと言われたので状況をまとめて質問メールを送ることにします。)

いっぽう、スレーブのほうは、GR-SAKURAにEasyCAT Shieldというのをのせてます。このEasyCAT Shiledというのは、EtherCATスレーブの専用チップを搭載したArduono用シールド基板です。

デモ

コントローラのツマミを回すと、ロボットアームが動きます。まあ、こんなもんArduino Uno 1個でできるやろ、GR-SAKURA 3個も使うなやって話ですが、あくまでEtherCATの実験のためのシステムと考えてください (^^;)


GR-SAKURAでEtherCAT

ちなみに

ルネサスRX72MマイコンにはEtherCATスレーブのハードウェアが搭載されてるそうです。すでに開発ボードが市販されてますね。気になります。
www.chip1stop.com


発表は以上です。最後までお読みいただきありがとうございました。

EtherCATマスターSOEMを.NETで使う

この記事は EtherCATについて語る Advent Calendar 2019 の11日目です。

昨日は@nonNoiseさんの EtherCAT開発方法 フレーム編(ライトまで) でした。

今日はオープンソースのEtherCATマスターであるSOEMをWindows上の.NETアプリで使う方法を解説します。

SOEMとは?

SOEMはオープンソースのEtherCATマスターである。WindowsMacOSLinuxなどに対応している。ビルドシステムとしてCMakeを用いる。

github.com

方針

  1. SOEMをDLL化するためAPIC言語で定義する
  2. CMakeを使ってDLLをビルドする
  3. DLLをラップするクラスをC#で作成する
  4. C#アプリで使う

f:id:licheng:20191210124119p:plain:w640

(1) SOEMをDLL化するためAPIC言語で定義する

まず、SOEMをDLL化して外部から呼ぶ出せるようにするため、APIC言語で定義する。soemlib.c という名前でソースファイルを作成し、必要なAPI関数を定義する。DLLのAPI関数の定義には、__declspec(dllexport) と __stdcall というキーワードを付ける。一例を以下に示す。(2019/12/19 修正)

#include "ethercat.h"

int __stdcall soem_open(char* nif)
{
    int ret = ec_init(nif);
    return ret;
}

また、API関数をsoemlib.defというファイルに列挙する。 (2019/12/19 追記)

(2) CMakeを使ってSOEMのDLLをビルドする

Windows環境でのCMakeによるSOEMのビルド方法についてはまず以前の記事を参照。

SOEM/CMakeLists.txt の最後のほうに1行追加する。DLLのソースを置くサブディレクトリの追加である。親ディレクトリ名がlinuxになっているが気にしない。

if(BUILD_TESTS) 
  add_subdirectory(test/linux/slaveinfo)
  add_subdirectory(test/linux/eepromtool)
  add_subdirectory(test/linux/simple_test)
  add_subdirectory(test/linux/soemlib)     # ←この行を追加
endif()

SOEM/test/linux/soemlib/CMakeLists.txt を下記の内容で作成する。これがDLLをビルドするレシピである。add_library()で SHARED を指定することで共有ライブラリがビルドされる。Windowsでは共有ライブラリとはすなわちDLLである。

set(SOURCES soemlib.c soemlib.def)
add_library(soemlib SHARED ${SOURCES})
target_link_libraries(soemlib soem)
install(TARGETS soemlib DESTINATION lib)

(1)で作成したsoemlib.cを SOEM/test/linux/soemlib/ に置く。そしてCMakeによるビルドを実行する。ビルドが成功すると、SOEM/build/test/linux/soemlib/soemlib.dll が生成される。

(3) DLLをラップするクラスをC#で作成する

作成したDLLを.NETアプリから使うため、C#でラッパーを作成する。EtherCAT.cs という名前でソースファイルを作成しクラスを定義する。DLLが提供するAPI関数をC#で使うには、DllImport属性を使い、DLLファイル名とAPI関数名を指定する。一例を下記に示す。

using System.Runtime.InteropServices; // DllImport

(中略)
    // EtherCATラッパークラス
    class EtherCAT
    {
(中略)
        // 開く
        [DllImport("soemlib.dll", EntryPoint = "soem_open")]
        extern public static int open(string nif);

(4) C#アプリで使う

あとは作成したクラスを使った.NETアプリをC#で作成する。例として2個のEtherCATスレーブを接続してラジコンサーボの角度の指令とポテンショメータの角度の取得をおこなうアプリを作成した。


WindowsとArduinoでEtherCAT

ソース

この記事で作成したソースを下記に公開する。

github.com