pySerial program doesn't read serial correctly - python

I have a problem using pySerial, and I don´t know from where to start looking for.
I have a 64 bits Windows Seven OS, with Python 2.7.5 (32 bits), and pySerial and Arduino (Arduino working correctly) already installed.
My Arduino code is the following:
// the setup routine runs once when you press reset:
void setup() {
// initialize the serial in 19200 baud rate
Serial.begin(19200);
}
// the loop routine runs over and over again forever:
void loop() {
delay(1000); // wait for a second
Serial.print("hello");
}
(Arduino conected in COM8, when using Serial Monitor I can see it saluting)
And my PySerial code looks like this:
import serial
import time
arduino = serial.Serial("COM8", 19200)
time.sleep(2)
while True:
print arduino.readline()
When I start this script, the program runs, but I can´t see the serial output (I think the configuration in the Python script is OK because if something - e.g. the port - is wrong, it crashes).
I don´t know what to do to find a solution.
Can you help me?

You might try using println instead of print on the Arduino/C side, and/or set a timeout for the serial read on the Python side.
Since serial.readline() waits for a \n, and you never send one using print, the serial read will just wait for a timeout. (But it's a bit more complicated than this, and it's worth reading the docs on readline and EOL.)
If this doesn't work, at least switch readline to just read and print out each character you may (or may not) be reading, but don't make it more complicated by waiting for the \n that readline requires.
From the demo docs:
Be carefully when using readline(). Do specify a timeout when opening the serial port otherwise it could block forever if no newline character is received. Also note that readlines() only works with a timeout. readlines() depends on having a timeout and interprets that as EOF (end of file). It raises an exception if the port is not opened correctly.

Related

Pyserial cannot read data but minicom works fine

I'm writing something like an SMS gate on Ubuntu. The device is a Huawei E173 Modem.
I use pyserial to write/read to and from the device. Here is my code:
import serial
import time
port = '/dev/ttyUSB0'
ser = serial.Serial(port,
stopbits=serial.STOPBITS_ONE,
parity=serial.PARITY_NONE,
bytesize=serial.EIGHTBITS
)
ser.write(b'AT\r\n')
time.sleep(0.1)
print(ser.read(ser.in_waiting))
This code works. But sometimes when I reconnect the device, I find that it cannot read anything. (ser.in_waiting=0 and nothing changes even if I set n larger).
But I can still use minicom to work with that port.
My Question: Why doesn't pyserial work but minicom can? Is there any difference between them?
What I guess it's happening is that the delay you are using together with the timeout you set when you open the port is conspiring with the time it takes for the modem to process the command.
To avoid that try reading data repeatedly for a certain time with a loop:
...
ser.write(b'AT\r\n')
timeout=time.time()+3.0
while ser.inWaiting() or time.time()-timeout<0.0:
if ser.inWaiting()>0:
data+=ser.read(ser.inWaiting())
timeout=time.time()+3.0 print(data)
With minicom or any other terminal you are always listening on the port so you always get the answer no matter how long the modem takes to process the command. In your code you send the command, wait 100 ms and then listen on the port for a time period defined by the timeout setting. Since you are not defining a timeout you have the default wait forever but that behavior is overridden by the use of the bytes in the buffer as an argument. If you happen to check the buffer before data arrives in it (because the command took longer than the 100 ms you gave it) the timeout becomes zero.
Considering the previous paragraph, and assuming you know the number of bytes it might be better to define a finite timeout and read with a ser.read(n) with n the expected bytes.
In my case, (on the BeagleBone Black), the above answer helped me get some bytes but not all. I realized, due to some reasons, minicom was reading the port and (maybe) flushing it. So, PySerial got nothing to read.
I simply closed minicom terminal and everything is good now :)

Troubleshooting serial communication from Python to Arduino

I'm using software which has Python scripting capabilities. I want to use it to move a Clearpath servo and run internal software commands intermittently.
Using an Arduino, I can control the servo, but it starts going wrong once I start using serial communication. After reading through other post, I'm thinking the problems are arising because serial communication is 8bit and I'm wanting to send large int.
For example, a section of the Arduino code shows:
void loop(){
if(Serial.available()){
inByte = Serial.readStringUntil('\n');
ser = inByte.toInt();
X.move(ser);
while(!X.commandDone()||!X.readHLFB())
{ }
Serial.print (inByte);
delay(1000);
}
}
Before I started using serial communication, I'd utilize integers in X.move(ser) and get flawless results. Now that I'm using the serial port, I can tell there's something wrong with this code. Even though it seems to work using the Serial Monitor, the more I try it (especially using larger numbers) the more I realize its probably not doing what it did before I used serial.
Then add Python into the mix and it gets even worse.
To give you an idea of what I'm trying to do, here was an example of Python code:
ser = serial.Serial('COM3', 9600, timeout=1)
ser.close()
ser.open()
while True:
var = "1000"
ser.write(var.encode())
time.sleep(1)'
Using this code, the servo moves but it's not right at all.
How can I send large integers (for example, 50502) from Python to Arduino through serial without it getting mangled during serial communication?

