Связь между Arduino и python: последовательный порт отправляет пустые данные

Код Arduino:

Этот код обеспечивает связь между датчиком gy-521 и Arduino. Читаю данные по команде "1", после 1000 выборок ардуино ждет новой команды для чтения данных.

Код Arduino хорошо работает в порту Arduino.

#include<Wire.h>
const int MPU=0x68; 
int16_t AcX,AcY,AcZ;
unsigned long time;
bool allow = false;
//целый доход = 0;

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B); 
  Wire.write(0);    
  Wire.endTransmission(true);
  Serial.begin(19200);
  while (!Serial);// ждем подключения последовательного порта. Требуется только для родного порта USB
}

void loop(){
  if (allow){ //если allow == true, прочитать данные

    for (int i = 0; i < 1000; i++){
      Wire.beginTransmission(MPU);
      Wire.write(0x3B);  
      Wire.endTransmission(false);
      Wire.requestFrom(MPU,12,true);  
      AcX=Wire.read()<<8|Wire.read();    
      AcY=Wire.read()<<8|Wire.read();  
      AcZ=Wire.read()<<8|Wire.read();

      time = millis();
      Serial.print(time);Serial.print(",");Serial.print(AcX);Serial.print(",");Serial.print(AcY);Serial.print(",");Serial.println(AcZ); 
      delay(0);
    }
    Serial.println(0); //см. UPD.3
    allow = false;
  } 
}

void serialEvent() {
  while (Serial.available()){ // ждем команды
    int incom = Serial.read() - '0'; 
    Serial.println(incom);
    if (incom == 0){ //если 0 - стоп
      allow = false;
      delay(100);
    }
    if (incom == 1){ //если 1 - читать данные
      allow = true;
      delay(100);
    }
  }
}

Код Python:

    def sensors(self):

        self.arduino_port_sensor.reset_input_buffer() #clear buffer

        self.arduino_port_sensor.write(str(1).encode()) #send command to arduino - read data

        main_array = []

        pbar = tqdm(total=self.time_observation) #just to see the progress

        while True:

            values = self.arduino_port_sensor.readline().decode().rstrip().replace(" ", "") #read data, some manipulation for cleaning
            main_array.append(values)

            pbar.update(1)

            if values == '': #if data is empty
                print('!!!!')
                continue
            if values == '0': #see UPD.3
                break

        pbar.close()
        ...bla bla...

Я вызываю эту функцию время от времени, затем на каком-то этапе arduino прекращает отправку данных — она отправляет пустую строку.

Выглядит так:

ПС. В этом коде я использую 2 порта: для датчика и для двигателя, 2 разных ардуино. Принцип работы второй ардуино с мотором такой же, но работает без проблем (я просто посылаю команду с "действием" на ардуино с мотором, а потом получаю ответ "получил обратно")

Вопрос: что не так с питоном? как исправить эту проблему?


UPD

Инициализация:

arduino_port_sensor = serial.Serial('/dev/tty.usbmodem143101', 19200, timeout = 1)

УПД.2

Поступает команда - "1" - чтение данных, при чтении данных происходит прерывание:

УПД.3

Также я изменил код Arduino - добавил "0" после цикла.

УПД.4

Если я вспомню эту функцию после того, как arduno перестал отправлять данные, я получу следующее:

, 👍0

Обсуждение

Как вы инициализировали PySerial? Ваш код Python этого не показывает., @Fahad

Проблемы могут быть разные: 1. Вы уверены, что Arduino что-то отправляет? Например, когда вы говорите, что перестали получать гата, проверьте, мигает ли светодиод TX на плате Arduino. 2. Получил ли Arduino «1» до того, как вы перестали получать данные? 3. Каков тайм-аут PySerial? Вы пытаетесь читать быстрее, чем может обеспечить Arduino?, @Fahad

0) Добавил инициализацию 1) да, потому что работает несколько итераций (самая долгая работа около 39 итераций). Моя программа не будет работать, если Arduino не отправляет данные. 2) да, я проверил это. Перед получением данных у меня всегда есть «1» в начале. 3) тайм-аут = 1, кстати, как это может работать на некоторых итерациях и не работать после?, @anna

