2

Python2.5.4とWindows7を使用しています。

pygameを使ってマイクロコントローラーと情報を送受信するプログラムを作ろうとしています。このコードは、マイクロコントローラーがpygameにデータを書き込むだけで正常に機能しますが、情報を受け取るマイクロコントローラーコード(readline)に行が含まれていると、pygameウィンドウがフリーズします(ウィンドウを閉じるだけでなく、問題が何であるかを確認できます) )。マイクロコントローラーとpygame/pyserialがお互いに話したり聞いたりした経験がある人はいないでしょうか?

私は潜在的に類似した投稿を読みましたが、コードを理解しておらず、同じ問題であるかどうかもわかりませんでした。私はこれらのフォーラムで「フロー制御」という用語を読みましたが、これが私の問題であるかどうか疑問に思っていますか?

私のコードは次のとおりです。

import os, pygame, math, serial   
from pygame.locals import *
from pygame.compat import geterror
from time import clock, time
pygame.init()
w = 1100   #sets pygame screen width
h = 642   #sets pygame screen height
screen = pygame.display.set_mode((w, h),0,32)  #make and display screen

pygame.display.flip()   #Update screen
running = 1
font = pygame.font.Font(None, 36)
clock = pygame.time.Clock()
port = serial.Serial("COM2", 115200)

while running:          #Loop this
   for event in pygame.event.get():    #get user input
      if event.type == pygame.QUIT:    #if user clicks the close X
           running = 0                 #make running 0 to break out of loop

   temp = float(port.readline())
   clock.tick(100)
   value = font.render(str(temp), 1, (100, 100, 100))
   screen.blit(value, (280,165))
   pygame.display.flip()   #Update screen
   port.write('3')
4

2 に答える 2

2

行末文字を待っている間に readline がブロックされている可能性があります。キャリッジ リターンとライン フィードの組み合わせ。マイクロコントローラーは、readline が戻る前に、これらの文字の 1 つまたは両方を送信する必要があります。pyserial のドキュメントをチェックして、readline が期待するライン ターム chars を確認し、ターミナルを調べたり、シリアル ストリームで 16 進ダンプを実行したりして、uC がそれらを送信していることを確認する必要があります。

于 2012-06-22T14:00:59.320 に答える
1

最も可能性が高いと思われる問題: デッドロック

Jeff Laughlin の投稿を少し拡張します。

非常に多くの人がこのデッドロックの問題に遭遇しました:

  • マイクロコントローラが改行文字を送信するのを待っているブロッキング readline() コマンドの途中にあるため、PC は文字を送信できません。
  • マイクロコントローラーは、PC が改行文字を送信するのを待っているブロッキング readline() コマンドの途中にあるため、文字を送信できません。

どちらも、相手が何かをするのを永遠に待つことになります。

双方向通信システムがこのデッドロックに陥る方法は多数あります。おそらく、シリアル ケーブル上を移動する改行文字は、改行のように見えなくなるほど、ごくわずかに破損する可能性があります。おそらく、長い文字列が受信側の処理速度を超えて送信され、一部のバッファがオーバーフローし、失われたバイトの 1 つが改行文字でした。この改行がマイクロから PC または PC からマイクロの方向に向かうかどうかは問題ではありません。どちらの方法でも同じデッドロックに陥ります。

回避策 1: タイムアウト

「import serial」によってロードされるpyserial パッケージのドキュメントには、この問題に対する部分的な回避策が 1 つあります。タイムアウトを設定します。ドキュメントでは、具体的に次のことを推奨しています。

シリアルポートを開くときはタイムアウトを指定してください。そうしないと、改行文字が受信されない場合、永久にブロックされる可能性があります。

PC とマイクロの両方でその回避策を実装できますか?

回避策 2: ノンブロッキング readline

多くの人がノンブロッキングの readline() サブルーチンを実装しています。これは次のように機能します:

def try_readline():
  • 新しいバイトがシリアル ポートに入っていますか、それともシリアル バッファが空ですか? (おそらくinWaiting()のようなもので確認してください)。
  • まだ空の場合、try_readline() はすぐに null 文字列を返します。
  • (オプション) 最後にバイトをしてから本当に長い時間が経ちましたか? その場合は、バッファを空の文字列にリセットします。
  • シリアル ポートから 1 バイトを読み取り、それを内部バッファーの末尾に追加します。
  • バッファー (有効なメッセージよりも数バイト長い) がオーバーフローしそうですか? その場合は、バッファーを空の文字列にリセットします。
  • 今読み取ったバイトは改行文字ですか?
  • 改行文字でない場合、try_readline() はすぐに null 文字列を返します。
  • ねえ、それは改行文字です。ついに!
  • メッセージを内部バッファから戻り文字列にコピーします。
  • バッファを空の文字列にリセットします。
  • try_readline() は、戻り文字列にメッセージを返します。

さらなる議論

いずれの回避策でも、try_readline 関数が null 文字列以外を返すかどうかに関係なく、定期的かつ無条件にプログラムをセットアップします。readline() 関数がタイムアウトするか、有効なメッセージを受信するかどうかにかかわらず、無条件に情報行を送信します。

また、メッセージの途中でシリアル ケーブルを接続し、ソフトウェアがメッセージの半分とそれに続く改行を受信した場合に、正確にはどうなるかについて考えるかもしれません。また、送信機が一連の改行を続けて送信するとどうなるでしょうか?

双方向コミュニケーションは、人間がほとんど無意識に行っていることの 1 つであり、その複雑さに驚かされます。

ps: Pyserial で PC から Arduino への変換を行うこの小さなプログラムを見たことがありますか?

ps: おそらく、 Serial Programming Wikibookの最新のラフ ドラフトをざっと読んで、隙間のある穴の 1 つまたは 2 つを埋めてください。

于 2012-06-23T02:35:39.030 に答える