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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Arduino

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

Q&A

4回答

5048閲覧

ラズパイで取得したセンサー値を2線式RS485を介してArduinoに送信するコードについて

nosuke_ko

総合スコア5

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Arduino

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

0グッド

0クリップ

投稿2019/12/13 05:21

編集2019/12/13 05:32

前提・実現したいこと

①ラズパイで取得した可変抵抗器の値を取得 (実現済み)
②2線式RS485のUSBを用いてシリアル通信で値をArduinoに送信(200mのケーブルを介しています)
③ラズパイから受け取った値を適切に変換してモーターを駆動する

発生している問題・エラーメッセージ

ラズパイからArduinoへ送信した値がArduinoで正しく受け取れていない。

該当のソースコード

ラズパイ側  Python # -*- coding: utf-8 -*- import RPi.GPIO as GPIO import serial import time from time import sleep GPIO.setwarnings(False) ser = serial.Serial('/dev/ttyUSB0',9600) ~ 可変抵抗器の値を取得するためのコード ここは問題ないので省略します  ~ try: while True: inputVal0 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS) //inputVal0には可変抵抗器の値が入っています head = 128 high = (inputVal0 >> 7) & 127 low = inputVal0 & 127 headByte = head.to_bytes(1, 'big') highByte = high.to_bytes(1, 'big') lowByte = low.to_bytes(1, 'big') ser.write(headByte) ser.write(highByte) ser.write(lowByte) print(inputVal0) sleep(1.0) //このwhileの中のコードはすべて動いていることが確認できました。 except KeyboardInterrupt: pass GPIO.cleanup()
Arduino側 C言語 #include <stdio.h> #include <stdlib.h> #include <Servo.h> Servo motor; int val = 0; bool isValid = false; void setup() { Serial.begin(9600); motor.attach(9); delay(500); } void loop() { isValid = false; if (Serial.available() >= 0) {      // Lチカを使ってここまでコードを 読めていることは確認できました。   int head = Serial.read();   if (head == 128) { int high = Serial.read(); int low = Serial.read(); val = (high<<7) + low; int vel = map(val,0,4095,1300,1700); //ラズパイから受け取った可変抵抗器の値を変換 motor.writeMicroseconds(vel); if (0 <= val <= 1023) { isValid = true; } } }else{ Serial.print("not available"); } delay(100); }

補足情報(FW/ツールのバージョンなど)

ラズパイは Raspberry pi 3 Model B
ArduinoはELEGOO UNO R3
を使用しています。

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

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

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

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

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

thkana

2019/12/14 04:41

isValid変数はなんのお仕事をしているのでしょう?
nosuke_ko

2019/12/14 05:20

他の方が書いたコードを見よう見まねで書いているので、書いてありますが何の意味もないかもしれません。 消しても全く問題ないと思います。
guest

回答4

0

すでに指摘があるように
Serial.available() >= 0
は明らかにおかしいですし、その後のデータ受信はデータが来ている保証はありませんが、
それ以前に...

前提となるはずのRS485を正しく扱えているのかという情報がないので確認ですが、
・Arduino側でのRS485->UARTへの変換は出来ていますか?
・2線式ってことは半二重かと思いますが、送受信の切り替えなど必要な操作は行われていますか? RS232のRTSに割り当てられていたりするようですが。(自動で切り替わるものもありますが、それならそれの設定は出来ていますか?)

単純な、例えば1と0を送信して受け取るだけの動作を、短距離の伝送であればきちんと出来ていますか。そのへんから確かめてみては。

投稿2019/12/14 00:13

thkana

総合スコア7629

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

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

nosuke_ko

2019/12/14 02:30

