我正在尝试在Arduino UNO板和Python程序之间建立两种通信方式。为交换的消息选择的格式为JSON。
由于Arduino UNO具有64字节的输入缓冲区,并且JSON消息远大于此,因此我实现了一种方法,可以使用Python将JSON数据分解为64字节消息,然后在Arduino代码上重新组装。
要标记一条消息的结尾,我使用字符串“
通过Arduino串行监视器输入数据时,Arduino代码工作正常。我用作输入的JSON如下。两行,通过串行监视器发送,一次发送一次。
{"sequence": 0, "state": 0, "commands": [{"device_id": "1", "val
ue": 1.0, "result": 0}], "statuses": [{"device_id": "1"}]}<e>
串行监视器的输出是这样的:
但是当我用Python代码运行相同的Arduino代码时,生成并发送回Python的JSON为空('{}')。
这是我的Arduino代码:
#include <ArduinoJson.h>
String inputMessage = "";
bool processingRequest = false;
void serialEventRun(void) {
if (Serial.available()) serialEvent();
}
void serialEvent() {
if (!processingRequest) {
String message = "";
char c;
while (Serial.available() > 0) {
c = Serial.read();
message.concat(c);
}
message.trim();
inputMessage += message;
if (inputMessage.endsWith("<e>")) {
processingRequest = true;
inputMessage = inputMessage.substring(0, inputMessage.indexOf("<e>"));
const size_t bufferSize = 2 * JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(2) + 6 * JSON_OBJECT_SIZE(3) + 240;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.parseObject(inputMessage);
const int sequence = root["sequence"];
const int state = root["state"];
JsonArray& commands = root["commands"];
JsonArray& statuses = root["statuses"];
// TODO include real command/status call
if (commands.size() > 0) {
for (int i = 0; i < commands.size(); i++) {
JsonObject& command = commands[i];
command["result"] = 1;
}
}
if (statuses.size() > 0) {
for (int i = 0; i < statuses.size(); i++) {
JsonObject& status = statuses[i];
status["value"] = 1.1;
status["health"] = 0;
}
}
root["state"] = 2;
root.printTo(Serial);
Serial.print("<e>");
processingRequest = false;
}
}
}
void setup() {
Serial.begin(115200);
}
void loop() {}
这是我的Python代码:
import time
from serial import Serial
def main():
result = ''
serial_conn = Serial(port='COM5', baudrate=115200, timeout=0.1)
time.sleep(1)
serial_conn.write(str.encode('{"sequence": 0, "state": 0, "commands": [{"device_id": "1", "val'))
time.sleep(0.1)
serial_conn.write(str.encode('ue": 1.0, "result": 0}], "statuses": [{"device_id": "1"}]}<e>'))
time.sleep(0.1)
# serial_conn.flushInput()
while True:
# bytes_to_read = serial_conn.inWaiting()
# msg = serial_conn.read(bytes_to_read)
msg = serial_conn.readline()
time.sleep(0.1)
result += msg.decode()
print("<{}>".format(result))
if result.endswith('<e>'):
break
result = result.strip('<e>')
print("Message received: <{}>".format(result))
serial_conn.close()
if __name__ == '__main__':
main()
使用Python运行时,这是控制台输出:
<{}<e>>
Message received: <{}>
Process finished with exit code 0
试图弄清楚发生了什么,我将Arduino代码更改为仅将JSON序列化数据的长度打印到串行端口。在串行监视器上运行时,长度为135,与上面的屏幕快照相同。但是,使用Python运行时,其长度为5,与我们在Python的控制台输出中看到的“ {}
我已经想过,如果我不应该打印到串行端口(在Arduino代码中),也要像接收数据时那样尊重64字节的缓冲区。但是,由于JSON序列化数据的生成是空的,所以我不确定这是问题所在。
有什么想法吗?
谢谢!
答案 0 :(得分:0)
经过几次测试,我能够解决问题。
正如我上面的评论,Arduino返回空JSON的原因是来自Python的数据未正确发送。我的Python代码向Arduino发送了两个JSON字符串,但是只有第二个到达。
只有第二条消息,ArduinoJson无法解析JSON数据,从而生成了一个空的JsonObject,该JsonObject生成了一个空的JSON序列化数据(“ {}”)。
原因很明显,PySerial lib需要一些时间来打开串行端口并能够发送数据。对于这种情况,我发现不多,只有PySerial GitHub页面中报告了此issue。
最终,解决方案是在打开串行端口后包括2秒的延迟。
在寻求解决方案的过程中,我更改了很多Arduino代码。
Arduino代码的主要变化:
1-更改为不使用serialEvent()。
2-包含的JsonObject.success()检查。
3-如果JsonObject.success()失败,则返回特定错误。
#include <ArduinoJson.h>
String receivedMessage = "";
void processMessage(String message) {
const size_t bufferSize = 2 * JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(2) + 6 * JSON_OBJECT_SIZE(3) + 240;
DynamicJsonBuffer jsonBuffer(bufferSize);
//StaticJsonBuffer<bufferSize> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(message);
if (root.success()) {
const int sequence = root["sequence"];
const int state = root["state"];
JsonArray& commands = root["commands"];
JsonArray& statuses = root["statuses"];
// TODO include real command/status call
if (commands.size() > 0) {
for (int i = 0; i < commands.size(); i++) {
JsonObject& command = commands[i];
command["result"] = 1;
}
}
if (statuses.size() > 0) {
for (int i = 0; i < statuses.size(); i++) {
JsonObject& status = statuses[i];
status["value"] = 1.1;
status["health"] = 0;
}
}
root["state"] = 0;
root.printTo(Serial);
} else {
jsonBuffer.clear();
JsonObject& error = jsonBuffer.createObject();
error["state"] = 3;
error.printTo(Serial);
}
Serial.print("<e>");
}
void setup() {
Serial.begin(115200);
while (!Serial) {}
}
void loop() {
while (!Serial.available()) {}
receivedMessage = Serial.readString();
receivedMessage.trim();
receivedMessage.replace("\n", "");
if (receivedMessage.endsWith("<e>")) {
receivedMessage = receivedMessage.substring(0, receivedMessage.indexOf("<e>"));
processMessage(receivedMessage);
receivedMessage = "";
}
}
但是解决方案是将第11行中的延迟增加到2秒:
import time
from serial import Serial
def main():
result = ''
serial_conn = Serial(port='COM5', baudrate=115200, timeout=0.1)
time.sleep(2)
serial_conn.write(str.encode('{"sequence": 0, "state": 0, "commands": [{"device_id": "1", "val'))
serial_conn.write(str.encode('ue": 1.0, "result": 0}], "statuses": [{"device_id": "1"}]}<e>'))
# serial_conn.flushInput()
while True:
# bytes_to_read = serial_conn.inWaiting()
# msg = serial_conn.read(bytes_to_read)
msg = serial_conn.readline()
time.sleep(0.1)
result += msg.decode()
print("<{}>".format(result))
if result.endswith('<e>'):
break
result = result.strip('<e>')
print("Message received: <{}>".format(result))
serial_conn.close()
if __name__ == '__main__':
main()