日記；回すだけIII ⑬ C++でプログラミング＜その2 データ読み出しプログラム（EPOS4）＞ベータ版


　次の環境でプログラムを作っています。WindowsPCでプログラムは動き、CANバスとはIXXATのUSB-CAN変換モジュールを通してCANopenのプログラムを動かします。EPOSのライブラリは、IXXAT以外に、ベクターやKvaserなどのインターフェースのドライバが利用できるようです。IXXATは、検索して日本語で価格がわかったのでマルツから購入しました。

![EPOS4-C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/499ba1ae-0d60-4917-0b0a-359f07ae8bb7.png)


　これ以外に、EPOSはRS232C/USBとCANバスのブリッジになるので、上記のインターフェースはなくてもDeviceOpenが実行できます。マニュアル類では、そちらの方法の事例しか掲載されていません。

### ハローワールドから始める
　コンパイルしてプログラムを実行したのは初めてなので、その手順を記します。VisualStudioの上部メニューから新規プロジェクトを選びます。
　コンソールアプリのC++を選択し、次へをクリックします。
![2022-03-31 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/a31a5431-d39a-a803-c9ca-861bc1d3d85d.png)
　eposと名付けました。
![2022-03-31 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/0f4a88a3-681a-f1d1-fbc2-832b9c09bd62.png)
　最初の画面にハローワールドが出ています。
![2022-03-31 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/6d56d68d-09db-a0d3-ac20-ce6376698181.png)
　慣れたprintf()で書き換え、CTRL＋Shift＋Bでビルドします。画面下の出力に、ビルドでエラーなしが出ているので、メニューのローカルWindowsデバッガーの右の三角アイコンをクリックして実行します。黒地のコマンド・プロンプトが開き、printfの出力が出ました。


![epos103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/ca9211f2-a3b4-e0fd-ed83-fec048a45059.png)





### 二つある状態変数だが
　NMT（Network Management Object）は、電源投入時にInitialization、その後PRE-OPERATIONAL状態、最後に運転状態のOPERATIONAL状態に移行します。
　けれど、状態を読み出す関数見つかりません。サンプルを見ても、自分でPRE-OPERATIONALに移行するとかの記述は見つかりません。OPERATIONALからPre-Opeに変更するのは、PDOマッピング時に必要だけど、それはStudioで設定すればいいので、使うことはありません。つまり、エンド・ユーザはNMTには感知せずでいいようです。
　CiA-402 State Machineの状態変更や状態を調べる関数は多く用意されていますが、どうも状態はDisableとEnableしかみつかりません。もっと細かい遷移はエンド・ユーザはやらなくてもよいようです。
　また、SYNCにかかわる関数は用意されていないようです。

### SDOでいろいろ読み出す
##### 必要なファイルの追加
　VisualStudio左のソリューションエクスプローラのeposの上で、右クリックします。
　追加から既存の項目を選択します。
![2022-03-31 (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/3682a749-99bc-cc1a-e6a5-a8f641c3501c.png)
　前回ダウンロードしたサンプル・フォルダから、ヘッダ・ファイルはDefinitions.hを選択します。
　同様に、ライブラリはEposCom64.dllとEposCom64.libファイルを追加します。
![2022-03-31 (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/b85a1faf-b028-1b4c-133b-82d38b64f35b.png)
　ソリューションエクスプローラの様子です。一度全部を保存して終了します。このあたりの操作がわかっていません。エクスプローラを使って物理的にファイルをeposフォルダにコピーをする必要があるかもしれません。もしくは、次に立ち上げたときに自動でコピペされるかもしれないです。
![2022-03-31 (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/fd587b39-21a5-efac-3c57-8b1dc7d69579.png)

##### EPOS Command Library Documentationを参考に
　いくつかのオブジェクト・ディクショナリのデータを読み出します。エラー・コードは無視しています。

```C
#include <iostream>
#include "Definitions.h"

int main()
{
    printf("start EPOS4\n");
    HANDLE keyHandle = 0;
    char* deviceName = (char*)"EPOS4";
    char* protocolStackName = (char*)"CANopen";
    char* interfaceName = (char*)"IXXAT_USB-to-CAN V2 compact 0";
    char* portName = (char*)"CAN0";

    DWORD errorCode = 0;
    DWORD timeout = 0;
    WORD nodeId = 5;
    WORD MotorType = 0;
    DWORD NominalCurrent = 0;
    DWORD MaxOutputCurrent = 0;
    WORD ThermalTimeConstant = 0;
    BYTE NbOfPolePairs = 0;
    WORD SensorType = 0;
    DWORD EncoderResolution = 0;
    BOOL  InvertedPolarity = 0;
    WORD EController = 1; // PI current controller
    WORD EGain = 1;  // 1:Current controller P gain, 2:Current controller I gain
    DWORD64 Value = 0;

    keyHandle = VCS_OpenDevice(deviceName, protocolStackName, interfaceName, portName, &errorCode);

    if ((BOOL)keyHandle) {

        VCS_Store(keyHandle, nodeId, &errorCode);
        printf("nodeId  is %d\n", nodeId);

        VCS_GetMotorType(keyHandle, nodeId, &MotorType, &errorCode);
        printf("MotorType:(10 is EC motor sinus commutated): %d\n", MotorType);

        VCS_GetDcMotorParameterEx(keyHandle, nodeId, &NominalCurrent, &MaxOutputCurrent, &ThermalTimeConstant, &errorCode);
        printf("NominalCurrent: %d  MaxOutputCurrent: %d ThermalTimeConstant: %d\n", NominalCurrent, MaxOutputCurrent, ThermalTimeConstant);

        VCS_GetEcMotorParameterEx(keyHandle, nodeId, &NominalCurrent, &MaxOutputCurrent, &ThermalTimeConstant, &NbOfPolePairs, &errorCode);
        printf("EcMotor NbOfPolePairs: %d\n", NbOfPolePairs);

        VCS_GetSensorType(keyHandle, nodeId, &SensorType, &errorCode);
        printf("SensorType:(1 is Incremental encoder 1 with index (3-channel)): %d\n", SensorType);

        VCS_GetIncEncoderParameter(keyHandle, nodeId, &EncoderResolution, &InvertedPolarity, &errorCode);
        printf("EncoderResolution: %d InvertedPolarity: %d\n", EncoderResolution, InvertedPolarity);

        VCS_GetControllerGain(keyHandle, nodeId, EController, 1, &Value, &errorCode);
        printf("CurrentController PGain: %.3fmV/A\n", Value / 1000.0);
        VCS_GetControllerGain(keyHandle, nodeId, EController, 2, &Value, &errorCode);
        printf("CurrentController IGain: %.3fmV/(A*ms)\n", Value / 1000.0);
    }
    VCS_CloseDevice(keyHandle, &errorCode);
}
```
　CTRL＋Shift+Bでビルドし、実行します。
![2022-03-31 (17).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/d4fd8675-6c8e-dc8f-1167-0a6f4950360b.png)