我对Arduino和Raspberry Pi之间的串行通信有疑问。事实上,我想用Arduino向Raspberry Pi发送2个变量,并以不同的方式使用它们。
这是我的Arduino草图:
int one = 1;
int two = 2;
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.print(one);
Serial.print(two);
delay(3000);
}
这是我的Raspberry的python脚本:
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(4)
while True:
data=ser.read()
print data
问题在于数据'在python代码中获取Arduino发送的两个值(因为在Arduino循环()中有两个打印)。但是我希望在Raspberry Pi中接收两个不同变量的数据(以便记录它们)。我尝试了许多技术以两种不同的方式接收这些数据,但它不起作用。
感谢您的帮助。
答案 0 :(得分:3)
Arduino的Serial.print
以ASCII格式发送数据。
所以来自Arduino的命令实际上发送了字符串12
。
Python没有办法确定第一个值的结束位置和第二个值的开始位置。
一种解决方案是使用Serial.println
代替Serial.print
。
这将在每次调用后添加回车符和换行符。
因此字符串将变为1\r\n2\r\n
。
在Python端,您可以使用split
方法。
IPython中的一个例子:
In [1]: recv = "1\r\n2\r\n"
In [2]: recv.split()
Out[2]: ['1', '2']
然后您可以轻松地将值转换为整数。
In [3]: [int(j) for j in recv.split()]
Out[3]: [1, 2]
注意:Python可能会收到不完整的消息!因此,您可能会在第一次阅读时收到字符串1
,并在第二次阅读时收到2
!因此,您可能需要考虑格式化数据,以便知道您已收到完整的消息。
执行此操作的一个选项是将数据格式化为JSON。在您的示例中,这将是{"one": 1, "two": 2}
。在这个简单的calse中,您可以检查是否收到了完整的消息,因为它以{
开头,以}
结尾。但您也可以使用Python的内置JSON解析器。
In [4]: data = {'one': 1, 'two': 2}
In [5]: import json
In [6]: json.dumps(data)
Out[6]: '{"two": 2, "one": 1}'
In [7]: recv2 = json.dumps(data)
In [8]: json.loads(recv2)
Out[8]: {'one': 1, 'two': 2}
使用JSON解析器有一个优势,因为当您尝试解析不完整的消息时会引发异常:
In [10]: recv2
Out[10]: '{"two": 2, "one": 1}'
In [11]: recv3 = '{"two": 2, "on'
In [12]: json.loads(recv3)
---------------------------------------------------------------------------
JSONDecodeError Traceback (most recent call last)
<ipython-input-12-c1774b41dafa> in <module>()
----> 1 json.loads(recv3)
/usr/local/lib/python3.5/json/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
317 parse_int is None and parse_float is None and
318 parse_constant is None and object_pairs_hook is None and not kw):
--> 319 return _default_decoder.decode(s)
320 if cls is None:
321 cls = JSONDecoder
/usr/local/lib/python3.5/json/decoder.py in decode(self, s, _w)
337
338 """
--> 339 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
340 end = _w(s, end).end()
341 if end != len(s):
/usr/local/lib/python3.5/json/decoder.py in raw_decode(self, s, idx)
353 """
354 try:
--> 355 obj, end = self.scan_once(s, idx)
356 except StopIteration as err:
357 raise JSONDecodeError("Expecting value", s, err.value) from None
JSONDecodeError: Unterminated string starting at: line 1 column 12 (char 11)
处理此问题的正确方法是继续从串行端口读取数据并将其附加到字符串,直到解析数据不会失败;
import serial
import json
import time
ser = serial.Serial('/dev/ttyACM0', 9600)
buffer = ''
while True:
buffer += ser.read()
try:
data = json.loads(buffer)
print(data)
buffer = ''
except json.JSONDecodeError:
time.sleep(1)
答案 1 :(得分:0)
RE,
首先,我想感谢你的回答并让我发现Json。 所以我尝试了你的最后一个python代码并修改我的Arduino代码:
int one=1;
int two=2;
int three = 3;
int four = 4;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("{\"one\":\"" + String(one) +
"\", \"two\":\"" + String(two) +
"\", \"three\":\"" + String(three) +
"\", \"four\":\"" + String(four) +
"\"}");
}
在Rasberry Py中,当我执行代码(没有一会儿)时,控制台什么都不返回。似乎数据发送juste一个字符。
再次感谢
答案 2 :(得分:0)
实际上,我在这些应用程序中还很陌生,但是我偶然发现了一种简单的方法。
当然,Roland的回答已经很好地完成了工作。这种解决方案基本上可以做到非常快。
在Arduino中编写以下两行之后;
Serial.print(one);
Serial.print(two);
只需以相同的方式去阅读Raspberry中的行;
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
ser.flush()
one = ser.readline().decode('utf-8').rstrip()
two = ser.readline().decode('utf-8').rstrip()
我认为这里的窍门是放置两个readline(),以随后读取Arduino打印的行。至少对我有用:)
嗯,我不是专家,只是一个初学者。
税率