0

I am trying to transmit MPU6050 accelerometer data + data from 3 potentiometers from Arduino to Raspberry Pi. I do post processing here (on Raspberry Pi) and then transfer the data back to Arduino to move actuators. However my problem is that when I try to write the processed data back to Arduino, I see that even the stream of incoming data from Arduino starts getting corrupted and everything becomes really slow . Even If I just read serial data from Arduino, things are slower if than if I do the processing on Arduino directly. Also, the accelerometer data seems to become unresponsive i.e. its value doesn't change if I move the accelerometer. Everything just works fine if all the processing is done on Arduino. I don't know what is going wrong. Below are my Arduino and Python functions / codes.

Arduino Code:

void send_rec_data(){

    Serial.print(Kp);
    Serial.print(",");
    Serial.print(Kd);
    Serial.print(",");
    Serial.print(Ki);
    Serial.print(",");
    Serial.println(Theta_x);

    delay(20);    

  if (Serial.available()>0){ // Read data sent by Raspberry Pi / Piserial

    str_data = Serial.readString();    

    int firstCommaIndex = str_data.indexOf(',');

    cmd = str_data.substring(0, firstCommaIndex); // This stores the Scaled output from the Raspberry Pi

    param1 = str_data.substring(firstCommaIndex+1); // This stores the error from the Raspberry Pi to decide motor roattion direction

    Output = cmd.toFloat(); my_error = param1.toFloat(); // Change the outputs from string to float

    blink_led(); // Blink LEDS if data is received from Raspberry Pi



  }

}

Python Code:

while 1:

    data = cont.get_serial_data(arduino)

    time.sleep(0.02)

    if data is not None:

        Kp, Kd, Ki, Theta_x = data

        print(" \n Arduino sent Kp = ", Kp , "Kd = ",Kd , "Ki = ", Ki, "Theta_x = ", Theta_x)

        cont.set_tunings(Kp, Kd, 0)

        Output_scaled = cont.Compute_PID_Output(Input = Theta_x) # Compute the output of PID Algorithm

        ff = str(Output_scaled)+','+str(cont.error)

        arduino.write(ff.encode())

        print("\n Computed data sent TO ARDUINO Output_scaled = ", Output_scaled, "Error = ", cont.error)

arduino.close()

I have spent quiet sometime to resolve the issue byputting delays, flushing buffer but nothing has worked so far. Can someone please help.

Thanks.

  • You should start by seriously thinking about your required communication timings: How many bytes do you want to send in each direction? At what baud rate? How often? Then read Blink without delay, just to learn how to write non-blocking code, then Reading Serial on the Arduino. – Edgar Bonet May 24 '18 at 8:26
0

Ok, without rewriting all your code, one thing I'm seeing here is a lot of sloooow string functions.

Pythons print function is extremely slow, for example. You should insert some timers in your code and see how long everything's taking. I think you will be surprised.

For a real-time application, which it sounds like this is, you need to be very careful and use timeouts and non-blocking code to make sure that everything doesn't grind to a halt unexpectedly.

You really need to re-write all this code, but I'll point out a few specific problems.

delay(20); 
if (Serial.available()>0){
   ...
}

This is sloppy. If your python code does not process and return data before the 20ms elapses everything is going to go out of sync.

str_data = Serial.readString();

A look at the documentation reveals that this will only return on timeout, so this is guaranteed to block for 1s (I think that's the default), so there's another show-stopper problem. See this question for more info.

cmd = str_data.substring(0, firstCommaIndex);

This is also not sufficient. There is no synchronization between the pi and the arduino, so you have no guarantee that you won't get half of a previous transmission tacked onto the front of your data string (or worse). You need to make your own buffer and parse for the datastring. Or do some careful buffer clearing and use generous timeouts.

So TLDR; here's what you want to do (assuming you want to block while this exchange happens)

  1. Clear the arduino receive buffer.
  2. Send data packet from arduino.
  3. Start receiving. Add received bytes to a char buffer.
  4. Continuously search that buffer for your complete data packet.
  5. Timeout after x ms. Handle the lack of returned data somehow.
  6. If you do find the complete data packet, then process it.

On the Pi:

  1. Poll for serial data. Add it to a buffer as it comes in.
  2. Start deleting the oldest characters from the buffer if it's longer than 2x the longest data packet
  3. Continuously search the buffer for your data packet. If you find it then continue below.
  4. delete the data packet from the receive buffer.
  5. process the data.
  6. Send out return data packet to arduino.
0

Thank you every one. I read through this forum and it also says the same things which you guys also suggested. I did the same thing and now everything is fast.

Serial.readString()

is indeed the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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