Raspberry PI и Arduino Последовательная связь с Python - PullRequest
0 голосов
/ 31 декабря 2018

У меня проблемы с последовательным соединением между Raspberry Pi (Python Script) и Arduino nano / uno.Оба устройства подключены через USB-порт, и когда я посылаю команду напрямую с последовательного монитора IDE arduino, скриншот arduino всегда отвечает правильно:

<Arduino is ready>
<MSG:GDI,RESPONSE:EMD-1707-1993,Time:7>
<MSG:GDI,RESPONSE:EMD-1707-1993,Time:23>
<MSG:GDI,RESPONSE:EMD-1707-1993,Time:26>
<MSG:GDI,RESPONSE:EMD-1707-1993,Time:30>
<MSG:GDI,RESPONSE:EMD-1707-1993,Time:34>
<MSG:GDI,RESPONSE:EMD-1707-1993,Time:38>

Но, когда я запускаю скрипт python, и он посылает одну и ту же команду, набросок ответа случайным образом.

Терминал малины:

pi@raspberrypi:~/test/raspberry $ python test.py 
Sending GDI command to device...
<GDI>
Traceback (most recent call last):
  File "test.py", line 47, in <module>
    response = read_from_device(serial_connection)
  File "test.py", line 15, in read_from_device
    while ord(current_char) != MSG_START_CHAR: 
TypeError: ord() expected a character, but string of length 0 found

Серийный монитор Arduino:

<Arduino is ready>
MGIRSPi35

Код Mi:

Эскиз Arduino:

#include <EEPROM.h>

#define DEVICE_BAUD_RATE        9600

#define EEPROM_SIZE             1024

#define ID_PREFIX               "EMD-"

#define MSG_START_CHAR          '<'
#define MSG_END_CHAR            '>'

#define MSG_GET_DEVICE_ID       "GDI"

const byte buffSize = 40;
char inputBuffer[buffSize];
byte bytesRecvd = 0;
boolean readInProgress = false;
boolean newMsg = false;

char cmd[buffSize] = {0};
int pin = 0;
int value = 0;

unsigned long curMillis;

void setup() {
  if(getDeviceId() == "") {
    setDeviceId();
  }

  Serial.begin(DEVICE_BAUD_RATE);

  while(!Serial) {
    ;
  }

  Serial.println("<Arduino is ready>");
}

void loop() {
  curMillis = millis();
  readMsg();
  processCommand();
}

void readMsg() {
  if(Serial.available() > 0) {
    char x = Serial.read();

    if(x == MSG_END_CHAR) {
      readInProgress = false;
      newMsg = true;
      inputBuffer[bytesRecvd] = 0;
      strcpy(cmd, inputBuffer);
    }

    if(readInProgress) {
      inputBuffer[bytesRecvd] = x;
      bytesRecvd++;

      if(bytesRecvd == buffSize) {
        bytesRecvd = buffSize - 1;
      }
    }

    if(x == MSG_START_CHAR) { 
      bytesRecvd = 0; 
      readInProgress = true;
    }
  }
}

void processCommand() {
  if(strcmp(cmd, MSG_GET_DEVICE_ID) == 0) {
    sendMsg(getDeviceId());
  } else {
    sendMsg("Command Not Found");
  }
}

void sendMsg(String response) {
  if(newMsg) {
    newMsg = false;
    Serial.print("<MSG:");
    Serial.print(cmd);
    Serial.print(",RESPONSE:");
    Serial.print(response);
    Serial.print(",Time:");
    Serial.print(curMillis >> 9);
    Serial.println(">");
  }
}

String getDeviceId() {
  String id = "";

  for(int i=0; i<EEPROM_SIZE; i++) {
    int value = EEPROM.read(i);

    if(value == 0xFF) {
      return id;
    }

    id += char(value);
  }

  return id;
}

void setDeviceId() {
  randomSeed(analogRead(0));

  String id = ID_PREFIX + String(random(1000, 10000)) + "-" + String(random(1000, 10000));

  for(int i=0; i<EEPROM_SIZE; i++) {
    EEPROM.write(i, i<id.length() ? id.charAt(i) : 0xFF);
  }
}

Скрипт Python:

#!/usr/bin/python
import os
import serial

MSG_START_CHAR              = '<'
MSG_END_CHAR                = '>'

MSG_GET_DEVICE_ID           = 'GDI'


def read_from_device(serial_connection):  
    response = ""
    current_char = "z"

    while ord(current_char) != MSG_START_CHAR: 
        current_char = serial_connection.read()

    while ord(current_char) != MSG_START_CHAR:
        if ord(current_char) != MSG_START_CHAR:
            response = response + current_char 

        current_char = serial_connection.read()

    return(response)

def write_to_device(serial_connection, msg):
    cmd = MSG_START_CHAR + msg + MSG_END_CHAR

    print(cmd)

    serial_connection.write(cmd)

with serial.Serial('/dev/ttyACM0', 9600, timeout=10) as serial_connection:
    waiting_for_reply = False

    if waiting_for_reply == False:
        print('Sending {0} command to device...'.format(MSG_GET_DEVICE_ID))

        write_to_device(serial_connection, MSG_GET_DEVICE_ID)

        waiting_for_reply = True

    if waiting_for_reply == True:
        while serial_connection.inWaiting() == 0:
            pass

        response = read_from_device(serial_connection)

        print('Reply Received: {0}'.format(response))

        waiting_for_reply = False

    serial_connection.close()

1 Ответ

0 голосов
/ 31 декабря 2018

Проблема в том, что вы сравниваете int со строкой.В функции read_from_device эта строка:

    while ord(current_char) != MSG_START_CHAR: 
  • current_char - это строка.
  • ord(current_char) - это целое число (по сути, значение ASCIIсимвольная строка).
  • MSG_START_CHAR - это строка.

Таким образом, сравнение проводится между int и строкой.Это всегда будет False, поэтому цикл while никогда не завершится.В конце концов больше нет персонажей из Arduino, после чего вы будете выполнять ord() на пустой строке.Это недопустимо, поэтому вы получите трассировку в этот момент.

Вам не нужна функция ord вообще.В Python вы просто работаете напрямую со строками.

Попробуйте это:

def read_from_device(serial_connection):  
    while serial_connection.read() != MSG_START_CHAR:
        pass

    response = ""
    while True:
        current_char = serial_connection.read()
        if current_char == MSG_END_CHAR:
            break
        response = response + current_char 
    return response

Одна вещь, которую я не знаю здесь: Arduino отправляет однобайтовые символы.В Python3 (если это то, что вы используете) все символы в юникоде.Я не знаю, как библиотека Serial справится с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...