web-dev-qa-db-ja.com

Pythonでのリアルタイムでのシリアルデータの読み取り

Pythonのスクリプトを使用して、2Mbpsのシリアルポート経由でPICマイクロコントローラーからデータを収集しています。

PICは2Mbpsで完璧なタイミングで動作し、FTDI usbシリアルポートも2Mbpsで良好に動作します(両方ともオシロスコープで検証済み)

メッセージを送信している(サイズが約15文字)1秒あたり約100〜150倍で、そこにある数が増加する(メッセージが失われているかどうかを確認するなど)

私のラップトップでは、Xubuntuを仮想マシンとして実行しています。シリアルポートは、PuTTYおよびスクリプト(python 2.7およびpySerial)で読み取ることができます。

問題:

  • PuTTY経由でシリアルポートを開くと、すべてのメッセージが表示されます(メッセージのカウンターは1ずつ増加します)。パーフェクト!
  • PySerialでシリアルポートを開くと、すべてのメッセージが表示されますが、1秒あたり100〜150xを受信する代わりに、1秒あたり約5でメッセージを受信します(メッセージは1ずつ増加します)。機長、キッチンに行って戻ってきても、まだメッセージを受信できます。

コードは次のとおりです(コードの大部分は省略しましたが、ループは同じです)。

ser = serial.Serial('/dev/ttyUSB0', 2000000, timeout=2, xonxoff=False, rtscts=False, dsrdtr=False) #Tried with and without the last 3 parameters, and also at 1Mbps, same happens.
ser.flushInput()
ser.flushOutput()
While True:
  data_raw = ser.readline()
  print(data_raw)

PySerialがシリアルポートから行末まで読み取るのに時間がかかる理由を誰もが知っていますか?何か助け?

リアルタイムでこれを持ちたいです。

ありがとうございました

32
Vasco Baptista

inWaiting()を使用して、入力キューで使用可能なバイト数を取得できます。

次に、read()を使用して、次のようなバイトを読み取ります。

While True:
    bytesToRead = ser.inWaiting()
    ser.read(bytesToRead)

readline()この場合 Docsを使用しない理由:

Read a line which is terminated with end-of-line (eol) character (\n by default) or until timeout.

Eolを待機するため、読み取りごとにタイムアウトを待機しています。シリアル入力Qは、バッファーの「終わり」にたどり着くまでに長い時間同じままです。理解を深めるために、レースカーのように入力Qに書き込み、古い車のように読みます:)

34
Kobi K

シリアルポートを開くときに、タイムアウトを「なし」に設定する必要があります。

ser = serial.Serial(**bco_port**, timeout=None, baudrate=115000, xonxoff=False, rtscts=False, dsrdtr=False) 

これはブロックコマンドであるため、末尾に改行(\ nまたは\ r\n)が含まれるデータを受信するまで待機しています。line = ser.readline()

データを取得したら、できるだけ早く返します。

4
Fabian Meier

マニュアル から:

パラメータタイムアウトの可能な値:…xタイムアウトをx秒に設定

そして

readlines(sizehint = None、eol = '\ n')タイムアウトするまで、行のリストを読み取ります。 sizehintは無視され、組み込みのFileオブジェクトとのAPI互換性のためにのみ存在します。

この関数はタイムアウトでのみ戻ることに注意してください。

したがって、readlinesは最大2秒ごとに戻ります。 Timが示唆したようにread()を使用します。

2
msw

これに対する非常に良い解決策を見つけることができます here

以下は、pyserialオブジェクトのラッパーとして機能するクラスです。 CPUを100%使用せずに行を読み取ることができます。タイムアウトロジックは含まれていません。タイムアウトが発生すると、self.s.read(i)は空の文字列を返します。タイムアウトを示す例外をスローすることもできます。

また、著者によると高速であると想定されています。

以下のコードでは790 kB /秒が得られますが、コードをpyserialのreadlineメソッドに置き換えると、わずか170kB /秒になります。

class ReadLine:
    def __init__(self, s):
        self.buf = bytearray()
        self.s = s

    def readline(self):
        i = self.buf.find(b"\n")
        if i >= 0:
            r = self.buf[:i+1]
            self.buf = self.buf[i+1:]
            return r
        while True:
            i = max(1, min(2048, self.s.in_waiting))
            data = self.s.read(i)
            i = data.find(b"\n")
            if i >= 0:
                r = self.buf + data[:i+1]
                self.buf[0:] = data[i+1:]
                return r
            else:
                self.buf.extend(data)

ser = serial.Serial('COM7', 9600)
rl = ReadLine(ser)

while True:

    print(rl.readline())
0
Joe