I want to use pyserial module to read serial data sent by Arduino, the data update rate is about 250Hz, one data consists of 29 bytes and the baud rate is 230400.
When my code is running, I found that the pyserial input buffer does not automatically replenish data from arduino until about 0.5 seconds has passed. Is there any way to replenish the input buffer immediately after data received from Arduino?
Many thanks!
Adam Shiau
import serial
import time
ser = serial.Serial()
old = 0
while True
if ser.in_waiting > 29:
print('buf: ', ser.readInputBuffer())
new = time.perf_counter_ns()
print(ser.readBinaryList(29))
print(''%.1f\n %((new - old)*1e-3))
old = new
# updated function definition_07/23
def readBinaryList(mum):
data_r = ser.read(mum)
data_r = [i for i in data_r]
return data_r
def readInputBuffer(self):
return ser.in_waiting
result1
result2
ser.readInputBuffer() and ser.readBinaryList() look weird. I cannot find those functions in the docs. If I was writing this code, I would just use ser.read(29)
import serial
import time
ser = serial.Serial()
old = 0
while True
if ser.in_waiting > 29:
new = time.perf_counter_ns()
print(ser.read(29))
print(''%.1f\n %((new - old)*1e-3))
old = new
First time ever I am doing python coding with Pyserial and RS485.
My function for reading serial data is here:
#RS485 read function
from threading import Thread
from time import sleep
def v_read_left():
b = 0
packet = bytearray()
packet.append(0x01) #
packet.append(0x03)
packet.append(0x20)
packet.append(0xab)
packet.append(0x00)
packet.append(0x02)
a = crc_find(packet)
packet += a
ser.flush()
while True:
ser.write(bytes(packet)) # write request to motor driver
sleep(0.1) # for frequency control
b = ser.read(9) # read RS485 received
#print(b)
if len(b) > 0:
print(b)
thread = Thread(target = v_read_left, args = ( ))
thread.start()
thread.join()
and the output of this function is here:
b'\x00fj\x06\x01\x03\x04\x00c'
b'\x00a\xcb\xc5\x01\x03\x04\x00h'
b'\x00b\xfa\x06\x01\x03\x04\x00`'
b'\x00`\xfa\x05\x01\x03\x04\x00^'
b'\x00c\xdb\xc8\x01\x03\x04\x00l'
b'\x00e\xfa\x05\x01\x03\x04\x00b'
b'\x00_\x1b\xd5\x01\x03\x04\x00]'
b'\x00e\xab\xca\x01\x03\x04\x00o'
b'\x00m\x0b\xc3\x01\x03\x04\x00h'
b'\x00_;\xd7\x01\x03\x04\x00`'
I am not able to identify what the problem is?
This is the BLDC motor driver RS485 command reference, I am trying to read the speed of the motor via the given example in this image.
Image
I am writing a python script that will gather data from a serial port. I am able to gather the data and when it comes out it says b'1' I want to make an if statement for if it comes out as b'1' then I want it to run a function.
This is my code.
import serial
import time
z1baudrate = 115200
z1port = '/dev/ttyACM0'
z1serial = serial.Serial(port=z1port, baudrate=z1baudrate)
z1serial.timeout = 2
print (z1serial.is_open)
if z1serial.is_open:
while True:
size = z1serial.inWaiting()
if size:
data = z1serial.read(size)
print (data)
else:
print ("no data")
time.sleep(1)
else:
print("z1serial not open")
What should I do?
You can use "==" operator with bytes.
if z1serial.is_open == b'1':
...
should do the trick.
***Python code:***
import serial
import pandas as pd
import time
import re
import xlrd
from msvcrt import getch
import numpy as np
i = 0
x = 0
y = 0
df = pd.read_excel(r'C:\Users\lynchfamily\Desktop\mlglovesdata.xls')
# Read COM9
# Read from COM10 as well
# Readline() only works with a timeout (IMPORTANT)
serHC = serial.Serial('COM9', 115200,timeout=.250,parity=serial.PARITY_NONE,rtscts=1) # This is the JY
serRN = serial.Serial('COM10', 115200,timeout=.250,parity=serial.PARITY_NONE,rtscts=1) # This is the silvermate
def serialin():
# Sensor lists
sensor_names = list()
sensor_values = list()
global i
# Read a certain amount of bytes from serial and then continue
# Regular expressions for finding the proper data
while i < 6:
# print(i) for debugging
global serHC
global serRN
#searchObj = re.search(r'(A\d?\d*)?(\d*)?',serHC.read(4).decode(),re.I)
#searchObjRN = re.search(r'(A\d?\d*)?(\d*)?',serRN.read(4).decode(),re.I)
# Serial data stops while in loop
# The if statements keep the false values out of the program
#if searchObj.group(1):
sensor_names.append(serHC.read(2))
#if searchObj.group(2):
sensor_values.append(serHC.read(2))
#if searchObjRN.group(1):
sensor_names.append(serRN.read(2))
#if searchObjRN.group(2):
sensor_values.append(serRN.read(2))
i = i + 1
while 1:
# Get the key from the msvcrt module
key = getch().decode('ASCII')
# If key is pressed, do something
if key:
print(key)
# Zip them together
# Final 2D list
final_2d_list = zip(sensor_names,sensor_values)
print(list(sorted(final_2d_list)))
#vals = df.Dataframe([
#df.append(vals)
#print(sorted_array_1stdim[r])
#sensor_values = [0] * 10
# Thread for reading definition
break
# Fancy recursion
sensor_values.clear()
sensor_names.clear()
i = 0
serialin()
serialin()
Arduino Code:
// The device with green colored wires
void setup() {
Serial.begin(115200);
}
void loop() {
// It won't work with the I2C while loop for some reason. Perhaps it is getting stuck up on it
Serial.print("A4");
Serial.print(analogRead(0)); // Read the local analog signal
delay(5);
Serial.print("A5");
Serial.print(analogRead(1)); // Read the local analog signal
delay(5);
Serial.print("A6");
Serial.print(analogRead(2)); // Read the local analog signal
delay(5);
Serial.print("A7");
Serial.print(analogRead(3)); // Read the local analog signal
}
I'm trying to send analog data from sensors over through bluetooth silver mate from sparkfun, and HC-06 modules to python.
I have to read the analog data at a delay of 5 seconds between each, so that the readings aren't conflicted.
The data comes through serial ports COM9 and COM10. I know that serial in python can be blocking, that's why I attempted to read it first, and then put it in a list.
I also knows that once serial has been read through, it appears to be non-blocking. When I was using serHC.readline() and serRN.readline(), I was getting something like what I'd expect to see.
However, the data in the list were not updating according to the change in the sensors. I have to admit python is not my main programming language, so that is why I'm asking for help.
I thought maybe using multiple threads might work, but I wasn't able to get the serHC and serRN variables in the main thread.
Any help will be appreciated!!
As you have discovered it is not possible to read sequentially from serial ports: a blocking read over one port implies a loss of data simultaneous sent over the other port.
Use a thread based approach.
The following sketch should be enough to get started:
import serial
import time
import re
import threading
BYTES_TO_READ = 6
# read from serial port
def read_from_serial(board, port):
print("reading from {}: port {}".format(board, port))
payload = b''
ser = serial.Serial(port, 115200,timeout=.250, parity=serial.PARITY_NONE, rtscts=1)
bytes_count = 0
while bytes_count < BYTES_TO_READ:
read_bytes = ser.read(2)
# sum number of bytes returned (not 2), you have set the timeout on serial port
# see https://pythonhosted.org/pyserial/pyserial_api.html#serial.Serial.read
bytes_count = bytes_count + len(read_bytes)
payload = payload + read_bytes
# here you have the bytes, do your logic
# ...
print("READ from {}: [{}]".format(board, payload))
return
def main():
board = {
'JY': 'COM9',
'SILVER': 'COM10'
}
threads = []
for b in board:
t = threading.Thread(target=read_from_serial, args=(b, board[b],))
threads.append(t)
t.start()
# wait for all threads termination
for t in threads:
t.join()
main()
For learning about threading: https://pymotw.com/3/threading/
Periodic read from serials
Below a sketch for reading each TIME_PERIOD seconds.
A parte the infinite while loop around the read there is a "thread" loop with a nested try/catch block
for catching serials communication problems and retrying to connect after TIME_PERIOD.
Take it just as a starting example!
import serial
import time
import re
import threading
BYTES_TO_READ = 6
TIME_PERIOD = 5
def read_message(board, port, handle):
payload = b''
bytes_count = 0
while bytes_count < BYTES_TO_READ:
read_bytes = handle.read(2)
bytes_count = bytes_count + len(read_bytes)
payload = payload + read_bytes
# here you have the bytes, do your logic
# ...
print("READ from {}: [{}]".format(board, payload))
def serial_thread(board, port):
print("reading from {}: port {}".format(board, port))
while True:
try:
handle = serial.Serial(port, 115200,timeout=.250, parity=serial.PARITY_NONE, rtscts=1)
while True:
read_message(board, port, handle)
time.sleep(TIME_PERIOD)
except Exception as e:
print("ERROR: {}".format(e))
print("retrying in {} seconds".format(TIME_PERIOD))
handle.close()
time.sleep(TIME_PERIOD)
def main():
board = {
'JY': '/dev/ttyUSB0',
'SILVER': '/dev/ttyACM0'
}
threads = []
for b in board:
t = threading.Thread(target=serial_thread, args=(b, board[b],))
threads.append(t)
t.start()
# wait for all threads termination
for t in threads:
t.join()
main()
I'm trying to test a serial connection, prior to hooking up the external device that will actually source the data. I'm trying to use pySerial's "loop://" device, but I'm not receiving data correctly. I've started with a very toy program, just be sure I understood how/if it would work. Clearly I don't. :)
Here is my data "Source"
def serialDataPump():
ser = serial.serial_for_url('loop://', timeout=1)
testCtr = 0;
while not bbq.closing and testCtr<10:
ser.write(bytes("Test\n", encoding='ascii'))
time.sleep(1)
testCtr += 1
Here is my data "sink":
def serialDataTestRcv():
ser = serial.serial_for_url('loop://', timeout=1)
while not bbq.closing:
line = ser.readline()
sys.stdout.write('received' + str(line))
And here is my test Function - I use two threads:
def testSerMain():
thread1 = Thread(target = serialDataPump)
thread2 = Thread(target = serialDataTestRcv)
thread1.start()
thread2.start()
thread1.join()
bbq.closing = True
time.sleep(2)
exit()
And finally, here is the output - I am receiving the EOLs at a minimum, because readline() unblocks, and loops exactly 11 times, prior to terminating, which indicates that both the pump and the receive are looping and terminate properly. However, as you can see, it receives just empty data + the EOL:
>>>
receivedb''receivedb''receivedb''receivedb''receivedb''receivedb''receivedb''receivedb''receivedb''receivedb''receivedb''
>>>
Win 7, x64m py3.3
Incidentally, I know about com0com - I just can't run it on the machine I'm on.
I discovered the problem - you must use the same instance of ser = serial.serial_for_url('loop://', timeout=1) that you created for both receive and Xmt.