19


25

Arduinoをコンピュータに接続してループを実行し、シリアルポートを介して値を100 msごとにコンピュータに送信します。

私は数秒ごとにシリアルポートから読み込むPythonスクリプトを作りたいので、Arduinoから最後に送られたものだけを見たいと思います。

Pyserialでどのようにしますか?

これが私が試したコードで、うまくいきません。 行を順番に読み取ります。

シリアルインポート時間をインポート

ser = serial.Serial( 'com4'、9600、timeout = 1)1:time.sleep(10)print ser.readline()#デバイスから送信された最新の行を取得する方法を教えてください。

10 Answer


28


多分私はあなたの質問を誤解していますが、それはシリアルラインであるので、あなたはArduinoから送られた全てを順番に読む必要があります - それはあなたがそれを読むまでArduinoにバッファされます。

最新のものが送信されたことを示すステータス表示を使用したい場合は、質問にコードを組み込んだスレッドを使用し(スリープを除く)、最後の1行をArduinoの最新の行として読んでください。

更新: `+ mtasic `のサンプルコードは非常に優れていますが、 ` inWaiting()`が呼び出されたときにArduinoが部分的な行を送信した場合、切り捨てられた行が表示されます。 代わりに、最後の_complete_行を ` last_received `に入れ、部分的な行を ` buffer +`に保持して、次回のループに追加できるようにします。 このようなもの:

def receiving(ser):
    global last_received

    buffer_string = ''
    while True:
        buffer_string = buffer_string + ser.read(ser.inWaiting())
        if '\n' in buffer_string:
            lines = buffer_string.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            #If the Arduino sends lots of empty lines, you'll lose the
            #last filled line, so you could make the above statement conditional
            #like so: if lines[-2]: last_received = lines[-2]
            buffer_string = lines[-1]

`+ readline()+`の使用に関して:Pyserialのドキュメントには次のように書かれています(わかりやすくするために少し編集し、readlines()に言及しています):

_ 「readline」を使用するときは注意してください。 シリアルポートを開くときにタイムアウトを指定してください。そうしないと、改行文字を受け取らないと永久にブロックされる可能性があります。 また、 "readlines()"はタイムアウトでのみ機能します。 それはタイムアウトを持つことに依存し、それをEOF(ファイルの終わり)として解釈します。 _

これは私にはかなり合理的です。


11


シリアルインポートから*スレッディングインポートからThread

last_received = ''

受信中のdef(ser):グローバルなlast_received buffer = ''

Trueの場合:#last_received = ser.readline()buffer = ser.read(ser.inWaiting())buffer: 'last_received、buffer = buffer.split(' \ n ')の場合[ -  2:]

__name__ == '__main__'の場合:ser =シリアル(ポート=なし、ボーレート= 9600、バイトサイズ= EIGHTBITS、パリティ= PARITY_NONE、ストップビット= STOPBITS_ONE、タイムアウト= 0.1、xonxoff = 0、rtscts = 0、interCharTimeout =なし)

スレッド(ターゲット=受信、引数=(ser、))。start()


7


これらの解決策は文字を待っている間CPUを独占します。

read(1)に対して少なくとも1回ブロッキング呼び出しを行うべきです。

Trueの場合:バッファ内の '\ n'の場合:pass#すでにバッファ内の行である場合はskipをスキップします。 ))#残りのバッファ文字を取得する

…​and do the split thing as before.


5


`+ ser.flushInput()+`を使用して、現在バッファーにあるすべてのシリアルデータをフラッシュできます。

古いデータを消去した後、ser.readline()を使用してシリアルデバイスから最新のデータを取得できます。

私はそれがここで提案された他の解決策より少し簡単だと思います。 私のために働いた、それがあなたに適していることを願っています。


3


この方法では、各行のすべてのデータを収集するためのタイムアウトと、追加の行を待つための異なるタイムアウトを別々に制御できます。

#シリアルポートの最後の行を取得するlines = serial_com()lines [-1]

def serial_com(): '' 'シリアル通信:応答を受け取る' ''

e:print( "serial port '{}'を開くことができませんでした:{}"。 e))

#Trueのときにシリアルポートlines = []から応答を読み取ります。line = serial_port.readline()lines.append(line.decode( 'utf-8')。rstrip())

#各行の後に新しいデータを待つtimeout = time.time()0.1で、serial_port.inWaiting()ではなく、timeout> time.time():serial_port.inWaiting()でなければpass:break

#シリアルポートを閉じるserial_port.close()リターンライン


2


タイムアウトまでブロックされたreadline()への最後の呼び出しで送信されたすべてを読むためにループが必要になるでしょう。 そう:

def readLastLine(ser):last_data = ''の場合True:data = ser.readline()data!= ''の場合:last_data = data else:return last_data


2


mtasicへのわずかな修正

私はこのコードが同じようなアプリケーションにとって非常に有用であると思ったが、定期的に情報を送るシリアルデバイスから戻ってくるすべての行が必要でした。

最初の要素を先頭からポップして記録し、残りの要素を新しいバッファとして再結合してそこから続行することにしました。

これはGregが求めていたものではないことに気付きましたが、副次的なメモとして共有する価値があると思いました。

受信中のdef(ser):グローバルなlast_received

buffer = '' Trueの場合:buffer = buffer ser.read(ser.inWaiting())。バッファの '\ n'の場合:lines = buffer.split( '\ n')last_received = lines.pop(0)

buffer = '\ n'結合(行)


2


無限ループ内で `+ .inWaiting()+`を使用すると問題が生じる場合があります。 実装によってはhttp://en.wikipedia.org/wiki/Central_processing_unit [CPU]全体を占有する可能性があります。 代わりに、読み取る特定のサイズのデータ​​を使用することをお勧めします。 したがって、この場合は、たとえば次のようにします。

ser.read(1024)


2


多すぎる合併症

改行または他の配列操作によってbytesオブジェクトを分割する理由は何ですか? 私はあなたの問題を解決する最も簡単な方法を書きます:

import serial s = serial.Serial(31)s.write(bytes( "ATI \ r \ n"、 "utf-8")); Trueの場合:s.read(s.inWaiting())のバイトの場合はlast = '':len(last)> 0の場合はlast = chr(byte)>: -8 "))最後= ''


0


これは、100%CPUなしで最新の行を読むことを可能にするラッパーを使った例です。

クラスReadLine:行ソースを読み込むためのpyserialオブジェクトラッパー:https://github.com/pyserial/pyserial/issues/216 "" def __init __(self、s):self.buf = bytearray()self.s = s

def readline(self):i> = 0の場合、i = self.buf.find(b "\ n")r = self.buf [:i 1] self.buf = self.buf [i 1:] return r Trueの場合:i = max(1、min(2048、self.s.in_waiting))data = self.s.read(i)i> = 0の場合、i = data.find(b "\ n"):r = self.buf data [:i 1] self.buf [0:] = data [i 1:] return rそれ以外の場合:self.buf.extend(data)

s = serial.Serial( '/ dev / ttyS0')device = ReadLine(True)の間:print(device.readline())