Python serial write doesn't work FIRST run

I have 2 programs to test serial communication, an simple arduino program that echoes whatever is on the serial port and a python program that writes to the serial port and prints the reply.
I'm having an issue where whenever I upload the arduino program and try to run the python the first time after I uploaded, it would be stuck on print ser.readline() which I'm assuming means for some reason python is not writing to the serial port. I would have to quit the python program and run it again to get it to get a reply from arduino. The program would continue to work until I re-upload the arduino then once again python wouldn't work on first run. Also if I open and close the serial monitor before I run the python program it will work the first run. Does anyone know what is the issue? This is on Ubuntu.
arduino
String str;
void setup() {
// Turn the Serial Protocol ON
Serial.begin(115200);
}
void loop() {
if (Serial.available()) {
str = Serial.readStringUntil('\n'); // Read the serial input
Serial.println(str); // sends ascii code
}
}
Python
import serial
ser = serial.Serial('/dev/ttyACM1', 115200)
for i in range(0,4):
str = "test string\n"
ser.write(str)
print ser.readline()
The issue is likely related to many Arduinos resetting when a new serial connection is made.
The solution is to either add a delay (about 2 seconds works) to the python program between the serial connection being created and the first data being sent or modifying the hardware to prevent a reset on serial connect.
By default python Serial might be blocking by default try removing the timeout:
ser = serial.Serial('/dev/ttyACM1', 115200,timeout=0)
additionally have a peek at the serial.threaded in the docs
I added
time.sleep(1)
ser.setDTR(level=0)
time.sleep(1)
after opening the serial port and the issue was fixed.

pySerial reading data from AT commands

