日記；回すだけIII ⑰ ラズパイ、C++でプログラミング＜その3 SDOを読み出す（EPOS4）＞ベータ版

　サンプル・プログラムは時代が新しく、C++で書かれています。エラー処理も適切に行われているので、すこし見通しが悪いです。

　　[日記；回すだけIII ⑬ C++でプログラミング＜その2 データ読み出しプログラム（EPOS4）＞ベータ版](https://qiita.com/jamjam/items/c3bc062866f6acce4d17)

の事例と同様に、単純に読み出しを行います。上記はWindowsですが、ここではラズパイ4で動かします。

### 接続
　CANインターフェースは、[「日記；回すだけIII ⑮ ラズパイ、C++でプログラミング＜その1 準備（EPOS4）＞ベータ版」](https://qiita.com/jamjam/items/d4aa4d630025b6830f7f)の回路図通りにブレッドボード上に組み立てたハードを使っています。CANトランシーバはMCP2551ではなくMCP2561を使っています。
　図の赤い線の経路でアクセスします。

![EPOS4-raspi2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/ece7d371-ed80-4604-1a2c-81af7f025687.png)

### プログラム

``sudo /sbin/ip link set can0 up type can bitrate 500000``
は不要のようです。
　プログラム名はeps_e.cppにしました。Makefileのなかで、``TARGET = epos_e``に変更します。



```cpp
#include <stdlib.h>
#include <iostream>
#include "Definitions.h"

int main(){
    printf("start EPOS4\n");
    void* keyHandle = 0;
    char* deviceName = (char*)"EPOS4";
    char* protocolStackName = (char*)"CANopen";
    char* interfaceName = (char*)"CAN_mcp251x 0";
    char* portName = (char*)"CAN0";
    uint32_t errorCode = 0;
    uint32_t timeout = 0;
    uint16_t nodeId = 5;
    uint16_t MotorType = 0;
    uint32_t NominalCurrent = 0;
    uint32_t MaxOutputCurrent = 0;
    uint16_t ThermalTimeConstant = 0;
    uint8_t  NbOfPolePairs = 0;
    uint16_t SensorType = 0;
    uint32_t EncoderResolution = 0;
    int32_t  InvertedPolarity = 0;
    uint16_t EController = 1; // PI current controller
    uint16_t EGain = 1;  // 1:Current controller P gain, 2:Current controller I gain
    uint64_t Value = 0;

    printf(" interfaceName is %s , protocol is %s\n", interfaceName,protocolStackName);

    keyHandle = VCS_OpenDevice(deviceName, protocolStackName, interfaceName, portName, &errorCode);
    printf(" keyHandle  is 0x%x , errorCode  is 0x%x\n", keyHandle,errorCode);

    VCS_SendNMTService(keyHandle, nodeId, 130, &errorCode); // RESET_COMMUNICATION
    VCS_ClearFault(keyHandle, nodeId, &errorCode); // ClearFault

    printf("\n - - - - - \n");

    if (keyHandle!=0 && errorCode == 0) {

        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_SetState(keyHandle, nodeId, 0x0002, &errorCode);  // Quick stop state
    VCS_SendNMTService(keyHandle, nodeId, 130, &errorCode); // RESET_COMMUNICATION

    VCS_CloseDevice(keyHandle, &errorCode);
    printf("\nClose device\n");
}
```

### 別のハードウェア
　アマゾンで、CANインターフェースを購入しました。40ピンのピンヘッダに乗せるだけで接続は完了です。
　CANバスとはHとL端子につなぎます、GNDは用意されていません。

　　[3.3V RS485通信 CAN BUS バス モジュール HAT 拡張ボード スターターキット for RPI ラズベリーパイ ゼロ ラズパイ Raspberry Pi Zero 2 W WH 3 Model B+ Plus 4 4B 電子工作 半二重通信](https://www.amazon.co.jp/gp/product/B08LCKLHBX/)

![IMGP1091.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/10797efc-18e7-1adf-cb6d-b2fbba0dfad2.png)


　/boot/config.txtの内容を、水晶発振子の値に合わせて16MHzから12MHzに変更します。

```shell
dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=12000000,interrupt=25
```

　リブートします。

```shell
$ dmesg | grep -i  "spi"
[    9.405542] mcp251x spi0.0 can0: MCP2515 successfully initialized.
```
　組み込みが正常だったことを確認します。
　自作のボードに比べて、CANバス・エラーを発生しやすいように感じます。また、バス・エラーをNMTのコマンドで解消できません。CANインターフェースICは同じですが、CANトランシーバはSN65HVD230が使われています。

　実行例です。
![2022-05-14 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/aca6f127-c2c9-4496-b831-9706ab3d40ee.png)