thkana様 ご回答ありがとうございます。Serial.available() >= 3としたところarduinoでデータが受信できていないことが判明いたしました。 RS485についてですが、 お恥ずかしながら僕自身知識が全くなくて現在手探りでコードの作成を進めている状態です。 ・UARTへの変換はできていません。(UARTが何なのかもわからない状態です…) ・ネットなどで調べていて送受信の切り替えが必要ということ自体は分かったのですが、やり方がわからず切り替え操作はできていないです。ラズパイとArduinoの双方向的な通信ではなく、ラズパイから一方的に送信してArduinoが受信するだけであればできるのかな、と思い上のようなコードにしました。 ちなみにですが、ラズパイとArduinoをUSBで接続した場合には欲しい挙動(ラズパイにつなげた可変抵抗器のつまみをひねることでArduinoにつなげたモーターの速度を制御する)を得ることができています。
thkana

2019/12/14 03:03

ハード的にちゃんと繋がっていなければソフトがどんなに頑張っても通信出来るわけがありません。 ハードを確かにしてからソフトを検討するべきです。 > ・UARTへの変換はできていません。(UARTが何なのかもわからない状態です…) ではどうやってArduinoに通信線をつないでいるのですか? > やり方がわからず切り替え操作はできていないです。 一方向の通信であれば途中で切り替える操作は不要ですが、それでも最初にRaspberryPiからArduinoにデータが流れるような設定に出来なければ通信が出来るわけありません。 とりあえず、USB-RS485変換器の型番はわかりますか? どのように扱うかの資料が公開されているかも知れません。
nosuke_ko

2019/12/14 06:34 編集

そうですよね、、まずハードの確認をしてみます。 https://www.amazon.co.jp/FTDI-USB-RS485%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%82%B1%E3%83%BC%E3%83%96%E3%83%ABRS485-USB%E3%82%B3%E3%83%B3%E3%83%90%E3%83%BC%E3%82%BF%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB-RS485-WE-1800-BT%E5%AF%BE%E5%BF%9C/dp/B075VMK99R/ref=sr_1_19?adgrpid=50762324622&gclid=CjwKCAiAis3vBRBdEiwAHXB29J0XPB83IQjN-IQPL547Rp5bwUIjIMAeePg8XND6m2Db57cAFC2TkhoCeLkQAvD_BwE&hvadid=338571775169&hvdev=c&hvlocphy=1009285&hvnetw=g&hvpos=1t1&hvqmt=b&hvrand=17712298440849130185&hvtargid=kwd-299852377177&hydadcr=9354_11298756&jp-ad-ap=0&keywords=rs485+usb+%E5%A4%89%E6%8F%9B&qid=1576305180&sr=8-19 このUSBケーブルを二つ使って片方はArduinoにもう片方はラズパイに接続しています。そして、その中間に200mのケーブルがあるというような構成です。 低レベルな質問をしてしまって申し訳ありませんが、このUSBケーブルを使っている時点でUARTへの変換はできているのでしょうか。 送信のSerial.write、受信のSerial.readでデータの送受信はできていると認識していました。 変換器はジャンク品のようなものを使っていて、型番は分からない状態です。申し訳ありません。
nosuke_ko

2019/12/14 06:23

USB-RS485変換器がラズパイで認識されていないようだったので、ちゃんとした正規品を買うことにしました。
thkana

2019/12/14 11:35

認識していない変換器で通信できるとなぜ思ったのか、/dev/ttyUSB0というデバイスはなんなのか...一つ一つ確実に積み上げていかないと、なにやってるのかわからなくなるんじゃないかと思いますが大丈夫ですか? ...って、大丈夫じゃないから質問してるんですね。 とりあえず、そのアマゾンのページに「USB-RS485-WE-1800-BTと互換性のある」とありますから、そちらで調べてみるとこれはFTDIの製品みたいでまともなマニュアルがみつかります。FTDIの石をちゃんと使っていればドライバも簡単にみつかりそうなものですが。ちなみに、特に設定を変えていなければ送受信の切り替えは自動のようですね。(USB-RS485変換だと自動切り替えじゃないとまともに制御出来ないか...前にそれで悩んだことがあったのを思い出した) > このUSBケーブルを使っている時点でUARTへの変換はできているのでしょうか。 そんなわけないでしょう。RS485への変換ケーブルですから。Arduinoには直接RS485信号は繋げないのですがそこはどうしているのですか?
thkana

