PPMの仕様について

ドローンのフラコンと受信機間でよく使用されるPPM信号について調査したので、備忘録として残しておきます。(2019年6月調査)

目次

 


PPM信号とは?

PPMとは「Pulse Position Modulation」の略で、日本語では「パルス位置変調」と呼ばれる。
以下の図のように、パルスの位置によって信号を伝える方式。

 

PPM信号はラジコンの受信機との通信によく使用される規格。似たような信号にPWM信号(パルス幅変調/Pulse Width Modulation)があるが、PWM信号は信号の幅と間隔で情報を伝える。

 

 

RC向けPPM信号の仕様

PPM信号のパルス幅や信号開始を判断する信号幅などは仕様としては共通的に定められているわけではないみたい。そのため、業界ごとで仕様が定められているようだ。

RC向けのPPM信号はなかなか資料として見つからなかった。唯一見つけたのは以下のサイト。

 

A complete PPM-Frame has a length of 22.5 ms. It exists of an overlong start information and 8 channel information. A stop information with 0.3 ms follows on every channel impulse. The length of a channel impulse ranges from 0.7 ms to 1.7 ms and corresponds to the stick position. Consequently, the illustration shows a transmitter with full amplitude right in channel 1, channel 2 on full amplitude left, channel 3 on middle,.. the start impulse supplements the 8 channel impulses, so that the total length of 22.5 ms emerges.

引用元: http://www.mftech.de/ppm_en.htm

 

  • PPMフレーム全長:22.5ms
  • パルス幅:0.3ms
  • PPM信号幅:0.7ms~1.7ms + 0.3ms(パルス幅)
  • PPM信号数:8チャネル
  • スタート判定信号幅(最小):6.5ms(PPMフレーム長からPPM信号分の差)

 

 

実動作の確認

あまり正確な仕様の情報がなかったので、以下の2パターンの実動作を確認しました。

  • BetaFlightのソースコード確認
    • ドローンFPV業界で有名なフラコン用OSSのBetaFlightでどのようにPPMが読まれているか確認しました。
  • 受信機のPPM信号確認
    • FrSky(FrSky 8CH PWM PPM SBUS Micro Receiver ) の受信機のPPM信号をArduinoで読み取り、信号を可視化して確認しました。

 

BetaFlightのソースコード確認

 

PPM受信処理の調査

今回確認したいのは受信機と通信するためのPPM信号のため、\betaflight-master\src\main\rx配下にあるプログラムを見ていく。 いくつもプログラムがあるが、この中でPPM信号の処理があるのはpwm.cのようだ。
"pwm"はPPMと同じくパルス信号を使った変調方式であり、どうしてpwm内にppmの処理があるかは調べていないが、おそらく後からPPMの処理が追加されたのだろう。

  • \betaflight-master\src\main\rx\pwm.c
static uint16_t ppmReadRawRC(const rxRuntimeConfig_t *rxRuntimeConfig, uint8_t channel)
{
    UNUSED(rxRuntimeConfig);
    return ppmRead(channel);
}

 

実態はppmRead()のようであり、検索すると\betaflight-master\src\main\drivers\rx\rx_pwm.cファイルにあった。
このプログラムの中で、 ppmEdgeCallback( )がPPM信号の割り込み処理でコールバックされる関数のようだ。
この関数のなかで、信号の妥当性を見ているのは、以下の処理 。

  • \betaflight-master\src\main\drivers\rx\rx_pwm.c
    /* Sync pulse detection */
    if (ppmDev.deltaTime > PPM_IN_MIN_SYNC_PULSE_US) {
        if (ppmDev.pulseIndex == ppmDev.numChannelsPrevFrame
            && ppmDev.pulseIndex >= PPM_IN_MIN_NUM_CHANNELS
            && ppmDev.pulseIndex <= PPM_IN_MAX_NUM_CHANNELS) {
            /* If we see n simultaneous frames of the same
               number of channels we save it as our frame size */
            if (ppmDev.stableFramesSeenCount < PPM_STABLE_FRAMES_REQUIRED_COUNT) {
                ppmDev.stableFramesSeenCount++;
            } else {
                ppmDev.numChannels = ppmDev.pulseIndex;
            }
        } else {
            ppmDev.stableFramesSeenCount = 0;
        }

        /* Check if the last frame was well formed */
        if (ppmDev.pulseIndex == ppmDev.numChannels && ppmDev.tracking) {
            /* The last frame was well formed */
            for (i = 0; i < ppmDev.numChannels; i++) {
                captures[i] = ppmDev.captures[i];
            }
            for (i = ppmDev.numChannels; i < PPM_IN_MAX_NUM_CHANNELS; i++) {
                captures[i] = PPM_RCVR_TIMEOUT;
            }
            ppmFrameCount++;
        }

        ppmDev.tracking   = true;
        ppmDev.numChannelsPrevFrame = ppmDev.pulseIndex;
        ppmDev.pulseIndex = 0;

        /* We rely on the supervisor to set captureValue to invalid
           if no valid frame is found otherwise we ride over it */
    } else if (ppmDev.tracking) {
        /* Valid pulse duration 0.75 to 2.5 ms*/
        if (ppmDev.deltaTime > PPM_IN_MIN_CHANNEL_PULSE_US
            && ppmDev.deltaTime < PPM_IN_MAX_CHANNEL_PULSE_US
            && ppmDev.pulseIndex < PPM_IN_MAX_NUM_CHANNELS) {
            ppmDev.captures[ppmDev.pulseIndex] = ppmDev.deltaTime;
            ppmDev.pulseIndex++;
        } else {
            /* Not a valid pulse duration */
            ppmDev.tracking = false;
            for (i = 0; i < PWM_PORTS_OR_PPM_CAPTURE_COUNT; i++) {
                ppmDev.captures[i] = PPM_RCVR_TIMEOUT;
            }
        }
    }

ここら辺の定数は以下とのこと。

  • PPM_IN_MIN_SYNC_PULSE_US 2700μs
  • PPM_IN_MIN_CHANNEL_PULSE_US 750μs
  • PPM_IN_MAX_CHANNEL_PULSE_US 2250μs
  • PPM_IN_MIN_NUM_CHANNELS 4
  • PPM_IN_MAX_NUM_CHANNELS 12

 

PPM受信処理の調査結果

調査内容をまとめると以下のような仕様でPPM信号を受信していることが分かった。

 

 

受信機のPPM信号確認

測定方法の詳細は割愛しますが、上記の「測定に使ったソースコード」をESP8266に書き込み、250ms間という短い間のPPM値を50μs間隔で測定してシリアルプロッタに表示しました。それをデータ集計して、PPM信号をグラフ化しました。

 

 

 

まとめ

今回調査した、「RC向け仕様」、「BetaFlightのPPM受信処理」、「FrySky受信機の実測」の結果について以下にまとめました。

RC向け仕様BetaFlight処理FrySky実測
PPMフレーム全長[ms]22.5?19.25
パルス幅[ms]0.3?0.3
PPM信号幅[ms]1~20.75~2.25?
スタート判定信号幅(最小)[ms]6.52.78
PPM信号数[チャネル]84~128

 

 

関連情報

その他の部品について気を付けることや部品の検討については以下。

ドローン部品の購入に向けて、いろいろと検討したので備忘録としてまとめした。

 

 

参考

 

 

 

以上。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする