2022年11月6日日曜日

プロポからのPWM信号変換の方法を変更

 これまでの記事にあるように、プロポからのPWM信号を変換するのに、ローパスフィルターを使っていたが、値が不正確で、モーターの回転のばらつきが発生して、飛行失敗につながっていることがわかった。

そこで、この方法は諦めて、ラズパイのGPIOの立ち上がり、たち下がりを検知するCALLBACK関数を用いて変換することにした。そのために、pigpioというライブラリを使用する。詳細はまた、この記事に書こうと思う。

(1)インストール

https://abyz.me.uk/rpi/pigpio/download.html

最新バージョンのダウンロードとインストールはここに書いてあるとおりにすればいい。

(2)C++で実行するときは、作成したプログラムをsudoを使ってroot権限で実行する必要がある。その代わり、pigpiodを事前に起動する必要はない。

(3)受信機の接続

受信機からの信号を空いている GPIOピンに接続。



(4)プログラム

8ちゃんねるの信号を読みとっとμ秒単位のPWMの幅で出力するプログラムの概要は以下のような感じである。CALLBACK関数は、グローバルな場所に置いておかなければならない。それに伴い、変数もStaticである。

コンパイル時のライブラリに pipgioとpthreadを追加しなければならない。

#include <stdio.h>
#include <pigpio.h>

static int pwm_count[8];
static uint32_t rise_tick[8];
static int pwm_width[8];
unsigned int from_gpio[30];

void interruptDisplay( int gpio, int level, uint32_t tick)
{
    int array_No = from_gpio[gpio];
    if(level==1){
        rise_tick[array_No] = tick;
    }else if(level==0){
        int diff = tick - rise_tick[array_No];
        if(diff > 500 && diff < 2500){
            pwm_width[array_No] = tick - rise_tick[array_No];
            //printf("Interrupt pin %d #%d level %d at %u DIFF = %d\n", gpio, c, level, tick, pwm_width);
            printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", gpio,pwm_count[array_No]
                    , pwm_width[0]
                    , pwm_width[1]
                    , pwm_width[2]
                    , pwm_width[3]
                    , pwm_width[4]
                    , pwm_width[5]
                    , pwm_width[6]
                    , pwm_width[7]
                   );
            pwm_count[gpio]++;
        }
    }else{
        printf("ERROR level is non 0 and non 1\n");
    }

}

int main(void)
{
   int ret;
   // 配列番号をGPIO番号に
   unsigned int to_gpio[8];
   to_gpio[0] = 4;
   to_gpio[1] = 17;
   to_gpio[2] = 27;
   to_gpio[3] = 22;
   to_gpio[4] = 5;
   to_gpio[5] = 6;
   to_gpio[6] = 13;
   to_gpio[7] = 26;
   // GPIO番号を配列番号に
   from_gpio[4] = 0;
   from_gpio[17] = 1;
   from_gpio[27] = 2;
   from_gpio[22] = 3;
   from_gpio[5] = 4;
   from_gpio[6] = 5;
   from_gpio[13] = 6;
   from_gpio[26] = 7;

   if (gpioInitialise()<0) return 1;

   for(int i=0;i<8;i++){
       pwm_count[i] = 0;
       rise_tick[i] = 0;
       pwm_width[i] = 0;
       /* Set GPIO modes */
       gpioSetMode(to_gpio[i], PI_INPUT);
       gpioSetPullUpDown(to_gpio[i], PI_PUD_UP);
       printf("GPIO %d is level %d\n",to_gpio[i], gpioRead(to_gpio[i]));
       ret = gpioSetISRFunc(to_gpio[i], EITHER_EDGE, 5000, interruptDisplay);
       // Callback 設定
       if(ret < 0) printf("error GPIO Int %d\n",to_gpio[i]);
   }

   while (1)
   {
    time_sleep(60);
   }

   gpioTerminate();
}

(5)プロポに反応した結果

実行はルート権限で行う必要がある。



異常値を取り除けば十分よく反応している。




0 件のコメント:

コメントを投稿

DJI MAVIC MINIのFPVライブ動画をiOSのVisionframeworkで顔認識させるという話

 iOSでは、他の方法もあるが、Visionframeworkは、いろんなことができるので、これでなんとか顔認識させようとここ2,3日没頭していた。ようやく、 こんな感じで、緑の枠で認識画像をリアルタイムで表示できるようになった。 (プログラムの全体は、最下段に掲げてある) 途中...