2019/12/14 11:39

あと、RS485は終端抵抗が必要です...というのも「なにそれ?」ですか? 知らなければググれば一杯情報が見つかるはずですので調べて下さいね。9600bpsと低速とはいえ、200mというのがそこそこ長距離ですし。
guest

0

nosuke_koさん、

if (Serial.available() >= 0) { だと
>=0 なので、一文字も受信しなくても、実行される(常にTrue?)ので、> に。(elseも以降もメッセージが出まくりそうなので、いらないかも?)

if文の処理内で3バイト呼び出ししてるようなので、if (Serial.available() >= 3) として、3バイト以上受信バッファにはいったら、処理をする、でしょうか。
受信前に、Serial.read()を呼ぶと、エラーで-1が返ってきます。

https://www.arduino.cc/reference/en/language/functions/communication/serial/available/

...
Serial.available()
...
Returns
The number of bytes available to read. => 何文字読み出せるか => 受信したデータのバイト数
...

投稿2019/12/13 16:54

編集2019/12/13 21:37
mt08

総合スコア1825

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

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

nosuke_ko

2019/12/14 01:56

mt08様 ご回答ありがとうございます。if (Serial.available() >= 3) に修正しました。Arduino側でデータの受信ができてないままSerial.readの処理をしていたことが判明しました。 データの受信ができるようにもう一度コードの検討をしてみます。
guest

0

シリアル通信というのは遅いです
if (Serial.available() >= 0) { 
1文字でも受信したらこのif文が実行されます
それではまずいでしょう

1バイトづつ受信するように、
そもそもの処理を見直しましょう

投稿2019/12/13 10:53

y_waiwai

総合スコア87749

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

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

nosuke_ko

2019/12/14 01:51

ご回答ありがとうございます。if (Serial.available() >= 0) { ~ }の中身は読めているとLチカを使って 確認できたので、Arduino側で受信できていると勘違いしていましたが>=0になっているから実行されているだけだったんですね。if (Serial.available() >= 3 {に修正したところ受信できていないことがわかりました。 ありがとうございます。
y_waiwai

2019/12/14 01:59

3文字受信できるのを待つってのもいいですが、それでは50点です。 ・最初の1バイトを受信 ・ヘッダバイトか?そうでないならそれを捨ててやり直し ・2バイトを順次受信 ・きちんと成立したデータとして処理 という処理にしましょう。
nosuke_ko

2019/12/14 02:54

isValid = false; if (Serial.available() >= 1) { int head = Serial.read(); if (head == 128) { while(Serial.available() < 2); int high = Serial.read(); int low = Serial.read(); val = (high<<7) + low; int vel = map(val,0,4095,1300,1700); motor.writeMicroseconds(vel); Serial.print("velocity:"); Serial.println(vel); if (0 <= val <= 1023) { isValid = true; } } } アドバイスありがとうございます。上のようなコードに変更いたしました。
y_waiwai

2019/12/14 02:59

それで、Arduino側のコードに入っているDelayを削除しときましょう。 そして、ラズパイ側のコードに入っているsleepをいろいろかえても、たとえ0にしても、エラーなく受信できるかを確認してみよう
nosuke_ko

2019/12/14 04:23

RS485を使った通信はまだ実現できていませんが、Arduinoとラズパイに直接USBでつないでエラーなくスムーズなモーターの制御ができるようになりました。ありがとうございます。 次はRS485を用いて制御できるように検討してみます!
guest

0

head を受信した時点で high,low はまだ受信して無いのでは?

if (head == 128) { while(Serial.available() < 2); // high,low 2byte 受信待ち int high = Serial.read(); int low = Serial.read();

投稿2019/12/13 05:45

koujikuu

総合スコア401

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

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

nosuke_ko

2019/12/13 06:27

ご回答ありがとうございます。アドバイスいただきありがとうございます!!コードを編集しましたが、今までと挙動は変わりませんでした。 そもそもArduino側でSerial.readで値を取得できていないように感じました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問