Clash of connection between serial port read and write codes - python

This is the code that reads from the z1 mote
while True:
if not ser.isOpen():
try:
ser = serial.Serial(z1port, z1baudrate,timeout=0, parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS)
except:
sys.exit("Error connecting device")
queue = ser.inWaiting()
if queue > 0:
data = ser.read(1000)
print data
time.sleep(0.2)
And this is the code that I have that I use it to write to the mote
# some event-driven code here so that whenever a message is received then do:
print(str(msg.payload))
ser = serial.Serial("/dev/ttyUSB1")
print ser.isOpen()
ser.write(msg.payload)
The output from the second code should be if msg.payload = "hello":
hello
True
But then the read code stops reading from the serial port (the code will run but no input). How do I solve this problem?

You can only create one serial connection to a device. The code in your question creates two connections, one in the main routine and one in the subroutine. In the main routine, you create a connection to establish communication with the device:
ser = serial.Serial(z1port, z1baudrate) # I assume z1port='/dev/ttyUSB1'
Then in your subroutine you also create a connection:
ser = serial.Serial("/dev/ttyUSB1")
So there are now two connections trying to use the same port. This will not work.
Instead, you should use the original connection throughout your program,
and define your subroutines to receive the connection as an input parameter. For example:
ser = serial.Serial(z1port, z1baudrate)
# do whatever to make connection to the device
getMessage(ser) # call subroutine to read data *with the existing connection*
ser.close() # close connection when finished
def getMessage(serConn):
# read data
data = serConn.read(1000)
# send ack
serConn.write(b'OK')
Another option is to open and close serial connections throughout your code, whenever you need to do communication. This is usually much less efficient, and only makes sense if there will only be intermittent communication with the device.

I used the idea by #mhopeng to write a code that implements multithreading programming, where one function handles the reading and the other handles the writing. And before they are both called, I will connect to the serial port and pass it to both of the threads.
I had to use multithreading because I needed a separate thread for writing at any time from the user input.

Related

Detecting python serial read timeout or serial interruption

I am making a program to talk to a piece of serial equipment. The code I have so far allows me to talk to the device just fine. However I would like to have the program do alert the user if the link does dead, along with triggering a different section of code. Ideally I would like the code to be able to detect a interruption in any part in the transmission.
I intend to have this code used with kivy with a user interface to indicate link status.
I have read about people using threading, and I have tried making timers with threading. But I think it all just gets messy.
Thank you for any input.
import serial
import time
# lineread is the variable to store the data read from comport
# b"\x80" is the format to read and write hex values this = 80 in hex
SerialConfig = serial.Serial(port='COM5', baudrate=9600, parity=serial.PARITY_EVEN, timeout=.1) # comport configurations
def Start_loop():
while True: # loop forever
lineread = SerialConfig.read() # lineread variable is = to serial configurations reading from com port
if lineread == b"\x80": # wait for device to start handshake
SerialConfig.write(b"\x80") # reply to device with handshake
del lineread # clear lineread variable to wait for next value to come in
while True: # keep looping till
lineread = SerialConfig.read() # lineread variable is = to serial configurations reading from com port
if lineread == b"\x80": # if comport sees reply respond with the following lines
SerialConfig.write(b"\xA0")
SerialConfig.write(b"\x90")
print("handshake complete")

Python socket won't timeout

