パイピコ用エンコーダカウンタ

# エンコーダとは
ロータリーエンコーダでは回転軸の角度、リニアスケールでは移動距離の計測に使用します。
AB位相信号を処理することで移動量を計測します。

# エンコーダ処理の問題点とパイピコを使う理由
移動速度が低速だったり解像度が低ければ割り込みなどを使用して処理できますが、移動速度の高速化や高解像度化をする場合、パルスの変化が早いのでarduinoなどのマイコンでは間に合わない場合があります。

ラズベリーパイピコのPIOにはステートマシンがありますので、ステートマシンにAB位相信号処理用のプログラムを導入することによりカウンタを作ることが出来ます。
ステートマシン用のプログラム(quadrature.pio.h)はGitHubに公開されているものを利用させていただきました。

Jamon Terrell <github@jamonterrell.com>
Arda Alıcı     <ardayaozel@hotmail.com>

https://github.com/jamon/pi-pico-pio-quadrature-encoder



# 6軸用エンコーダーカウンタのプログラム
``` C
// このソフトウェアおよび関連する文書ファイル（以下「ソフトウェア」と称します）のコピーを入手した人に対して、
// ソフトウェアを無制限に使用、複製、修正、マージ、公開、配布、サブライセンス、販売を行うことを無料で許可します。
// また、このソフトウェアを提供された人に対しても、以下の条件に従ってこれを行うことを許可します：
//
// 上記の著作権表示およびこの許可表示は、ソフトウェアの全てのコピーや主要な部分に含まれるものとします。
//
// このソフトウェアは「現状のまま」で提供されており、いかなる保証もありません。明示的または暗黙的を問わず、
// 商品性や特定目的への適合性の保証を含む、いかなる種類の保証もありません。いかなる場合においても、
// 著者または著作権保持者は、契約行為、過失またはその他の方法で発生した損害、責任を負いません。
// ソフトウェアの使用や他の取引から生じる責任についても同様です。



#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"


#include "quadrature.pio.h"
// quadrature.pio.h は MIT ライセンスの下で含まれています
// Copyright (c)
//        2022 Jamon Terrell <github@jamonterrell.com>
//        2023 Arda Alıcı     <ardayaozel@hotmail.com>


// エンコーダーピン番号の定義
#define ENCODER_X_A_PIN 0
#define ENCODER_X_B_PIN 1
#define ENCODER_Y_A_PIN 2
#define ENCODER_Y_B_PIN 3
#define ENCODER_Z_A_PIN 4
#define ENCODER_Z_B_PIN 5
#define ENCODER_A_A_PIN 6
#define ENCODER_A_B_PIN 7
#define ENCODER_B_A_PIN 8
#define ENCODER_B_B_PIN 9
#define ENCODER_C_A_PIN 10
#define ENCODER_C_B_PIN 11

// PIOとステートマシン設定
PIO pioXYZ = pio0;
uint offsetXYZ;
uint smXYZ[] = {0, 1, 2};  // ステートマシン番号の配列

PIO pioABC = pio1;
uint offsetABC;
uint smABC[] = {0, 1, 2};  // ステートマシン番号の配列

// エンコーダーのカウントおよびオフセット
int encoderXYZ[3] = {0, 0, 0};
int encoderABC[3] = {0, 0, 0};
int encoderXYZ_offset[3] = {0, 0, 0};
int encoderABC_offset[3] = {0, 0, 0};

// エンコーダーピンの初期化
void encoder_pin_init(void) {
    // XYZのエンコーダー用PIOプログラムを追加
    offsetXYZ = pio_add_program(pioXYZ, &quadrature_program);
    if (offsetXYZ == -1) {
        printf("Error adding quadrature program to PIO0\n");
        return;
    }

    // 各軸のエンコーダーを初期化
    for (int i = 0; i < 3; i++) {
        uint encoder_a_pin, encoder_b_pin;
        switch(i) {
            case 0: encoder_a_pin = ENCODER_X_A_PIN; encoder_b_pin = ENCODER_X_B_PIN; break;
            case 1: encoder_a_pin = ENCODER_Y_A_PIN; encoder_b_pin = ENCODER_Y_B_PIN; break;
            case 2: encoder_a_pin = ENCODER_Z_A_PIN; encoder_b_pin = ENCODER_Z_B_PIN; break;
        }
        quadrature_program_init(pioXYZ, smXYZ[i], offsetXYZ, encoder_a_pin, encoder_b_pin);
    }

    // ABCのエンコーダー用PIOプログラムを追加
    offsetABC = pio_add_program(pioABC, &quadrature_program);
    if (offsetABC == -1) {
        printf("Error adding quadrature program to PIO1\n");
        return;
    }

    // 各軸のエンコーダーを初期化
    for (int i = 0; i < 3; i++) {
        uint encoder_a_pin, encoder_b_pin;
        switch(i) {
            case 0: encoder_a_pin = ENCODER_A_A_PIN; encoder_b_pin = ENCODER_A_B_PIN; break;
            case 1: encoder_a_pin = ENCODER_B_A_PIN; encoder_b_pin = ENCODER_B_B_PIN; break;
            case 2: encoder_a_pin = ENCODER_C_A_PIN; encoder_b_pin = ENCODER_C_B_PIN; break;
        }
        quadrature_program_init(pioABC, smABC[i], offsetABC, encoder_a_pin, encoder_b_pin);
    }
}

// エンコーダーの値を更新
void reload_encoder(void) {
    for (int i = 0; i < 3; i++) {
        pio_sm_exec_wait_blocking(pioXYZ, smXYZ[i], pio_encode_in(pio_x, 32));
        encoderXYZ[i] = pio_sm_get_blocking(pioXYZ, smXYZ[i]) - encoderXYZ_offset[i];
    }

    for (int i = 0; i < 3; i++) {
        pio_sm_exec_wait_blocking(pioABC, smABC[i], pio_encode_in(pio_x, 32));
        encoderABC[i] = pio_sm_get_blocking(pioABC, smABC[i]) - encoderABC_offset[i];
    }
}

```

# プログラム中の注意点

パイピコにはpioが2個ですのでpio0ではXYZ軸用エンコーダーでステートマシンを3個使い、pio1ではABC軸用エンコーダーでステートマシンを3個使います。最大では8個になります。

quadrature.pio.hにはエンコーダーの０リセット機能は無いようなので、リセット時はencoderXYZ_offset[]、XYZencoderXYZ_offsetXYZ[]にエンコーダーの現在値を記憶し、読み出し時はそれらの値をエンコーダーから差し引きすることでゼロセットしたことにしています。

メインプログラム内では下記のように利用します。

``` c
int enc_x;
//メインプログラムからエンコーダー初期化
encoder_pin_init();

while(1){
    //ループ内でエンコーダー情報更新
    reload_encoder();
    enc_x=encoderXYZ[0];
}
```



# パイピコを使った他のエンコーダープログラムについて
quadrature.pio.h以外にもPIOを使ったエンコーダー処理のプログラムがあるようでこちらで紹介されています。回路については差動出力を変換するICを使っています。

https://www.youtube.com/watch?v=lGm3rTDp7nE&t=577s