Hello guys I am attempting to write ASCII commands & in return read the serial buffer & get serial data. I am having an issue parsing the serial data out to only read the serial data I want to see and use.
The Code:
import serial
# Serial Connection
ser = serial.Serial(
port="COM2", baudrate = 38400,
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS, timeout=1)
# Write ASCII Commands To TSI 4043 Flow Sensor
ser.write(b'?\r\n') # Ask Sensor if it is getting a signal (Returns "OK")
ser.write(b'SUS\r\n') # Set Flow type to SLPM (Returns "OK")
ser.write(b'SG0\r\n') # Set Flow Gas to Air (Returns "OK")
ser.write(b'SSR0010\r\n') # Set Sample Rate to 10ms (Returns "OK")
ser.write(b'DAFxx0010\r\n') # Read 10 sensor Flow Reading
# Read ASCII From Serial Buffer
output = ser.read(100) # Read 100 bytes from serial buffer
print(output)
OUTPUT:
b'OK\r\nOK\r\nOK\r\nOK\r\nOK\r\n80.63,80.42,80.52,80.32,80.33,80.66,79.88,80.39,80.26,80.28\r\n'
What I want to happen:
OK
OK
OK
OK
80.63,80.42,80.52,80.32,80.33,80.66,79.88,80.39,80.26,80.28
The OKs are just for debugging purposes. What I really need is to put all of the flow readings into an array so I can average it so I can watch the change in real time and control a motor.
You should change Your approach a bit.
Read from serial port after every ser.write and parse / process it's output.
Check if You actually receive b'OK\r\n' response from the device and make sure You comply with Device communication protocol (what are possible outputs for every command You send). You never know when Device throw an error while processing the command.
Like this You will already have communication in a way WRITE command => READ output for every command You send.
Then it comes to the part of flow readout. You should have just b'80.63,80.42,80.52,80.32,80.33,80.66,79.88,80.39,80.26,80.28\r\n' in Your output.
You can process it and get average with:
# Output value from DAFxx0010 command
output = b'80.63,80.42,80.52,80.32,80.33,80.66,79.88,80.39,80.26,80.28\r\n'
# Decode bytes to string, remove `\r\n`, split by ',' and convert values to float and save them into list
output_values = [float(val) for val in output.decode().strip().split(",")]
# Average all values
output_avg = sum(output_values) / len(output_values)
Now You have clean communication with Device and Your script can handle possible communication errors.
Related
I have an embedded development board connected to my Ubuntu host PC. And the board's serial port is exposed as /dev/ttyACM0 file.
I experiment with below naïve python code to read the raw serial output from the board.
with open("/dev/ttyACM0", "r") as sdf:
content = sdf.readline()
print(content)
I first let the board to output some string.
After a while, when I am sure the string output is finished, I run above script. It does print out the readable string. (BTW, it seems the serial output from the board seems to be cached somewhere.)
My questions are:
With tools like putty, I need to specify some parameters of the serial port, such as baud rate, etc. But I didn't specify anything in my script. How could it ever work?
If the serial port is outputting a stream of binary data endlessly, how to capture them lively?
Note: I don't want to use pySerial or other packages. I just want to do it from scratch.
I have an intelligent sensor for measure robot axis movements, i would read valuesusing modbus for every single reading position (it read values every 100ms)
I try using pymodbus:
slave = ModbusSerialClient(port='/dev/ttyAMA4', parity=N, baudrate=9600, timeout=1)
slave.connect()
while True:
print(slave.read_input_registers(300013, 2, unit=10))
time.sleep(0.01)
The problem is, my script start and read the first values but in 5,6 seconds exit because too many request to devices (devices does not respond)
There is a method for call a modbus device and get values in "RealTime" for example every milliseconds without problem due to the hight volumes of continuosly calls?
So many thanks in advance
Your code reads values at about every 10ms rather than 100ms. Typo?
Since your purpose is to get values in "realtime", but how fast you can achieve mostly depends on the sensor, if you can find the specs from sensor datasheet, e.g. minimal polling interval, please code accordingly, otherwise, you can keep testing with different interval values until you are satisfied.
to better understand serial port communication, I am trying to write some sample code, where Matlab has a loop running, which continously sends data to a serial port, while a Python script running on the same windows machine listens to this port, then receives and prints any received data.
In Matlab, I have written a simple loop, which sends 99 test signals to Port COM1,
% Setup a serial port and open it
tep=serial("COM1", "Baudrate", 9600);
fopen(tep);
% this loop is supposed to send a number to a serial port repeatedly
n = 1; % counter variable
while n < 100
fprintf(tep,"50"); % Send data to serial port
n = n + 1; % Counter variable
pause(0.5) % Sleep to make this loop run for a total of 50s0
fprintf('run'); % Test output within matlab to check, whether it runs
end
% finally close the serial port
fclose(tep);
as far as I can tell, this Matlab part works, as it prints "run" every hald second.
The Python listener:
import serial
import time
# set up the serial line same as in Matlab
ser = serial.Serial('COM1', 9600)
time.sleep(2)
# Read and record the data
data =[] # empty list to store the data
for i in range(50):
b = ser.readline() # read a byte string
string_n = b.decode() # decode byte string into Unicode
string = string_n.rstrip() # remove \n and \r
flt = float(string) # convert string to float
print(flt)
data.append(flt) # add to the end of data list
time.sleep(0.1) # wait (sleep) 0.1 seconds
ser.close()
# show the data
for line in data:
print(line)
Running the script in Python results in the following error:
serial.serialutil.SerialException: could not open port 'COM1': PermissionError(13, 'Zugriff verweigert', None, 5)
Obviously the port is already in use by Matlab, as it sends information to it, but I don't understand, why that is a problem. Shouldn't it be fine, for one program to send data to it and for another to receive data from it?
Kind regards.
I'm afraid you cannot connect to the same serial port from two different processes.
That means if you open the serial port from Matlab for writing you cannot open it from Python to read.
The serial port is intended to send data from a computer to another computer or device not to share data between different applications (to do that there are better ways like writing to a file or to a chunk of shared memory).
Having said that, if what you are trying to do is for debugging purposes or just learning you might want to investigate com0com which allows you to create a pair of virtual (software) serial ports. This would be the same as having a couple of hardware (real) serial ports wired to each other. Since now you have two ports you can send data from Matlab on one and read from Python on the other.
This is one of the most recurring questions about serial ports, so you should be able to find a lot of good resources. You might want to start here.
i want to set and get temperature of serial device (testequity1000) by using pyserial but not able to communicate.
cable used RS232
python 3.7
import serial
port = 'COM20'
` serial_comunication = serial.Serial(port, baudrate=9600, timeout=1)
answer = serial_comunication.read(400)
print(answer)
NEW_TEMPERATURE=45
set_temp=serial_comunication.write(b'NEW_TEMPERATURE')
print(set_temp)
abc=serial_comunication.close()
print(abc)
results:
b''
15
None
can't understand these result
Your device seems to be able to communicate on the RS232 bus but you have to use Modbus instead of the raw serial.
Quoting from the manual:
The F4 Temperature Controller has an RS-232C interface. A DB-9
connector is located on the rear panel. It is wired to accommodate a
null-modem cable. To communicate with the controller from a PC, you
need to run software that uses the Modbus RTU protocol. Each
controller function has a “register” number which can be read or
written to (when applicable). These registers are listed Chapter Seven
of the “Series F4 User’s Manual”. RS-232C Modbus programming resources
and LabVIEW drivers can be downloaded from
http://chamber.testequity.com/rs232.html
Common Modbus Registers
-Actual chamber temperature reading is register 100 (Input 1 Value).
-Actual chamber humidity reading is register 104 (Input 2 Value).
-Static temperature set point is register 300 (Set Point 1).
-Static humidity set point is register 319 (Set Point 2). •
-Temperature set point during a profile is register 4122 (Set Point 1, Current Profile Status).
-Humidity set point during a profile is register 4123 (Set Point 2, Current Profile Status).
-Decimal points are implied. For example, 1005 is actually 100.5 and -230 is -23.0.
Based on these details you can use pymodbus instead. A good starting point is this example.
You can install the package with: pip install pymodbus
So, if you want to read the Actual Chamber Temperature you need to write something similar to this:
#!/usr/bin/env python
# Pymodbus Synchronous Client Examples
# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s '
'%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
UNIT = 0x1
# ------------------------------------------------------------------------#
# choose the client you want
# ------------------------------------------------------------------------#
client = ModbusClient(method='rtu', port='COM20', timeout=1, baudrate=19200)
client.connect()
# ----------------------------------------------------------------------- #
# example requests
# ----------------------------------------------------------------------- #
rr = client.read_holding_registers(100, 1, unit=UNIT) #Actual chamber temperature reading
print(rr.registers[0])
# ----------------------------------------------------------------------- #
# close the client
# ----------------------------------------------------------------------- #
client.close()
You might need to change the default baudrate (according to the manual 19200) and/or the Modbus UNIT ID (UNIT 1 is the default value).
Hello I actually just finished using a little something in python. TestEquity chamber for the RS-232 you need to use modbus RTU protocol.
I'm using minimalmodbus. The other thing is that you need to make sure that you are using a null modem Tx and Rx need to be swapped in the DB9 connector.
Check the baudrate and slave address in setup, communications.
My code is here:
import minimalmodbus
TE1007C = minimalmodbus.Instrument("COM5", 1)
# Set baudrate
TE1007C.serial.baudrate = 9600
temp = TE1007C.read_register(100, 1, signed=True)
print(temp)
To set a temperature use write_register(). There are other registers that can be use.
I have to do an application for a GPRS modem JAVA (J2ME) programmable that must interface with an electromedical device (glucometer).
I have an input buffer and an output buffer on the serial port of the device.
When the application starts, I listen on the serial port and I receive from the glucometer one byte with the decimal code "5" which corresponds, to the ASCII table, the symbol of Enquiry and after 15 seconds I get the bytes "4" that corresponds to the End of Transmission.
To receive data from the glucometer I need to send an ACK signal (acknowledge) which corresponds to the byte "6".
I tried the following forms:
outBuffer.write("ACK\r\n".getBytes()); //first without setting the charset and after I trying to set all the charset.
I tried to send a byte buffer like this:
byte[] bSend = new byte[] { 6 };
outBuffer.write(bSend); //(I tried also with the byte 10 (LF) and 13 (CR)).
The result is that I can not receive data but I get cyclically but only the values 5 and 4.
With all the software that can comunicate with serial port (like Serial Monitor) if I send an ACK message I receive data from glucometer correctly.
I think my problem is due to the value of the ACK coding in Java, someone can indicate any solution?
As this seems to be a pretty low-level interface that uses ASCII control characters to do its communication I think you need to send these byte values verbatim, and without extra stuff like newlines or whatever. This means that
byte[] bSend = new byte[] { 6 };
outBuffer.write(bSend);
Is the correct approach. Now, this protocol looks a lot like ASTM E1381, so I checked here and paragraph 6.1.2 might be related to your problem:
When the meter initiates the Establishment Phase, the meter determines
if the computer is connected by initially sending an <ENQ> character.
If the computer responds within 15 seconds by sending an <ACK>
character, the meter proceeds with Data Transfer Mode. If the computer
responds within 15 seconds with a <NAK> character, the meter sends an
<EOT> then attempts to enter Remote Command Mode, by looking for an
<ENQ> character from the computer. Also see "Section 6.2 Remote
Command Mode Protocol". Any response within 15 seconds to the meter’s
<ENQ> other than an <ACK> or <NAK> character causes the meter to send
an <EOT>, delay one second, then send another <ENQ>. If the computer
does not respond within 15 seconds, then the meter sends an <EOT>,
delays one second, then sends another <ENQ> and waits again for a
response from the computer. Note: One second after sending an <ENQ>,
the meter may enter a low power mode. Thus, there is a possibility
that the first <ACK> sent by the computer is not read correctly. In
this case, the meter responds with an <EOT>, delays one second, then
sends another <ENQ>.
Emphasis mine, I guess that that's what's happening. So, you should repeat sending another ENQ to get it into data transfer mode, assuming that that's what you want.
it should be
byte bSend=(byte)0x6;
outBuffer.write(bSend);