1) Что я на самом деле имел в виду, КОГДА он перестал работать, это может быть либо ваш Python, либо Arduino. Он работал в течение 39 итераций. Таким образом, Arduino отправлял данные в течение этих 39 итераций. Но когда он перестал работать, это из-за того, что Arduino больше не отправляет или «по какой-то причине» Python не может его прочитать. Один из способов проверить это — проверить светодиод Tx на плате Arduino, КОГДА ваша система перестала работать. Если светодиод все еще мигает, как это было, когда система работала, то мы точно знаем, что это Python, который нам нужно исправить., @Fahad

2) То же самое и для этого, вы получили «1» в Arduino прямо перед тем, как он перестал работать? Один из способов проверить это — когда он перестает работать, напечатайте файл main_array. Если в main_array нет «1», это означает, что ваш Arduino никогда не отправлял «1», то есть никогда не получал «1»., @Fahad

2) Я показывал это в UPD.2: ардуино получает команду - читать данные - но потом что-то происходит 1) ДА! Спасибо, я действительно не заметил этого. Вы правы - когда он работает (питон читает данные), светодиод Tx мигает. Но потом я вижу "!!!!" - пустая строка - светодиод Tx не мигает. Значит проблема в ардуино?, @anna


1 ответ


1

Ваша проблема может быть вызвана разными причинами. Но из обновления, которое вы добавили позже, мы можем, по крайней мере, сказать, что ваш Arduino иногда не получает символ «1». И когда это происходит, ваш Python застревает в бесконечном цикле, пытаясь прочитать что-то из последовательного порта.

Поскольку ваш Arduino отвечает «1», когда он получает «1», вы можете основывать свое приложение на этом, например, если Arduino не отвечает «1", продолжайте отправлять "1".

Я написал пример программы на основе вашего кода. Я удалил часть «Wire» в коде Arduino, так как у меня нет вашего датчика. Я призываю вас протестировать этот код Arduino, чтобы убедиться, что ваш датчик не блокирует ваш Arduino. Чтение проводов может быть заблокировано навсегда в зависимости от ИС, которую вы пытаетесь прочитать (и если у вас нет тайм-аута).

int16_t AcX,AcY,AcZ;
unsigned long time;
bool allow = false;

void setup()
{
  Serial.begin(19200);
}

void loop()
{
  if (allow) //если разрешить == true, прочитать данные
  {
    for(int i = 0; i < 10; i++)
    {
      AcX = 1;    
      AcY = 2;  
      AcZ = 3;

      time = millis();
      Serial.print(time); Serial.print(",");
      Serial.print(AcX);  Serial.print(",");
      Serial.print(AcY);  Serial.print(",");
      Serial.println(AcZ); 
    }
    Serial.println('0');
    allow = false;
  } 
}

void serialEvent() 
{
  while (Serial.available()) // ждем команды
  {
    int incom = Serial.read() - '0'; 
    Serial.println(incom);
    if (incom == 0)          //если 0 - стоп
    {
      allow = false;
      delay(100);
    }
    if (incom == 1)          //если 1 - читать данные
    {
      allow = true;
      delay(100);
    }
  }
}

В коде Python я проверил, получил ли я "1" от Arduino. Если нет, я продолжал пытаться.

import serial
import time


def sensors():
    # Clear receive buffer
    arduino_port_sensor.reset_input_buffer() 

    while True:
        # Send command to arduino to send data
        arduino_port_sensor.write('1'.encode())

        # As arduino send LF and CR at the end, let's strip those from the end
        response = arduino_port_sensor.readline().rstrip(b'\r\n ').decode()

        # Arduino should respond with the cmd that it received, 
        # if not, send cmd again
        if response == '1':
            # Arduino acknowledged
            break
        else:
            print('Did not receive 1. Retrying...')

    main_array = []

    while True:
        values = arduino_port_sensor.readline().rstrip(b'\r\n ').decode()

        if values == '':
            print('!!!!')
            # This should never happen, but if it does happen, try to read again
            continue
        elif values == '0':
            # print(main_array)
            # We are done receiveing packets
            break
        else:
            # We are still receiving packets
            main_array.append(values)


arduino_port_sensor = serial.Serial('COM50', 19200, timeout=3)

# Let PySerial get ready
time.sleep(3)

while True:
    sensors()
    time.sleep(1)
,