質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

5回答

946閲覧

Python : 可変byteデータ数の読み込み方法を教えてください。

haruiwa

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2023/04/19 04:46

実現したいこと

ここに実現したいことを箇条書きで書いてください。

  • pythonのシリアル通信にて受信したい

前提

センサへの測定結果要求コマンド送信後の返信取得が目的です。ラインモニター上では送信にミスは無く
返信のメッセージもセンサ側から発信されているのは確認しております。
その値を読み込むにあたり以下のコードを書きました。
以下のser.read()の部分に書いた通りなのですが、返信のbyte数が送信するリクエストによって変わります。
ラインモニタの返信部数を参考に要素数を入れれば取得可能ですがナンセンスな方法です。
送られるbyte数を調べて、その数だけ ser.read()を繰り返してデータを取り出したいのですが
どのようにコードを入力すれば良いのか分かりませんでした。

python 3.9.13
ser = serial.Serial('COM9', 38400, 8)
cmdData = bytearray([1, 2, 128, 6, 162, 0, 162])
ser.write(cmdData)
line = ser.read() <-----こうやると1byte分しか受け取れない
line = ser.read(14) <------いつも14byteとは限らない

textbox4.delete(0, tk.END)
textbox4.insert(tk.END, line)


Mater controller Slave controller Read Request Packet -------------------------------------------------> ACK(0x06) <------------------------------------------------ Response Data Packet <------------------------------------------------ ACK(0x06) ----------------------------------------------->

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dameo

2023/04/19 05:30

一般に使用されるpythonであるcpythonにシリアル通信機能はありません。 正確なpython処理系、シリアル通信機能として何を使っているか、マイコン基盤なのか、OS付きの基盤なのかPCなのか、基盤の型番とOSを含め明確にしてください。 またプロトコル仕様は全体を見て実装を決めましょう(説明がないので第三者には分からない)。 長さが入っているか、ありえないバイト列で判定しているか、一定時間で切るか、プロトコルの想定があるはずです。 (pythonのシリアルが確定しないので)C/C++の汎用な設計では、リアルタイムに複数のタスクを実行する必要があるので、受信タスクも送信タスクも独立して動かしてリングバッファに貯めておき、それをコマンドQueueの要素から参照するような形態になります。
TakaiY

2023/04/24 01:57

使っているセンサのメーカ・型番などの情報は提示いただけませんか。
guest

回答5

0

PySerial の timeoutと、.in_waitingを使えば、
連続したデータはひと固まりで処理できます。

投稿2023/04/21 23:16

Vngzh7

総合スコア4

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

他の方の回答と同じですが、通信はプロトコルに沿って行なわれる必要があります。そのプロトコルはいろいろ方式のものがあります。
シリアル通信でデータを送るにあたっても、いろいろな方式があります。
質問にある「Read Request Packetを送ったらAckが返る」というのもプロトコルの要素の1つです。
データの送受信についても、どのようにデータが送られて、どのような構成のデータなのかは、そのプロトコルによります。

お使いの「センサ」がどのようなプロトコルなのかは、仕様書などを確認すればわかるはずです。

投稿2023/04/19 09:49

TakaiY

総合スコア12743

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もしResponse Data Packet内にデータの区切りが分かる情報が入っていればそれを使います
例えば「ASCII形式で送って最後は改行」のようなフォーマットなら改行まで読めばいいですし
「nバイト目にパケット全体の長さが書いてある」であればその情報を使います

そうでなければ「ナンセンスな方法」を取るほかありません。

投稿2023/04/19 05:11

ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

haruiwa

2023/04/24 04:22

やはりそうですか
guest

0

何らかの方法で通信バイト数というのは決定しておく必要があります

  1. 常に一定バイトの通信とする
  2. メッセージの最初に通信バイト数を送る
  3. メッセージの終端に、通常ではありえないバイト列を送るようにして、受信側ではそれを受信するまで受信する

などなど。

投稿2023/04/19 04:52

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

haruiwa

2023/04/24 05:15

ご回答ありがとうございます。プロトコルとしては用意されているものなので、その内容を詳しく確認するしかないです。以下が受信データなのですが、受信データは受信要求コマンド送信後に、折り返し返信が来るようになっております。5番目が6番目からレスポンスメッセージの最後までのパケット数になるので、ここまでの情報を利用して以下のようにしてみました。 06H 00H 02H 80H 0AH A2H 00H A2H 52H 45H 56H 45H 52H 53H 45H 00H ECH ser.write(cmdData) <-----コマンド送信(受信始める為) line = ser.read(5)  <----- パケット数部分までの読み込み Psize = int(line[4]) <-----リスト要素4(パケット数)読み込み ser.write(cmdData) <-----コマンド送信 line = line + (ser.read(Psize + 2)) <----パケット数以降データ読み込み結合 lineArr = (bytearray(line)) <----変数lineをbitearray型へ変換 ResCount = (len(lineArr)-10) <-----全バイト数から固定バイト数を引いてレスのバイト数を算出 ResF = str(lineArr[8:8+ResCount]) <----リストをスライスしてレスのみ抜き取る 以上、レスバイト数の確認用に1度リクエストコマンド送信 レスバイト数確定後に全取得するために、もう一度リクエストコマンド送信 と1つの情報入手の為に、2度もリクエストコマンド送ってますが、正しい 方法なのか判断できません。 。
guest

0

自己解決

ser.write(cmdData) <-----コマンド送信(受信始める為)

line = ser.read(5)  <----- パケット数部分までの読み込み
Psize = int(line[4]) <-----リスト要素4(パケット数)読み込み

ser.write(cmdData) <-----コマンド送信

line = line + (ser.read(Psize + 2)) <----パケット数以降データ読み込み結合
lineArr = (bytearray(line)) <----変数lineをbitearray型へ変換
ResCount = (len(lineArr)-10) <-----全バイト数から固定バイト数を引いてレスのバイト数を算出
ResF = str(lineArr[8:8+ResCount]) <----リストをスライスしてレスのみ抜き取る

少しスマートな方法では無いのですが、上記方法で目的のレスデータが取り出せたので今後も良い方法を探りつつとりあえずは、こちらの方法で進めてみます。皆様ありがとうございました。

投稿2023/04/25 23:56

haruiwa

総合スコア1

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2023/04/26 00:24

2回めのコマンド送信は不要では?
TakaiY

2023/04/26 01:17

別の質問の回答に >レスバイト数確定後に全取得するために、もう一度リクエストコマンド送信と1つの情報入手の為に、2度もリクエストコマンド送ってますが、正しい方法なのか判断できません。 とありますが、僕も2回目のコマンド送信は不要と思います。 というより、送信してはいけません。 ご存知と思いますが、受信したデータはread()するまでバッファに蓄積されています。なので、2度目の送信をしなくてもデータはあるはずです。 また、質問のプロトコルを見ると、受信が完了したらこちらからackを送る必要があるので、そういう意味でも問題があります。そういう意味では最後にackを送信する必要もありますね。 また、データの処理ですが、コマンド送信後のセンサからのackは別で処理したほうがいいと思います。 1バイトずつ読むループで待ち合わせします。来なければリトライしたり、もし何らかの理由で余計なデータが混入してしった場合のガードになります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問