Go Down

Topic: Python <-> Arduino - Serial communication questions (Read 3935 times) previous topic - next topic

dethpole

Hi all,
I am currently working on a robotic project and have been stuck on a certain communication problem for a while now and was wondering if anyone could provide some help on the matter.

Overview
I am using a Python script to execute a path planning algorithm. The path data is stored in a list (length in a straight line and rotation). All data is a real number, therefore is an integer. This data should be sent over serial connection - in this case a USB cable - from PC or RPi3 to an Arduino (Uno or Nano v3 running on ATMega328)

As of now I have the two communicating with each other to some degree. Python seems to be sending the data, however I am not sure if it's correct. When I try to read the data it comes back different from the Arduino.

Python code
Code: [Select]
from time import sleep
import serial
import struct
arduino = serial.Serial('COM3',9600)        # set the serial communication, comms port and the baud rate
sleep(.5)
if arduino.is_open == 1:                    # check if arduino port is open
    print("open")                           # print confirmation message

for i in range(0,len(mov_data)):            # send data to arduino
    d = struct.pack('<I',mov_data[i])       # pack integer data as little-edian bytes
    print("struct complete")
   
    arduino.write(d)                        # write data over serial
    print("sent data")
    print(d)
   
    a = arduino.read()                      # read the returning information 
    print("received data")
    print(a)
    sleep(.2)
arduino.close()

In my understanding, using the struct.pack should return the information as bytes. In this case using <I returns the information as four bytes and I can confirm this by printing d. However, I am not entirely sure if my Arduino code is interpreting the data correctly.

Arduino code
Code: [Select]
union {
  byte data_len[4];
  int data_len_int;
} read_data;


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

void loop() {
  if (Serial.available() < 4) {
    for (i = 0; i < 4; i++) {
      read_data.data_len[i] = (byte)Serial.read();
    }
  }
  Serial.write(read_data.data_len_int);
}

Above is the excerpt from my Arduino code. From my research multiple sources said to use union as it helps dealing with data flowing in, however I do not understand how it is accomplished. As I understand correctly, the if statement checks for number of bytes awaiting in the serial buffer and since I am sending 4 bytes from Python the condition for Serial.available is greater than 4. The for loop should collect each byte from the buffer and assign it to the data_len array. This should be then printed again where Python grabs it and outputs the returning value in the shell.

That is the point where my troubles really start as the data doesn't match. An example of the received output is as follows:
Code: [Select]
struct complete
b'\x0b\x00\x00\x00'
sent data
received data
b'\xff'
struct complete
b'\x03\x00\x00\x00'
sent data
received data
b'\xff'
struct complete
b'\x05\x00\x00\x00'
sent data
received data
b'\xff'

The line after "struct complete" is the result of struct.pack in Python. The line after received data is the data sent by Arduino. Seems that Arduino just sends the same thing over and over again, no matter what's the input from Python script.

I feel as if I am missing something really obvious at some stage. Would anyone be able to point me into the correct direction and provide some help?

Thanks in advance,
Lukas

PaulS

Code: [Select]
    arduino.write(d)                        # write data over serial
    print("sent data")
    print(d)
   
    a = arduino.read()                      # read the returning information 

How long between sending data and expecting a response? Is that REALLY reasonable?

Code: [Select]
union {
  byte data_len[4];
  int data_len_int;
} read_data;

How many bytes are in an int on the Arduino?

Code: [Select]
  if (Serial.available() < 4) {
    for (i = 0; i < 4; i++) {
      read_data.data_len[i] = (byte)Serial.read();
    }
  }

If there are less than 4 bytes to read, read all 4 of them. WTF?
The art of getting good answers lies in asking good questions.

dethpole

Are you suggesting I should implement a small delay here?

Gotcha, changed the type to long as it has 4 bytes on Arduino (since int has 2 bytes). The output has not changed however.

I have written code for reading serial data that way as that's the solution suggested by most resources I have found:
Example 1
Example 2
Example 3 - look post #5
Example 4 - union example with for loop for reading serial values

dethpole


PaulS

Nevermind, managed to solve to problem.
It would be nice to know how, just in case someone else has the same problem.
The art of getting good answers lies in asking good questions.

Go Up