MODBUS RS485 serial communication - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Data Science (https://python-forum.io/forum-44.html) +--- Thread: MODBUS RS485 serial communication (/thread-40562.html) |
MODBUS RS485 serial communication - Vivek - Aug-18-2023 Hi all, I'm trying to send a command to my sensor and get the response back, but I'm facing these problems: i. The time elapsed between each received/saved data is not exactly 1 second ii. The program stops printing/saving data after a few iterations, even though the code is still running Here is the code I'm using: import serial import time import os # Create a directory with the desired name format folder_name = time.strftime("%H%M%S%d%m%y") os.makedirs(folder_name, exist_ok=True) # Establish serial connection ser = serial.Serial('COM3', 19200, parity=serial.PARITY_EVEN, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS) # Save column headers to the file file_path = os.path.join(folder_name, "data.txt") with open(file_path, "a") as file: file.write("date_time\telapsed_seconds\tO2_ppm\tO2_percent\n") start_time = time.time() try: while True: # Send MODBUS command to read O2 ppm ser.write(b':010400000004F7\r\n') response = ser.readline().decode().strip() print(response) o2_ppm = float(response[7:15]) / 100.0 # Adjust according to the format mentioned print(o2_ppm) o2_percent = o2_ppm / 10000 print(o2_percent) # Calculate elapsed seconds elapsed_seconds = time.time() - start_time # Get current timestamp timestamp = time.strftime("%Y-%m-%d %H:%M:%S") # Append data to the file with open(file_path, "a") as file: file.write(f"{timestamp}\t{elapsed_seconds:.2f}\t{o2_ppm:.2f}\t{o2_percent:.6f}\n") time.sleep(1) # Wait for 1 second except KeyboardInterrupt: pass finally: # Close the serial connection ser.close()Please give me some suggestions to rectify the issue. Thanks in advance. RE: MODBUS RS485 serial communication - deanhystad - Aug-22-2023 Disclaimer: I've never used Modbus ASCII. I'm used to reading/writing binary modbus packets. I'm also more used to using TCP or UDP instead of serial. View everything below with a degree of skepticism. Never use readline without a timeout. When your program stops responding it would be nice to know why. If the read times out, check if there any bytes in the serial buffer and display the partial results. Maybe the information can help you figure out what is going on. You are waiting a second, of course your transactions are not happening at 1 second intervals. They are one second in-between. You could adjust your sleep time to compensate for the time it takes to perform the transaction, but it would be easier to use an event scheduler. Python comes with a built in scheduler, sched, but it is awkward to use for reoccurring events. I suggest using schedule. https://pypi.org/project/schedule/ I would try debugging like this: import serial import time import os # Create a directory with the desired name format folder_name = time.strftime("%H%M%S%d%m%y") os.makedirs(folder_name, exist_ok=True) # Establish serial connection ser = serial.Serial( "COM3", 19200, parity=serial.PARITY_EVEN, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1.0, ) # Save column headers to the file file_path = os.path.join(folder_name, "data.txt") with open(file_path, "a") as file: file.write("date_time\telapsed_seconds\tO2_ppm\tO2_percent\n") start_time = (time.time() + 1) // 1 try: while True: time.sleep(1 - time.time() % 1) # Wait til start of second ser.write(b":010400000004F7\r\n") response = ser.readline().decode().strip() if not (response := ser.readline()): if ser.in_waiting: print("Read timed out. Buffer =", ser.read(ser.in_waiting)) else: print("Read timed out. Buffer is empty.") continue o2_ppm = float(response[7:15]) / 100.0 o2_percent = o2_ppm / 10000 elapsed_seconds = time.time() - start_time timestamp = time.strftime("%Y-%m-%d %H:%M:%S") # Append data to the file with open(file_path, "a") as file: # file.write( print( f"{timestamp}\t{elapsed_seconds:.2f}\t{o2_ppm:.2f}\t{o2_percent:.6f}\n" ) except KeyboardInterrupt: pass finally: ser.close()This uses sleep(), but adjusts the sleep period to compensate for the message processing/transmission time and any jitter. |