I'm having an issue with Python's socket module that I haven't been able to find anywhere else.
I'm building a simple TCP chat client, and while it successfully connects to the server initially, the script hangs endlessly on sock.recv() despite the fact that I explicitly set a timeout length.
I've tried using different timeout values and including setblocking(False) but no matter what I do it keeps acting like the socket is in blocking mode.
Here are the relevant parts of my code:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
def listen_to_server():
global connected
while connected:
ready_to_read, ready_to_write, in_error = select.select([sock], [], [])
if ready_to_read:
try:
data = sock.recv(1024)
except socket.timeout:
print('TIMEOUT')
if not data:
append_to_log('Disconnected from server.\n')
connected = False
else:
append_to_log(str(data))
Any suggestions would be helpful, I'm at a total loss here.
You've mixed two things the socket timeout and the select.
When you set socket timeout then you are telling to that socket: if I try do some operation (e.g. recv()) and it won't be finished until my limit then raise timeout exception.
The select takes file descriptors (on Windows only sockets) and start checking if the rlist (the first parameter) contains any socket ready to read (aka some data have arrived). If any data arrived then the program continues.
Now your code do this:
Set timeout for socket operations
Select start waiting for data (if you don't send them then they never arrives)
and that's it. You stuck at the select.
You should just call the recv() without select. Than your timeout should be applied.
If you need manage multiple sockets at once than you have to use select and set the 4th parameter timeout.

Reset an open serial port

I am reading data from a serial port, sent by an arduino.
I have two files, which I use separately to write some code and try differents things. In one of them, I read the data and I draw it using a matplotlib figure. After I finish using it, it remains connected to my computer and sending data. So, what i need to do is to "reset" the port. This is, close the opened port and open it again, and stop it from sending data so I can use the arduino to try some modifications in the code of this file.
So to accomplish this, i mean, to reset the port, i created another file and wrote this code:
import serial
print "Opening port"
try:
serial_port = serial.Serial("com4", 9600)
print "Port is open"
except serial.SerialException:
serial.Serial("com4", 9600).close()
print "Port is closed"
serial_port = serial.Serial("com4",9600)
print "Port is open again"
print "Ready to use"
But this code does not seems to work.The port is still connected and sending data. So, it means that I can not close the port with my code,and then reopen it again.
What am i doing wrong? How can I stop the arduino from sending data? Or how can I reset thw arduino, maybe?
Hope you can help me.
----- EDIT -----
I accomplish to identify the real problem that i am having, and it is not what i thought. The problem was not that the port was open despite that i use the closefunction that Pyserial have. The real thing is that the port is closing as I want, but the device (the arduino) is still sending data. So, i changed the code to reproduce the situation.
This is the code:
print "Abriendo puerto"
ser = serial
try:
ser = serial.Serial("com4", 9600, timeout = 1)
serial_port = "Open"
print "The port %s is available" %ser
except serial.serialutil.SerialException:
print "The port is at use"
ser.close()
ser.open()
while ser.read():
print "Sending data"
ser.setBreak(True)
time.sleep(0.2)
ser.sendBreak(duration = 0.02)
time.sleep(0.2)
ser.close()
time.sleep(0.2)
print "The port is closed"
exit()
With this code, what i do is:
1) I open the serial port
2) If the device is sending data, I print "Sending data"
3) After 1 sec, I try to close the port and stop the device from sending data
I tried these last two thing with the close function to close the port, and reading the docs I tried with setBreak and sendBreak as you can see in the code above (i left them on purpose). But the device is still sending the data, which means that the code does not work.
So, is there a way to tell the arduino "stop sending data", or can i reset the device?
I do a very similar thing, two ways with success.
The first way is to let the Arduino send data continuously. The problem here is when your python code wakes up and starts to read from the serial port, the Arduino might be anywhere in its procedures. The simple solution is to modify the Arduino code to send some kind of "restarting" line. All your python code needs to do in this case is wait for "restart", then read real data until it again sees "restart". I had noisy lines so my code read (and parsed) through multiple cycles to make sure it got good data.
resetCount = 0;
while resetCount < 3:
line = s.readline().rstrip("\r\n")
if string.find(line, "restart") != -1 :
resetCount += 1
elif resetCount > 0 :
fields = string.split(line, " ")
dict[fields[0]] = fields
The second way is to implement a command-response protocol with the Arduino, wherein the Arduino sends data only when requested. In this case your python code sends a command to the Arduino ("RT" in the example below) and then reads data from the Arduino until it sees a "completed" line or it times out.
dict = {}
regex = re.compile('28-[0-9A-Fa-f]{12}') # 28-000005eaa80e
s = serial.Serial('/dev/ttyS0', 9600, timeout=5)
s.write("RT\n");
while True:
line = s.readline().rstrip("\r\n")
print line
if string.find(line, "completed") != -1:
break;
fields = string.split(line)
if (regex.match(fields[0]) != None and len(fields) == 4) :
dict[fields[0]] = fields
s.close()
It is possible that when you close the port, data is still coming from the arduino and being buffered by the operating system. There is a short delay between your script calling close() and the device driver actually shutting stuff down.
An immediate re-open may allow the driver to carry on without resetting its buffer. This is the device driver buffer, not the one seen by the Python serial port instance.
If you wait for at least a couple of seconds after the call to close() before you try to call open() then the behaviour should be as you hope.
I have just spent most of the day working out that this is what had been preventing my code from working properly.
I think you have to do a serial_port.open() immediately after creation to actually open the port.
It also looks like it just opens the port and exits if successful. Maybe I'm missing something here. I've never used pySerial, I'm just going by the docs.
Try using the handle to close the port instead of invoking the constructor again.
If you the port is open and you call serial.Serial("com4", 9600) it will attempt to re-open the port again and fail.
If serial_port was assigned successfully then serial_port.close() should close it.

Getting constant updates from serial to output to TexCtrl

I have a gui that I've written in wxPython, this is working as a software controller going to a PID type thermal controller.
I need to get constant readings from the thermal controller to consistently output the current temperature of the device.
Let's say I have this function in another file:
def temp_read():
#this function will query a controller, then read the value
I import that function, and set it to the value of a TextCtrl widget:
out_current = wx.TextCtrl(self, pos=(250,8), size=(110,23), style=TE_READONLY)
out_temp = temp_read()#get value from function
out_current.SetValue(out_temp)#set value to widget
How do I set this up so that it constantly outputs, while leaving the gui functional to allow for the rest of control parameters(setting temperature and other items) to be set by the user?
You do not specify how you get the serial data. I suppose however you will use pyserial. The principal problem in reading the serial is that reading it will block until the next character arrives. And because it will immediately try to read the next byte (and block again) the GUI will never become idle.
So essentially you have to spin off the serial reading in a separate thread and communicate the result back thread-safely.
For the purpose of reading out an Arduino I have created a small running example (which also explains in more detail why threading is required). When deleting the line for DRS/DTR, it will apply to any serial device.
EDIT: And if you further look in the pyserial library and look at the wxPython example, it is using threading.
With regard to my comment:
This is from the pyserial manual:
>>> ser = serial.Serial('/dev/ttyS1', 19200, timeout=1)
>>> x = ser.read() # read one byte
>>> s = ser.read(10) # read up to ten bytes (timeout)
>>> line = ser.readline() # read a '\n' terminated line
>>> ser.close()
>>> ser = serial.Serial(1, 38400, timeout=0,
... parity=serial.PARITY_EVEN, rtscts=1)
>>> s = ser.read(100) # read up to one hundred bytes
... # or as much is in the buffer
If you find that you have to take the Thread route see the accepted answer written by Fredrik Haard here PySerial non-blocking read loop
His quick example is as follows:
import threading
connected = False
port = 'COM4'
baud = 9600
serial_port = serial.Serial(port, baud, timeout=0)
def handle_data(data):
print(data)
def read_from_port(ser):
while not connected:
#serin = ser.read()
connected = True
while True:
print("test")
reading = ser.readline().decode()
handle_data(reading)
thread = threading.Thread(target=read_from_port, args=(serial_port,))
thread.start()

Send data to Arduino on keypress Raspberry Pi

I'm trying to build a car (Wild Thumper) that i can drive from my Raspberry Pi. Currently i'm using my Raspberry Pi over SSH. It should send to data to my Arduino so it knows when it has to go forward or when to turn.
I've tried making scripts that get called by jQuery (apache on Pi) and send an integer over the serial port but it requires a delay and this is not ideal. (example forwardStart.py:)
import serial
ser = serial.Serial('/dev/ttyACM0', 9600)
ser.open()
# here a delay is needed
ser.write('4') # go forward
ser.close()
To solve this i tried looking for a single python script that read my keyboard and send the correct integer. However, all keylisteners require display and can't be used over SSH.
Can anybody help me with the Python script or another idea that would works?
Thanks!
You should start reading from here. The idea would be something like
import serial
ser = serial.Serial('/dev/ttyACM0', 9600)
ser.open()
# here a delay is needed
try:
while 1:
try:
key = sys.stdin.read(1) # wait user input
actionKey = key2action(key) # translate key to action
ser.write(actionKey) # go forward
except IOError: pass
finally:
ser.close()
Note: this code will fail, it's more like pseudo-code to illustrate the idea.

Categories