Read the serial port - python

I dont seem to get the proper reading Id like from my serial.write/read. What do I do wrong?
After one turn in the loop, I would like to have another A00 output, but instead I get D13HIGH, as you can see below.
import serial
from time import sleep
import math
port = '/dev/ttyAMA0'
baud = 9600
ser = serial.Serial(port=port, baudrate=baud)
sleep(0.2)
count = 0
while count < 20:
ser.write('a--A00READ--')
sleep(0.2)
reply = ser.read(12)
print(reply)
adc = reply[7:]
adc = adc.strip('-')
adc = int(adc)
volts = (adc / 1023.0 * 5.0)
ser.write('a--D13HIGH--')
count += 1
ser.close()
Output:
>>>
a--A00+487--
a--D13HIGH--
Traceback (most recent call last):
File "/home/pi/serialcom.py", line 21, in <module>
adc = int(adc)
ValueError: invalid literal for int() with base 10: 'IGH'
>>>

Related

minimalmodbus checksum error in rtu mode with 2 devices

I have a RPI with a USB CH340 dongle connected to a EM340 energy meter. It works fine with the code below.
When I connect 2 x EM340 energy meters I get the following error:
pi#raspberrypi:~ $ python3 modbus_test.py
Traceback (most recent call last):
File "modbus_test.py", line 21, in <module>
freq2 = instrument.read_register(0x0033,1) # Registernumber, number of decimals
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 486, in read_register
payloadformat=_Payloadformat.REGISTER,
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 1245, in _generic_command
payload_from_slave = self._perform_command(functioncode, payload_to_slave)
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 1330, in _perform_command
response, self.address, self.mode, functioncode
File "/home/pi/.local/lib/python3.7/site-packages/minimalmodbus.py", line 1867, in _extract_payload
raise InvalidResponseError(text)
minimalmodbus.InvalidResponseError: Checksum error in rtu mode: '6ý' instead of '\x99ò' . The response is: '\x01\x01\x00\x00\x166ý' (plain response: '\x01\x01\x00\x00\x166ý')
My code:
import minimalmodbus
import serial
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1) # port name, slave address (in decimal)
#instrument.serial.port # this is the serial port name
instrument.serial.baudrate = 9600 # Baud
instrument.serial.bytesize = 8
#instrument.serial.parity = serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 0.2 # seconds
instrument.address = 1 # this is the slave address number
#instrument.mode = minimalmodbus.MODE_ASCII # rtu or ascii mode
instrument.mode = minimalmodbus.MODE_RTU
instrument.clear_buffers_before_each_transaction = True
instrument.close_port_after_each_call = True
## Read temperature (PV = ProcessValue) ##
freq2 = instrument.read_register(0x0033,1) # Registernumber, number of decimals
txt = "Frekvens: {} Hz".format(freq2)
#0x0034
kwh_total = instrument.read_register(0x0400)
kwh_total_2 = instrument.read_register(0x0402)
txt2 = "Total forbrug: {0}.{1} kWh".format(kwh_total,kwh_total_2)
w_l1 = instrument.read_register(0x0012,1) # Registernumber, number of decimals
txt3 = "Nuværende forbrug: {} W".format(w_l1)
print(txt)
print(txt2)
print(txt3)
I have wired the 2xEM340 according to the https://web.evishine.dk/wp-content/uploads/2019/11/EM340-ENG.pdf page 3.
Any idea why I get Checksum error in rtu mode ?
As per the comments if you attach two Modbus RTU devices with the same ID in parallel then they will both respond to any request addressed to that Slave ID. The responses will probably collide which means your code will receive a garbled response (detected via the CRC).
The solution is to change the ID of one of the devices.

Why decode("utf-8") not working in serial?

using serial, am trying to send a number then reading it on the other side....error:
Traceback (most recent call last):
File "C:\Users\desk\Downloads\serialTestPy_processing3.py", line 8, in <module>
serPrint = serPrint.decode("utf-8")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x98 in position 0: invalid start byte
sending code:
import serial
from time import sleep
ser7 = serial.Serial('COM7',19600)
while True:
ser7.write(str.encode('80'))
sleep(1)
Receiving code:
import serial
from time import sleep
ser8 = serial.Serial('COM8',19600)
while True:
serPrint = ser8.read()
serPrint = serPrint.decode("utf-8")
print(serPrint)
friend!
I have tested this and worked for me,
Sending Part:
import serial
import time
ser7 = serial.Serial('COM7',19600) while True:
ser7.write('80')
time.sleep(1)
Receiving Part:
import serial
from time import sleep
ser8 = serial.Serial('COM8',19600)
while True:
serPrint = ser8.read()
serPrint = serPrint.decode('utf-8')
print(serPrint)

