簡體   English   中英

將數據結構從 python 發送到 arduino 的干凈方法?

[英]Clean way to send data struct from python to arduino?

我正在研究機器人,我想以某種方式使用 pySerial 向 arduino 發送命令。該命令看起來像 {MOVE, 60, 70} 或 {REQUEST_DATA},我會在其中讀取 arduino第一個值,如果它是“MOVE”,那么它會以 60 和 70 的速度驅動一些電機,如果它是“REQUEST_DATA”,它會響應一些數據,比如電池狀態、gps 位置等。

將其作為一串字符發送,然后進行解析真的是一個巨大的痛苦。 我已經嘗試了幾天(,挫折,)但它沒有正常工作,有沒有辦法序列化像{'MOVE'這樣的數據結構? 70. 40}? 將字節發送到 arduino 並在那里重建為一個結構。 (也許使用 struct.pack() ?但我還不知道如何在 arduino 中“解壓”)。

我查看了 arduino 上的串行通信,人們似乎只是以“令人沮喪”的方式進行通信——發送單個字符。 加上所有關於將結構從 arduino 發送到 python 的話題,而不是反過來。

有很多方法可以解決這個問題,最好的解決方案取決於您來回發送的數據。

最簡單的解決方案是用單個字節表示命令(例如, M表示MOVER表示REQUEST_DATA ),因為這樣您只需讀取 arduino 端的一個字節即可確定命令。 一旦你知道了這一點,你就應該知道你需要閱讀多少額外的數據才能獲得必要的參數。

例如,這是一個理解兩個命令的簡單程序:

  • 移動到給定 position 的命令
  • 打開或關閉內置 LED 的命令

代碼如下所示:

#define CMD_MOVE 'M'
#define CMD_LED 'L'

struct Position {
  int8_t xpos, ypos;
};

struct LEDState {
  byte state;
};

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);

  // We need this so our Python code knows when the arduino is
  // ready to receive data.
  Serial.println("READY");
}

void loop() {
  char cmd;
  size_t nb;

  if (Serial.available()) {
    cmd = Serial.read();
    switch (cmd) {
      case CMD_MOVE:
        struct Position pos;
        nb = Serial.readBytes((char *)&pos, sizeof(struct Position));
        Serial.print("Moving to position ");
        Serial.print(pos.xpos);
        Serial.print(",");
        Serial.println(pos.ypos);
        break;
      case CMD_LED:
        struct LEDState led;
        nb = Serial.readBytes((char *)&led, sizeof(struct LEDState));
        if (led.state) {
          digitalWrite(LED_BUILTIN, HIGH);
        } else {
          digitalWrite(LED_BUILTIN, LOW);
        }
        Serial.print("LED is ");
        Serial.println(led.state ? "on" : "off");

        break;
    }
  }
}

與上述交互的 Python 代碼片段可能如下所示(假設該port是一個serial.Serial對象):

print("waiting for arduino...")
line=b""
while not b"READY" in line:
    line = port.readline()

port.write(struct.pack('bbb', ord('M'), 10, -10))
res = port.readline()
print(res)

for i in range(10):
    port.write(struct.pack('bb', ord('L'), i%2))
    res = port.readline()
    print(res)
    time.sleep(0.5)

port.write(struct.pack('bbb', ord('M'), -10, 10))
res = port.readline()
print(res)

運行上面的 Python 代碼,在我的 Uno 上加載 Arduino 代碼,產生:

waiting for arduino...
b'Moving to position -10,10\r\n'
b'LED is off\r\n'
b'LED is on\r\n'
b'LED is off\r\n'
b'LED is on\r\n'
b'LED is off\r\n'
b'LED is on\r\n'
b'LED is off\r\n'
b'LED is on\r\n'
b'LED is off\r\n'
b'LED is on\r\n'
b'Moving to position 10,-10\r\n'

這實現起來很簡單,並且在 Arduino 端的解碼方式上不需要太多。

對於更復雜的情況,您可能需要研究更復雜的序列化解決方案:例如,您可以將 JSON 發送到 arduino 並使用類似https://arduinojson.org/的內容在 Arduino 端反序列化它,但這將是一個更復雜的解決方案。


在大多數情況下,它的工作速度將受到串行端口速度的限制:默認速度 9600bps 相對較慢,並且您會注意到數據量更大。 使用更高的串行端口速度將使事情明顯更快:我懶得查找最大值。 Arduino 支持的速度,但我的 UNO 至少可以達到 115200bps 的速度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM