0

Arduino code:

this code is provided communication between sensor gy-521 and arduino. I read data by the command "1", after 1000 samples arduino is waited for new command for read data.

Arduino code works well in arduino port.

#include<Wire.h>
const int MPU=0x68; 
int16_t AcX,AcY,AcZ;
unsigned long time;
bool allow = false;
//int incom = 0;

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B); 
  Wire.write(0);    
  Wire.endTransmission(true);
  Serial.begin(19200);
  while (!Serial);// wait for serial port to connect. Needed for native USB port only
}

void loop(){
  if (allow){ //if allow == true, read data

    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); //see UPD.3
    allow = false;
  } 
}

void serialEvent() {
  while (Serial.available()){ //wait for command
    int incom = Serial.read() - '0'; 
    Serial.println(incom);
    if (incom == 0){ //if 0 - stop 
      allow = false;
      delay(100);
    }
    if (incom == 1){ //if 1 - read data
      allow = true;
      delay(100);
    }
  }
}

Python code:

    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...

I call this function time to time, then in some step, arduino stops sending data -- it sends empty string.

It looks like:

PS. In this code I use 2 ports: for sensor and for motor, 2 different arduino. The principe of working second arduino with motor the same, but it works without any problem (I just send command with "action" to arduino with motor, and then receive answer "received back")

enter image description here

Question: what's wrong with python? how to fix this problem?


UPD

Initialization:

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

UPD.2

It receive command - "1" - read data, the interruption occurs while reading data:

enter image description here

UPD.3

Also i changed the code of arduino -- added the "0" after loop.

UPD.4

If I recall this function after arduno stopped sending data, I get this:

enter image description here

6
  • How did you initialize the PySerial? Your python code doesn't show that.
    – Fahad
    Jan 30, 2020 at 19:11
  • There can be different issues: 1. Are you sure Arduino is sending something? For example, when you say you stopped getting gata, check if the TX LED on the Arduino board is blinking or not. 2. Did Arduino actually receive "1" before you stopped getting data? 3. What's the timeout of the PySerial? Are you trying to read faster than Arduino can provide?
    – Fahad
    Jan 30, 2020 at 19:34
  • 0) I added initialization 1) yes, because it works some iterations (the most long work about 39 iterations). My program wont work if arduino not sending data. 2) yes, I checked this. Before getting data I always have "1" in the beggining. 3) timeout = 1, btw how it can work in some iterations and not working after?
    – anna
    Jan 30, 2020 at 20:22
  • 1) What I actually meant, WHEN it stopped working, it can be either your Python or the Arduino. It worked for 39 iterations. So Arduino was sending data during those 39 iterations. But when it stopped working, is it because of Arduino is not sending anymore or 'for some reason' Python is not able to read it. One way to verify is, check the Tx LED on the Arduino board WHEN your system stopped working. If the LED still blinks as it was, when the system was working, then we know for sure its the Python we need to fix.
    – Fahad
    Jan 30, 2020 at 23:51
  • 2) Same for this too, did you receive '1' in the Arduino right before it stopped working? One way to check this is when it stops working print the main_array. If main_array doesn't have '1', that means your Arduino never sent '1' i.e. it never received '1'.
    – Fahad
    Jan 30, 2020 at 23:56

1 Answer 1

1

There can be different reasons for your issue. But from the update you added later, we can at least say that your Arduino sometimes doesn't receive the character "1". And when that happens, your Python gets stuck in the infinite loop of trying to read something from the serial port.

As your Arduino responds with "1" when it receives "1", you can base your application on that i.e. if Arduino doesn't respond with "1", keep sending "1".

I wrote a sample program based on your code. I removed the "Wire" part in the Arduino code as I don't have your sensor. I would urge you to test with this Arduino code to make sure that Your sensor is not blocking your Arduino. Wire read can be blocked forever depending on the IC you are trying to read (and if you don't have a timeout).

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

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

void loop()
{
  if (allow) //if allow == true, read data
  {
    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()) //wait for command
  {
    int incom = Serial.read() - '0'; 
    Serial.println(incom);
    if (incom == 0)          //if 0 - stop 
    {
      allow = false;
      delay(100);
    }
    if (incom == 1)          //if 1 - read data
    {
      allow = true;
      delay(100);
    }
  }
}

In the Python code, I checked if I received "1" from Arduino. If not I kept trying.

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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.