Modbus RTU master - python script with minimalmodbus

I would like to control an actuator with a python script in MODBUS RTU
master. I tried to use the library minimalmodbus to communicate (write
bit, write & read registers) with my slave.
When I start my code, I have some errors. So, someone can I help me to find a solution?
My code:
import minimalmodbus
import os
import struct
import sys
import serial
import time
instrument = minimalmodbus.Instrument('/dev/ttyRS485', 1)
instrument.serial.port
instrument.serial.baudrate = 9600
instrument.serial.parity = serial.PARITY_NONE
instrument.serial.bytesize = 8
instrument.serial.stopbits = 1
instrument.mode = minimalmodbus.MODE_RTU
instrument.serial.timeout = 0.05
modbus = instrument.write_bit(0x0427, 1)
print (modbus)
alarme = instrument.write_bit(0x0404, 1)
print (alarme)
alarme = instrument.write_bit(0x0404, 0)
print (alarme)
on = instrument.write_bit(0x0403, 1)
print (on)
home = instrument.write_bit(0x040B, 1)
print (home)
position = instrument.write_register(0x9900, 0, number_of_decimals=2,functioncode=16, signed=False)
print (position)
posi = instrument.write_register(0x9901, 6000, number_of_decimals=2,functioncode=16, signed=False)
print (posi)
Errors:
========================= RESTART: /home/pi/test.py =========================
None
None
None
None
None
None
Traceback (most recent call last):
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py", line 2448, in _pack
result = struct.pack(formatstring, value)
struct.error: 'H' format requires 0 <= number <= 65535
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/pi/test.py", line 36, in <module>
posi = instrument.write_register(0x9901, 6000, number_of_decimals=2, functioncode=16, signed=False)
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py",line 518, in write_register
payloadformat=_PAYLOADFORMAT_REGISTER,
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py",line 1166, in _generic_command
payloadformat,
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py",line 1514, in _create_payload
value, number_of_decimals, signed=signed
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py", line 1991, in
_num_to_twobyte_string outstring = _pack(formatcode, integer)
File "/home/pi/.local/lib/python3.5/site-packages/minimalmodbus.py", line 2454, in _pack
raise ValueError(errortext.format(value, formatstring))
ValueError: The value to send is probably out of range, as the num-to-bytestring conversion failed.
Value: 600000 Struct format code is: >H
In response to your request in the comments for an alternative library, here is what I use to read modbus with the pymodbus library:
import pymodbus
from pymodbus.pdu import ModbusRequest
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
from pymodbus.transaction import ModbusRtuFramer
client = ModbusClient(
method = 'rtu'
,port='/dev/tty.usbserial-AQ00BYCR'
,baudrate=38400
,parity = 'O'
,timeout=1
)
connection = client.connect()
registers = client.read_holding_registers(0,100,unit=1)# start_address, count, slave_id
print (registers.registers)
Note that in the above, the reading begins from address 0 and continues to address 100, for slave_id 1.
To write registers, do the following:
write = client.write_register(1,425,unit=1)# address = 1, value to set = 425, slave ID = 1

InvalidPinDefError at the moment of definition the pins