I'm having trouble reading the response from a RS232 OBD2 interface via pySerial.
The code successfully enters the data, as I can see from a direct parallel terminal screen, but fails to read and print the response, regardless of the response.
Right now the code is not capable of printing the response in neither versions of Python.
The code looks something like this :
from serial import * # I also tried using /from serial import Serial
import time
ser = Serial("/dev/rfcomm1", 38400, timeout=1)
#print ('Starting up, formatting responses')
#ser.write("ATZ\r"),
#ser.write("ATSP0\r"),
#ser.write("ATS1\r"),
#ser.write("ATL1\r"),
#ser.write("ATH1\r"),
#ser.write("ATF1\r")
#time.sleep(1)
#print ('We have lift-off !')
if ser.inWaiting() > 0:
ser.flushInput()
#ser.timeout = 1.
time.sleep(1)
#print (raw_data)
ser.write("AT RV\r") #The response should be something like 13.5V, but nothing
ser.timeout = 1.
msg = ser.read(size=1024)
print msg
ser.close()
I left only the AT RV command because while I'm working on it I sent the text formatting commands to ease the job. Right now when I send it it just gives me a blank line (although the terminal which is running on the same machine displays the desired output)
There are no errors in the code, and the commands go through and are responded to by the interface, and I can see that in another live term, but nothing appears when running the Python code.
What should I do ?
You should read after writing, not before.
# before writing anything, ensure there is nothing in the buffer
if ser.inWaiting() > 0:
ser.flushInput()
# set the timeout to something reasonable, e.g., 1 s
ser.timeout = 1.
# send the commands:
ser.write("ATZ\r")
# ...
# read the response, guess a length that is more than the message
msg = ser.read(1024)
print msg
# send more commands
# read more responses
# ...
The point here is that there is no way to know when the response has been received. This code waits for one second after each command sent, unless more than 1024 bytes arrive during that time. There are more clever algorithms, but let's try with this one, first.
If you want to do something more complicated with the serial line, have a look at the pexpect module.
Some thoughts debugging python serial problems
Serial communication problems are sometimes a bit sticky to solve. pySerial is a reliable library, but as different platforms have different types of serial API, there are a lot of details. Things have not become any easier by the removal of physical serial ports, as the USB converters bring an extra layer into the game. Bluetooth converters are even worse.
The best way to debug the physical layer is to have some monitor hardware with two serial ports tapped into the serial lines. This kind of sniffer helps to isolate the problem to either end of the connection. Unfortunately, such sniffers are very rarely at hand when needed.
The next best thing is to short the RD and TD (RXD, TXD) pins of the serial line. This way all data will be echoed. If the data is received as sent, the physical connection is good. One thing to take care is handshaking. If you do not know what you are doing, disable all flow control (xon/xoff, rts/cts, dtr/dsr. pySerial disables these all if otherwise instructed.
In the case of the question above the physical connection is ok, as another piece of software demonstrates that the data is sent and understood by the other device. (Seeing that something is sent does not prove anything, as that information does not go through the physical layer, but seeing something produced by another device is received proves that the physical connection is ok.)
Now we know the data comes into the operating system, but pySerial does not see it. Or then our code is still somehow bad (no, it shouldn't, but...)
Let us suspect own own code and try someone else's code. This can be run from command prompt:
python -m serial.tools.miniterm /dev/rfcomm1 38400
Now we have a terminal which can be used to manually send/receive data form the other party. If the behaviour can be repeated (sends ok, data is received into the system, but not shown on the terminal) with this, then the problem is probably not in our code.
The next step then is to try:
sudo python -m serial.tools.miniterm /dev/rfcomm1 38400
In principle access right problems lead to situations where we can receive but not send. But it does not harm to test this, because odd rights cause odd problems.
pySerialhas a handy function readline which should read one line at a time from the serial line. This is often what is wanted. However, in this specific case the lines seem to end with \r instead of \n. The same may be repeated elsewhere in code, so with special data special care is needed. (The simple "read with timeout" is safe but slow in this sense.) This is discussed in: pySerial 2.6: specify end-of-line in readline()
The same issue plagues all terminal programs. For the pySerial miniterm, see its documentation (command-line option --cr).
If there are timeouts, they can and should be made longer for debugging purposes. A one-second timeout may be changed into a ten-second timeout to make sure the other device has ample time to answer.
I had exactly the same problem, through Python 2 IDLE no results displayed on the IDLE screen, but the results were redirected to picocom active at the terminal. I needed to capture results because my goal is to read incoming SMSs.
The following code solved my problem, I do not know the reason yet, ongoing analysis.
import time
import serial
modem1 = serial.Serial("/dev/ttyUSB3",baudrate=115200,timeout=0,rtscts=0,xonxoff=0)
def sendat1(cmd):
if cmd == 'res' : modem1.write('Z'); return
if cmd == 'out' : modem1.write(chr(26)); return
modem1.write('AT+'+cmd+'\r')
time.sleep(3)
obu = str(modem1.inWaiting())
msg = modem1.read(32798)
print(obu+':\n'+msg)
return
try:
if modem1.inWaiting()>0: modem1.flushInput()
sendat1('res')
sendat1('CMGF=1')
sendat1('CMGL')
sendat1('out')
finally:
modem1.close()

Sending hex data over RS-232 between an Arduino and a Mac OS X system

I'm using Voice Recognition Module -- Arduino Compatible. It says there to use AccessPort, but since I'm on Mac OS X it won't work. I don't know of any other solution but to write my own in Python while I'm open to any other language that works.
I found some solutions over here about pySerial but as of now it doesn't seem to work.
import serial
import struct
def C(val):
return struct.pack('H', val)
ser = serial.Serial(port='/dev/tty.PL2303-00001004', baudrate=9600, timeout=1)
ser.nonblocking()
ser.write(C(0xaa11))
print ser.read().__repr__()
ser.close()
It opens, write two bytes and doesn't read anything. 0xaa11 is used to start recording. My device seems to be in waiting mode since the red LEDs flash rapidly. Even if I do 0xaa00, it doesn't do much either. I even tried to change the byte order to 0x00aa, 0x11aa and so on, but I never receive my 0xcc or 0xe0 error code.
In the documentation it says to send it as hex, so my guess is that accessport converts hex to a Short which use two bytes. 0xaa00 is a two bytes number. I even tried to change the baud rate to 38400 in case someone before me did set that to this speed.
I'd be happy to read anything from that serial port because as of now I can write, it does nothing and reads nothing...
As of now, I'll try to install AccessPort with crossover. If it still doesn't work, I'll have to find a Windows box. I could even write my own bridge with my Arduino board since the driver I'm using might be buggy.
In case it matters, I'm using a USB to Serial PL2303.
Edit
I plugged my output and input pin to test my USB-to-serial. I do read what I write so the driver is working fine.
I'll try to set it up directly with Arduino and test directly from there.
Sending 0xaa11 is different than sending 0xaa and then 0x11. The serial seems to reverse the byte order.
On the other hand, the documentation doesn't tell about bit endianess, so it might be the problem too.
I kind of solved my problem while it was pretty dumb after all.
Here is my final script:
import serial
import struct
from time import sleep
def C(val):
return struct.pack('!H', val)
ser = serial.Serial(port='/dev/tty.PL2303-00002006', baudrate=9600)
sleep(2)
ser.write(C(0xaa00))
sleep(1)
ser.write(C(0xaa36))
sleep(1)
ser.write(C(0xaa11))
sleep(1)
while True:
print ser.readline()
If someone ever want to use that module, it works. It will switch to a mode where it puts to output words instead of bytes so you can read it using readline...
I used in struct.pack "!H" to use network endianess it change 0xaa00 to 0xaa 0x00 like it should be.
But the real problem here wasn't in the script. Since the usb to serial did work I thought that it was strange that the module didn't respond anything... not even a byte for errors. Every command in this module must return something. That's why I looked back at my cable and checked the pins... gnd to gnd, power supply to power supply and then rxd to txd, txd to rxd... While everything seems ok... I should receive something... And then I really thought... what if it's not supposed to use a cross cable and txd should be plugged to txd and rxd to rxd... Apparently it does.
I switch the cable and now data is sent and received.
So anyone using that module should check that it's correctly plugged in. If it doesn't work, switch the data pins.

Categories

Resources