I'm trying to log Arduino data with Python script in Raspberry via USB serial. The preferred data rate is quite high, 2.3kHz. The payload is a consistent 16 bytes of information.
I would like to use raw serial communication. But I'm not sure how to synchronize the frames to avoid framing errors. There is a lots of information on the internet. Unfortunately I still can't find an answer on how to implement them in practice. I certainly wouldn't invent a wheel. Please advise me what to look for.
Paul_KD7HB:
Are you going to use a common clock signal between the two boards?
Paul
Maybe you're asking that because I used the term "syncronization"? No. It'll be UART.
I presume it could be done with start/stop bit termination, but not sure how shall I do it. Or even better additionally detecting the idle between frames?
Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.
The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication. The start and end markers provide the synchronisation.
You can send data in a compatible format with code like this (or the equivalent in any other programming language)
Robin2:
Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.
The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication. The start and end markers provide the synchronisation.
You can send data in a compatible format with code like this (or the equivalent in any other programming language)
Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker
Also have a look at this [Simple Python - Arduino demo](http://forum.arduino.cc/index.php?topic=598209.)
...R
Thank you for the reply. Very helpful walkthrough. Although it is good for character comms, IMO start/end markers will trigger false termination conditions in binary. Perhaps you meant something else?
nebulae:
IMO start/end markers will trigger false termination conditions in binary.
That's true. I did not know you are working with binary data.
First question is it essential to use binary data? Sending data as human readable text makes debugging much easier. I would only send binary data if the extra performance was essential.
Second question, have you the ability to make changes to the sending program so as to make the data (whether binary or text) easier to handle?
If you can change the sending program then there are at least two options. The simplest is to set aside two byte values (perhaps 254 and 255) as start and end markers. That will reduce the range of possible data values to 0 to 253 - a loss of resolution of less than 1%. If you can't do that then if you set aside three values as markers (say 253, 254 and 255) you can use 253 as a marker that says that the following byte is a data byte rather than a start-or end-marker. For example to send the data value 254 you would send 253 254 and the send the value 253 you would send 253 253
Robin2:
First question is it essential to use binary data? Sending data as human readable text makes debugging much easier. I would only send binary data if the extra performance was essential.
The objective is to basically use the Arduino as a DAQ. I would like to be able to send 16 byte (24 in the future) time critical measurement data from Arduino to Raspberry at a relatively high speed of 2.3 kHz (or at least 1 kHz) and store it in a HDF5 file.
Robin2:
Second question, have you the ability to make changes to the sending program so as to make the data (whether binary or text) easier to handle?
Yes. It is an Arduino code.
Robin2:
If you can change the sending program then there are at least two options. The simplest is to set aside two byte values (perhaps 254 and 255) as start and end markers. That will reduce the range of possible data values to 0 to 253 - a loss of resolution of less than 1%. If you can't do that then if you set aside three values as markers (say 253, 254 and 255) you can use 253 as a marker that says that the following byte is a data byte rather than a start-or end-marker. For example to send the data value 254 you would send 253 254 and the send the value 253 you would send 253 253
Hrmm. It sounds like a very extraordinary solution. Similar to the one in your post "Demo of PC-Arduino comms using Python".
nebulae: Similar to the one in your post "Demo of PC-Arduino comms using Python".
That's hardly surprising - I had hoped it was identical, but maybe I overlooked some detail.
I would like to be able to send 16 byte (24 in the future) time critical measurement data from Arduino to Raspberry at a relatively high speed of 2.3 kHz (or at least 1 kHz)
That seems to mean that you want to send 24 x 2300 = 55200 bytes per second. Sending at 500,000 baud would fall a little short of that but at 1,000,000 baud there would be plenty of opportunity to include additional sync bytes.
If this was my project I would use either of the schemes that I suggested in Reply #5 to enable start- and end-markers to be added to the data.
It might also be a good idea to send some form of ID with each message so that the receiving program could identify if a message was missed. A single byte that increments from (say) 0 to 9 and then repeats would probably be sufficient.
You can interface Python and Arduinos with binary data easily using the compatible libraries: pySerialTransfer and SerialTransfer.h.
pySerialTransfer is pip-installable and cross-platform compatible. SerialTransfer.h runs on the Arduino platform and can be installed through the Arduino IDE's Libraries Manager.
Both of these libraries have highly efficient and robust packetizing/parsing algorithms with easy to use APIs.
Example Python Script:
from time import sleep
from pySerialTransfer import pySerialTransfer as txfer
if __name__ == '__main__':
try:
link = txfer.SerialTransfer('COM13')
link.open()
sleep(2) # allow some time for the Arduino to completely reset
link.txBuff[0] = 'h'
link.txBuff[1] = 'i'
link.txBuff[2] = '\n'
link.send(3)
while not link.available():
if link.status < 0:
print('ERROR: {}'.format(link.status))
print('Response received:')
response = ''
for index in range(link.bytesRead):
response += chr(link.rxBuff[index])
print(response)
link.close()
except KeyboardInterrupt:
link.close()
Power_Broker:
You can interface Python and Arduinos with binary data easily using the compatible libraries: pySerialTransfer and SerialTransfer.h.
pySerialTransfer is pip-installable and cross-platform compatible. SerialTransfer.h runs on the Arduino platform and can be installed through the Arduino IDE's Libraries Manager.
Both of these libraries have highly efficient and robust packetizing/parsing algorithms with easy to use APIs.
I went through your posts. It looks exactly what I need, all in one package.
Before it takes me understand how Python library works, I would like to ask for your help how to receive the data send from Arduino. I have my simple Arduino sketch to emulate the data source:
nebulae:
Before it takes me understand how Python library works, I would like to ask for your help how to receive the data send from Arduino. I have my simple Arduino sketch to emulate the data source:
I'd be glad to help. Do you have a specific question?
nebulae:
Maybe you're asking that because I used the term "syncronization"? No. It'll be UART.
I presume it could be done with start/stop bit termination, but not sure how shall I do it. Or even better additionally detecting the idle between frames?
I am confuser! Not the first or last time.
The standard for asynchronous data is for the BITS, 10 bits per 8 bits of data, to be SYNCHROUNOUS based on the bit rate, AKA Baud rate. The actual 10 bits are asynchronous because there is NO timing associated with them. Each set of 10 bits, start bit, 8 bits of data, stop bit, may have many seconds between each, or may have no delay time between them.
Are you attempting to only send 8 bits of data with nothing to indicate the starting of each set of bits? The old synchronous data transmissions were sent that way, with a set of known sync characters used to adjust the bit clock to match the incoming bits. In that case, no start bits or stop bits are necessary.
Power_Broker:
I'd be glad to help. Do you have a specific question?
Thanks! A Python example to receive the data from Arduino would be great. I'm sending a 16 byte frame for testing.
Paul_KD7HB:
I am confuser! Not the first or last time.
The standard for asynchronous data is for the BITS, 10 bits per 8 bits of data, to be SYNCHROUNOUS based on the bit rate, AKA Baud rate. The actual 10 bits are asynchronous because there is NO timing associated with them. Each set of 10 bits, start bit, 8 bits of data, stop bit, may have many seconds between each, or may have no delay time between them.
Are you attempting to only send 8 bits of data with nothing to indicate the starting of each set of bits? The old synchronous data transmissions were sent that way, with a set of known sync characters used to adjust the bit clock to match the incoming bits. In that case, no start bits or stop bits are necessary.
Paul
I probe Arduino's TX line with a logic analyzer and it shows me exactly 16 bytes of data when I "Serial.write()" 16 byte data. I guess it is 10 bits for text comms maybe?
nebulae:
Thanks! A Python example to receive the data from Arduino would be great. I'm sending a 16 byte frame for testing.
I probe Arduino's TX line with a logic analyzer and it shows me exactly 16 bytes of data when I "Serial.write()" 16 byte data. I guess it is 10 bits for text comms maybe?
I bet your logic analyzer was told to look for async data and realized it needed to sync it's logic on a start bit and end with a stop bit, so just showed the actual data. Look at the same TX line with an oscilloscope.
Power_Broker:
The built-in example already shows how to do this, but for a more tailored (and fully tested) example, see below:
Many thanks for the tailored example! It works amazingly well. I wish it was the weekend. I could fully discover its potential:
Paul_KD7HB:
I bet your logic analyzer was told to look for async data and realized it needed to sync it's logic on a start bit and end with a stop bit, so just showed the actual data. Look at the same TX line with an oscilloscope.