I'm trying to use pyfirmata to send and receive data between Arduino Uno R3 and my python program. At Arduino installed StandartFirmata sketch.
Code is:
from time import sleep
import serial
import pyfirmata
com_port_number = str(int(input('Введите номер COM-порта ')))
port = 'COM' + com_port_number # COM port number
print('Выбран порт COM ', port)
try:
board = pyfirmata.Arduino(port)
except serial.SerialException:
print('Не удается подключится к выбранному COM-порту')
com_port_number = str(int(input('Введите номер СОМ-порта')))
port = 'COM' + com_port_number
board = pyfirmata.Arduino(port)
sleep(1)
it = pyfirmata.util.Iterator(board)
it.start()
temp_list = []
potentiomentr = board.get_pin('a:0:o')
acid_control = board.get_pin('a:2:o')
stock_control = board.get_pin('a:3:o')
temperature_pin = board.get_pin('d:4:i') # well, this line is worked fine. Temperature sensor works correctly
in_connection_pc = board.get_pin('d:0:o') #but now i have InvalidPinDefError
triac = board.get_pin('d:6:o')
level = board.get_pin('d:8:i')
in_engine = board.get_pin('d:5:o')
in_triac = board.get_pin('d:10:o')
in_pump = board.get_pin('d:11:o')
drive_control = board.get_pin('d:12:o')
pump_control = board.get_pin('d:13:o')
while 1: # бесконечный цикл
a = temperature_pin.read()
b = in_connection_pc.write(1)
print(a)
list.append(a,b)
print(list)
sleep(3)
board.exit()
But i have some strange mistake:
Traceback (most recent call last):
File "C:/Users/lomil/PycharmProjects/Pyython_and_CSV_love/test_analog.py", line 22, in <module>
in_connection_pc = board.get_pin('d:0:i') #but now i have InvalidPinDefError??
File "C:\Users\lomil\Python_32\lib\site-packages\pyfirmata\pyfirmata.py", line 220, in get_pin
raise InvalidPinDefError('Invalid pin definition: UNAVAILABLE pin {0} at position on {1}'.format(pin_def, self.name))
pyfirmata.pyfirmata.InvalidPinDefError: Invalid pin definition: UNAVAILABLE pin d:0:i at position on COM1
When I commented all lines except
temperature_pin = board.get_pin('d:4:i')
It worked, but I can not understand what's wrong with other pins. They are totally good and worked fine when I wrote test sketch to Arduino.
The error message is actually complaining: UNAVAILABLE pin d:0:i at position on COM1. On the Arduino Uno (and most Arduinos) digital pins 0 and 1 are dual-use pins and are also used for communications over the serial port, aka COM port.
Firmata works by constantly communicating over the serial port so you can't actually use digital pins 0 and 1 for anything else while using Firmata.
So whatever wire you have plugged into your Arduino on digital pin 0, you need to move to another unused digital pin, like pin 3. So, if you move that wire to digital pin 3, then in code you would now need in_connection_pc = board.get_pin('d:3:o').

How to read a string of integers received on python from serial arduino

I'm sending a list of values (e.g. 80,539,345,677) from Arduino to a Python app running on my RPi. I have not been successful in extracting the values and assigning them to respective variables or objects in the app.
Here's my code:
def read_values():
#if DEBUG:
print "reading arduino data"
ser = serial.Serial('/dev/ttyUSB0', 9600)
print "receiving arduino data"
ser_line = ser.readline()
print ser_line
ser.close()
ser_list = [int(x) for x in ser_line.split(',')]
ambientLight = ser_list[1]
print ambientLight
return ambientLight
What I'm getting from Python is:
reading arduino data
receiving arduino data
80,477,82,2
Traceback (most recent call last):
File "serialXivelyTest4c.py", line 77, in <module>
run()
File "serialXivelyTest4c.py", line 63, in run
ambientLight = read_values()
File "serialXivelyTest4c.py", line 27, in read_values
ser_list = [int(x) for x in ser_line.split(',')]
ValueError: invalid literal for int() with base 10: '8254\r80'
You can see that I'm getting values, but that they're being truncated. Can anyone please tell me where I'm going wrong here. Thanks so much.
I've never used an Arduino but here's how I read from serial with a different board. I used serial.
import streamUtils as su # see below
ser = su.connectPort("/dev/tty.SLAB_USBtoUART") # make sure you have the right port name
data = ""
while True:
try:
data = data + ser.read(1) # read one, blocking
time.sleep(1) # give it time to put more in waiting
n = ser.inWaiting() # look if there is more
if n:
data = data + ser.read(n) # get as much as possible
# I needed to save the data until I had complete
# output.
if data:
# make sure you have the whole line and format
else:
break
except serial.SerialException:
sys.stderr.write("Waiting for %s to be available" % (ser.name))
sys.exit(1)
sys.stderr.write("Closing port\n")
ser.close()
Here's the streamUtils.connectPort():
import serial
def connectPort(portname):
# connect to serial port
ser = serial.Serial()
ser.port = portname
ser.baudrate = 9600
ser.parity = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
ser.bytesize = serial.EIGHTBITS
ser.timeout = 15 # need some value for timeout so the read will end
try:
ser.open()
except serial.SerialException:
sys.stderr.write("Could not open serial port %s\n" % (ser.name))
sys.exit(1)
return (ser)

Categories

Resources