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

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

新規登録して質問してみよう
ただいま回答率
85.50%
シリアルポート

シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

Q&A

2回答

1131閲覧

Arduinoアナログ入力+Processing波形表示におけるchの順序について

Wombat

総合スコア1

シリアルポート

シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

0グッド

0クリップ

投稿2021/12/23 10:13

Arduinoアナログ入力(3ch)から信号データを入れて,Processingで波形表示させています.
Arduinoは互換機を使っています.サンプリングは64Hzです.OSはLinux Mintです.
ポートの定義は
port = new Serial(this, Serial.list()[0], 9600);

そして,Aruduinoからデータを受けとる部分は下記です.
// for 3ch input
void serialEvent( Serial p ) {
if ( port.available() > 11 ) {
for ( i = 0; i < 3; i++ ) {
data[i] = port.read() + port.read() * 256 ;
}
port.write( '*' );
}
}

ところが,実行するとある条件(PCの種類?)で,受け取るch順が実行するタイミングによって
バラバラになります.つまりA0,A1,A2の順に入力しているはずが,入れ替わったりします.
これは何か他にchの入力順を決めるための,条件設定などが必要なのでしょうか?
今まで気付かなかったのですが,PCをあるもの(Let's Note)に替えた途端にこの現象が起きました.
ヒントをいただければと思います.
どうぞよろしくお願いします.

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

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

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

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

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

guest

回答2

0

通信を扱うプログラムは、通信エラーが「当然に起こる」ことを前提に設計するものです。
「たまたま動く」ことを頼りにしてはいけません。ノイズで1バイト欠落したり、余計な1バイトが受信できてしまったとして、その回は仕方がないとしても以降のデータでは復帰できるように、何らかの方法(あなたがよいと思う方法)で、3つのデータが弁別できるようにするべきでしょう。

本題から若干はずれますが(関係なくはない)、

if ( port.available() > 11 ) { for ( i = 0; i < 3; i++ ) { data[i] = port.read() + port.read() * 256 ; }

なぜ12バイト以上のデータの受信を確認したあとで6バイトの受信を行う仕組みになっているのですか?


自己解決にするとのことですがまぁとっかかりだけでも。

D0L D0H D1L D1H D2L D2H D0L D0H D1L D1H ...
とダラダラ並んでいるだけのデータ列では、取りこぼしがあって例えばD0Hが抜けたときに受信側が
(D0L D1L) (D1H D2L) (D2H D0L)
のようなペアで解釈してしまうとデータは滅茶苦茶になって自力では復帰できません。
あるいは、たまたま受信を開始したのが途中からで
D2L D2H D0L D0H D1L D1H ...
と受信していれば、受信側はD0のつもりでD2を(以下順次ズレて再起不能)得てしまうことになります。

要は、通信データ列(だけ)を見てどれが1つ目、2つ目、3つ目のデータか認識できるように考えれば(送受信間の通信の約束=プロトコルを決めれば)いいわけです。

データ間隔が大きく空いているなら、
D0L D0H D1L D1H D2L D2H [間隔]
の間隔時間を測ることによってデータの区切りを知ることができますが、今回は64Hz=15ms周期とのことで、Processingのdraw()繰り返し実行のデフォルト周期(60Hz)との絡みもあって検出は難しいですね

となると、データ列に「位置を知るための特殊なデータ」を埋め込むことで位置を知るという方法が考えられるでしょう。テキストデータであれば、データ本体には登場しない改行コードであるとか','とかをデータ区切りに使うというのはよくあるパターンではありますが、今回はバイナリデータなのでちょっと考える必要があります。

Arduino UNO(ただArudinoとだけいう名前の機種はありません。原則としてArduinoのナニなのかを明示するようにしてください)のADCは10bitですから、高位側のデータは(特に加工していなければ)4以上にはなりません。つまり、4以上のデータが2つ続けば「それは特殊なデータだ」と知ることができるわけです。
例えば、
0xff 0xff D0L D0H D1L D1H D2L D2H
というのが一組のデータという規則にすれば、4以下(前回のD2H)、0xff, 0xffというデータ並びを見つければその次がD0Lという期待はまぁ正当でしょう(単純に0xff 0xffの並びだけを探してしまうと、D0Lが0xffになる可能性があるので誤検出が考えられます)。9600bpsで1byteの伝送に1msかかるとして、64Hz=15.6ms周期に8byte=8msのデータ量ですから収まります。

Processing

1//D0Lの頭出しをするループ(動作チェック等はしていません) 2byte head0,head1; 3boolean found_FF=false; 4head0=0;//仮データ 5while(true){ 6 if(port.available()){ 7 head1=port.read();//2byte目受信 8 if(found_FF && head1=0xff){ //D2L,0xff,0xffのパターンを見つけた。次はD0L 9 break; 10 } 11 found_FF=(head0<4 && head1==0xff);//4以下-0xffのシーケンス発見 12 head0=head1;//今回の2byte目は次回シーケンスの1byte目 13 } 14} 15//頭出しができているので安心して取得 16if(port.available()>=6){ 17 for ( i = 0; i < 3; i++ ) { 18 data[i] = port.read() + port.read() * 256 ; 19 } 20}

のように処理すれば、何らかのズレが発生したときにも次回には修正されることになるかと思いますがいかが。(もちろん送信側にも0xff 0xffを送る処理を追加する必要があります)

投稿2021/12/23 12:30

編集2021/12/23 23:43
thkana

総合スコア7610

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

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

Wombat

2021/12/23 12:40

回答ありがとうございます.全くわからないままにたまたま動いたソフトのソースをコピペしていたようですね.ちょっと周辺をきちんと勉強してから再度,自己解決したいと思います.ありがとうございました.
Wombat

2021/12/23 23:55

さらなるご教示をありがとうございました.サンプリングレートは一応設定しているのですが,当然PCの処理速度で制限される場合があります.Arduino Unoの件,たしかに質問の基本ですね.シリアル通信の基本から勉強し直しが早いようなので,この冬の間に取り組みたいと思っています.皆様の回答でここから詰めなければいけない対象がよくわかりました.本当にありがとうございました.初心者の質問に真摯に答えていただきまして,感謝申し上げます.
guest

0

data[i] = port.read() + port.read() * 256 ;

最初の1バイトを読み出して、次の1バイトがまだ来ていない場合、このデータはどうなるのか考えてみよう。

シリアル通信は遅いです。1バイトの送信に例えば1秒かかると考えてください。
たとえそのような場合でも、正常に受信できるようにする必要があります

投稿2021/12/23 10:18

y_waiwai

総合スコア87719

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

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

Wombat

2021/12/23 10:43

回答ありがとうございます.ただ,今まではまったく問題なく動いていて(10台近くのPC),今回のみおかしくなったのが,よくわからないのです.遅延ルーチンを入れる必要があるということですか?ほとんど既存ソフトのコピペでプログラムを作っていますので,詳細を検討していません.よろしくお願いします.
y_waiwai

2021/12/23 11:41

たまたま上手くタイミングが合ってちゃんと動いているように見えてるんでしょうね
thkana

2021/12/23 23:40

port.available()でデータ受信量を検査しているので、 > 最初の1バイトを読み出して、次の1バイトがまだ来ていない場合、 ということはありません。 > 1バイトの送信に例えば1秒かかる これは、データ間隔の話として別にシリアルに限定の話ではありません。10Gbpsの通信だってデータ間隔が1秒空くことは普通にあるでしょう。「1バイトの送信」そのものに1秒かかることはありません(モールス信号を耳で聞く通信ならともかく...)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問