InvalidPinDefError at the moment of definition the pins - python
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').
Related
UART communication Raspberry Pi Pico to Raspberry Pi
I am trying to communicate with a raspberry pi pico with my raspberry pi 4 over uart. The below code does transmit data, but I am only receiving data from the print statement. import os import utime from machine import ADC temp_sensor = ADC(4) # Default connection of temperature sensor def temperature(): # get raw sensor data raw_sensor_data = temp_sensor.read_u16() # convert raw value to equivalent voltage sensor_voltage = (raw_sensor_data / 65535)*3.3 # convert voltage to temperature (celcius) temperature = 27. - (sensor_voltage - 0.706)/0.001721 return temperature #print setup information : print("OS Name : ",os.uname()) uart = machine.UART(0, baudrate = 9600) print("UART Info : ", uart) utime.sleep(3) while True: temp = temperature() print(str(temp)) uart.write(str(temp)) utime.sleep(1) And the code on my raspberry pi 4 is: import serial import time import numpy as np import matplotlib.pyplot as plt #ser = serial.Serial('COM14',9600) ser = serial.Serial('/dev/ttyACM0', 9600) time.sleep(1) while True: # read two bytes of data #data = (ser.read(8)) data = (ser.readline()) # convert bytestring to unicode transformation format -8 bit temperature = str(data).encode("utf-8") #print("Pico's Core Temperature : " + temperature + " Degree Celcius") print(temperature) The output in the terminal on my RPI 4 is: 27.2332 26.443 26.443 26.564 There is an extra new line between. If I remove print(str(temp)) from the pico code I get nothing. I can put just about anything in uart.write(str(temp)) and still receive the print statement, but without the uart.write() I will receive nothing.
extra new line: this problem is just because the print ends with new line you can change print(str(temp)) to print(str(temp), end="") in raspberry pi pico code with respect to your second problem I don't think that uart.write(str(temp))is doing something useful. print statement is the way to send data to raspberry pi A way I use to send data to raspberry pi is: raspberry pi pico send the number of chars of the message then send the message while True: temp = temperature() print(len(str(temp))) utime.sleep(1) print(str(temp)) utime.sleep(1) the length would be between 1 and 9 so raspberry pi will receive 1 char in raspberry pi code while True: # read length of data length = int(ser.read(1).encode("utf-8")) # read the data data = (ser.read(length)) #convert bytestring to unicode transformation format -8 bit temperature = str(data).encode("utf-8") print(temperature)
RS485 modbus incomplete packets
I have two usb to serial cables connected to each other on 2 different usb ports on the same pc. The ground and A and B cables are all connected to eachother. the voltage cable is isolated. When I send ASCII characters using a serial terminal i can communicate both ways. But when I run a python script for a modbus slave and a master It works sometimes and sometimes it doesnt. I cannot find a pattern in when it works and when not. I can see when it works all the sent bytes are received by the slave but when it doesnt work the slave receives atleast 1 byte but not the rest. Then it obviously gives a CRC error and crashes. How come some bytes are missing through modbus and not ASCII serial terminals? Is this a hardware problem? How can I find out? I didnt connect extra resistors. I can show the code for the slave and master, Thanks As you can see I have three USB-to-serial cables connected in parallel, the orange and yellow cables are the A and B cables and the black ones are the grounds cables. The cables are these http://www.ftdichip.com/Products/Cables/USBRS485.htm This is the slave code but I tried different libraries and got the same results so I doubt its the code: #!/usr/bin/env python # -*- coding: utf_8 -*- """ Modbus TestKit: Implementation of Modbus protocol in python (C)2009 - Luc Jean - luc.jean#gmail.com (C)2009 - Apidev - http://www.apidev.fr This is distributed under GNU LGPL license, see license.txt """ import sys import modbus_tk import modbus_tk.defines as cst from modbus_tk import modbus_rtu import serial #PORT = 0 PORT = '/dev/ttyUSB2' def main(): """main""" logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s") #Create the server server = modbus_rtu.RtuServer(serial.Serial(port=PORT, baudrate=9600, bytesize=8, parity='N', stopbits=1, xonxoff=0)) try: logger.info("running...") logger.info("enter 'quit' for closing the server") server.start() slave_1 = server.add_slave(1) slave_1.add_block('0', cst.HOLDING_REGISTERS, 0, 100) while True: cmd = sys.stdin.readline() args = cmd.split(' ') if cmd.find('quit') == 0: sys.stdout.write('bye-bye\r\n') break elif args[0] == 'add_slave': slave_id = int(args[1]) server.add_slave(slave_id) sys.stdout.write('done: slave %d added\r\n' % (slave_id)) elif args[0] == 'add_block': slave_id = int(args[1]) name = args[2] block_type = int(args[3]) starting_address = int(args[4]) length = int(args[5]) slave = server.get_slave(slave_id) slave.add_block(name, block_type, starting_address, length) sys.stdout.write('done: block %s added\r\n' % (name)) elif args[0] == 'set_values': slave_id = int(args[1]) name = args[2] address = int(args[3]) values = [] for val in args[4:]: values.append(int(val)) slave = server.get_slave(slave_id) slave.set_values(name, address, values) values = slave.get_values(name, address, len(values)) sys.stdout.write('done: values written: %s\r\n' % (str(values))) elif args[0] == 'get_values': slave_id = int(args[1]) name = args[2] address = int(args[3]) length = int(args[4]) slave = server.get_slave(slave_id) values = slave.get_values(name, address, length) sys.stdout.write('done: values read: %s\r\n' % (str(values))) else: sys.stdout.write("unknown command %s\r\n" % (args[0])) finally: server.stop() if __name__ == "__main__": main() EDIT: I just changed to baudrate to 115200 and the errors are way less. Is there anything else i can do?
Python to automatically select serial ports (for Arduino)
Currently the python program must know which port a device (Arduino) is on before Python can communicate the device. Problem: Whenever the device is plugged out and back in, its COM port changes, so the correct serial port must be given to Python again for it to find the device. How can Python (using pySerial) automatically search for the correct serial port to use? Is it possible for python to correctly identify the device on a serial port as an Arduino?
Use the following code to see all the available serial ports: import serial.tools.list_ports ports = list(serial.tools.list_ports.comports()) for p in ports: print p This gives me the following: ('COM4', 'Arduino Due Programming Port (COM4)', 'USB VID:PID=2341:003D SNR=75330303035351300230') ('COM11', 'RS-232 Port (COM11)', 'FTDIBUS\\VID_0856+PID_AC27+BBOPYNPPA\\0000') To work out if it's an Arduino you could do something like: if "Arduino" in p.description: print "This is an Arduino!"
Using serial.tools.list_ports.comports, we can find and connect to an arduino with: import warnings import serial import serial.tools.list_ports arduino_ports = [ p.device for p in serial.tools.list_ports.comports() if 'Arduino' in p.description # may need tweaking to match new arduinos ] if not arduino_ports: raise IOError("No Arduino found") if len(arduino_ports) > 1: warnings.warn('Multiple Arduinos found - using the first') ser = serial.Serial(arduino_ports[0]) If you know you're looking for exactly the same arduino each time, you can filter on p.serial_number instead import serial.tools.list_ports def find_arduino(serial_number): for pinfo in serial.tools.list_ports.comports(): if pinfo.serial_number == serial_number: return serial.Serial(pinfo.device) raise IOError("Could not find an arduino - is it plugged in?") ser = find_arduino(serial_number='85430353531351B09121')
""" Written on a Windows 10 Computer, Python 2.7.9 Version. This program automatically detects and lists ports. If no ports are found, it simply shells out. In the printout below "list(serial.tools.list_ports.comports())" finds two ports and the program lists them out - a listout shown below: COM5 - USB-SERIAL CH340 (COM5) Found Arduino Uno on COM5 COM4 - Microsoft USB GPS Port (COM4) As each port is found, "CH340," (the name of the Adruino Uno) is searched for in the listed port with the "while int1 < 9:" loop. The first "If" statement looks for "CH340" and when found the integer value "int1" will be the same as the com port #. With a concatination, the operation "str1 = "COM" + str2" gives the com port name of the Adruino, eg. "COM5." The next "IF" statement looks for both "CH340" AND str1, ("COM5") in the above case. The statement "Found Arduino Uno on COM5" prints out, and "str1" is used in setting up the com port: ser = serial.Serial(str1, 9600, timeout=10) This program goes on to open the com port and prints data from the Adruino. The modules "serial, sys, time, serial.tools.list_ports" must all be imported. Written by Joseph F. Mack 01/29/2016. "A BIG Thank you" to all the individuals whose programs I "borrowed" from that are available in the many forums for Python and PYGame users! """ import serial import sys import time import serial.tools.list_ports serPort = "" int1 = 0 str1 = "" str2 = "" # Find Live Ports ports = list(serial.tools.list_ports.comports()) for p in ports: print p # This causes each port's information to be printed out. # To search this p data, use p[1]. while int1 < 9: # Loop checks "COM0" to "COM8" for Adruino Port Info. if "CH340" in p[1]: # Looks for "CH340" in P[1]. str2 = str(int1) # Converts an Integer to a String, allowing: str1 = "COM" + str2 # add the strings together. if "CH340" in p[1] and str1 in p[1]: # Looks for "CH340" and "COM#" print "Found Arduino Uno on " + str1 int1 = 9 # Causes loop to end. if int1 == 8: print "UNO not found!" sys.exit() # Terminates Script. int1 = int1 + 1 time.sleep(5) # Gives user 5 seconds to view Port information -- can be changed/removed. # Set Port ser = serial.Serial(str1, 9600, timeout=10) # Put in your speed and timeout value. # This begins the opening and printout of data from the Adruino. ser.close() # In case the port is already open this closes it. ser.open() # Reopen the port. ser.flushInput() ser.flushOutput() int1 = 0 str1 = "" str2 = "" while int1==0: if "\n" not in str1: # concatinates string on one line till a line feed "\n" str2 = ser.readline() # is found, then prints the line. str1 += str2 print(str1) str1="" time.sleep(.1) print 'serial closed' ser.close()
Try this code (only for windows users. MAC user can withdraw idea from this concept) import serial import time list=['COM1','COM2','COM3','COM4','COM5','COM6','COM7','COM8','COM9','COM10','COM11','COM12','COM13','COM14','COM15','COM16','COM17','COM18',] COM1='COM1' COM2='COM2' COM3='COM3' COM4='COM4' COM5='COM5' COM6='COM6' COM7='COM7' COM8='COM8' COM9='COM9' COM10='COM10' COM11='COM11' COM12='COM12' COM13='COM13' COM14='COM14' COM15='COM15' COM16='COM16' COM17='COM17' COM18='COM18' COM19='COM19' time.sleep(1) ser = serial.Serial() ser.baudrate = 9600 i=1 while True: time.sleep(.2) print(i) ser.port = list[i] try: ser.open() if ser.isOpen()==True: print('connected') #print('arduino is on COMPORT'.join(i)) break break except: print('waiting') i=i+1 if i==18: print('Kindly remove usb cable and try again') break print('here we go') while True: print(ser.readline())
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)
How do I recover from a serialException using pySerial
I have an application that reads and transmits data to a device connected via USB. I'm using pySerial to facilitate this communication. Everything works fine until the USB cable is unplugged from the PC and an exception is thrown. Once the cable is plugged back in, I can't seem to recover and reconnect to my device. The only way for me to recover is to close down the application and unplug and plug the cable in again. Any help in understanding what's going on would be much appreciated. This is basic test code that I'm useing to help me understand the process. # Class used to communicate with USB Dongle import serial import time import sys class LPort: def __init__(self, port=0): "initialize the LPort class" self.error = "" self.traffic = "" self.dest = None if port == None: self.simulation = True else: self.simulation = False self.port = port # serial port we should use self.reset() self.time = time.time() def reInit(self): self.close() def reset(self): "flush port, reset the LPort, initialize LPort" if self.simulation: r = "LPort simulator" else: self.port.flushInput() self.port.flushOutput() self.fail = False self.command("/H1") self.dest = None r = "reset" self.error = "" self.traffic = "" return r def status(self): "return accumulated status info, reset collection" s = self.error self.error = "" return s def data(self): "return accumulated traffic data, reset collection" s = self.traffic self.traffic = "" return s def set_dest(self, addr): "set the destination address (if necessary)" if addr != self.dest: self.dest = addr self.command("/O") r = self.command("/D%02X" % addr) if r != "*": self.dest = None self.error += r else: r = True return r def checksum(self, bytes): "calculate the CRC-8 checksum for the given packet" crc_table = [ # this table is taken from the CP rectifier code 0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F, 0x36,0x31,0x24,0x23,0x2A,0x2D,0x70,0x77,0x7E,0x79, 0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53, 0x5A,0x5D,0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5, 0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,0x90,0x97, 0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1, 0xB4,0xB3,0xBA,0xBD,0xC7,0xC0,0xC9,0xCE,0xDB,0xDC, 0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA, 0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88, 0x81,0x86,0x93,0x94,0x9D,0x9A,0x27,0x20,0x29,0x2E, 0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04, 0x0D,0x0A,0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42, 0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,0x89,0x8E, 0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8, 0xAD,0xAA,0xA3,0xA4,0xF9,0xFE,0xF7,0xF0,0xE5,0xE2, 0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4, 0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56, 0x5F,0x58,0x4D,0x4A,0x43,0x44,0x19,0x1E,0x17,0x10, 0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A, 0x33,0x34,0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B, 0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,0x3E,0x39, 0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F, 0x1A,0x1D,0x14,0x13,0xAE,0xA9,0xA0,0xA7,0xB2,0xB5, 0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83, 0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1, 0xE8,0xEF,0xFA,0xFD,0xF4,0xF3] for i in range(len(bytes)): b = int(bytes[i]) if i == 0: chksum = crc_table[b] else: chksum = crc_table[chksum ^ b] return chksum def command(self, cmd): "transmit distinct commands to unit, and accept response" if self.simulation: r = "*" else: try: self.port.write(cmd + chr(13)) except serial.serialutil.SerialTimeoutException: r = "/TO" return r except: print "Unexpected error:", sys.exc_info()[0] r = "/Unknown" return r r = "" eol = False while True: c = self.port.read(1) if not c: r = "/FAIL " + r + " " + cmd self.error = r break else: r += c ordc = ord(c) if ordc == 13 or ordc == 42: break return r def checkRawDataForErrors(self, raw, errors = []): errorCodes = {'/SNA':'Slave Not Acknowledging', '/I81':'Busy, Command Ignored', '/I88':'Connection Not Open', '/I89':'Invalid Command Argument', '/I8A':'Transmit Not Active', '/I8F':'Invalid Command', '/I90':'Buffer Overflow', '/DAT':'Data Error', '/BADPEC':'Bad PEC Value', '/NO_MRC':'No Master Read Complete Signal', '/FAIL':'General Failure', '/LEN':'Data Length Error'} for ekey, eval in errorCodes.items(): if ekey in raw: errors.append(eval) return errors # self-testing module if __name__ == "__main__": com = serial.Serial(port=4, baudrate=115200, timeout=1, xonxoff=0) if com: port = LPort(com) print port time.sleep(5) port = LPort(com) print "/V =", port.command("/V") print "/V", port.data(), port.status() print "/O =", port.command("/O") print "/O", port.data(), port.status() print "/A =", port.command("/A") print "/A", port.data(), port.status() print "/L =", port.command("/L") print "/L", port.data(), port.status() com.close() else: print "cannot open com port" UPDATE: The following is the code around the creatfile() in serialwin32.py which returns the following message: serial.serialutil.SerialException: could not open port COM5: [Error 2] The system cannot find the file specified. self.hComPort = win32.CreateFile(port, win32.GENERIC_READ | win32.GENERIC_WRITE, 0, # exclusive access None, # no security win32.OPEN_EXISTING, win32.FILE_ATTRIBUTE_NORMAL | win32.FILE_FLAG_OVERLAPPED, 0) if self.hComPort == win32.INVALID_HANDLE_VALUE: self.hComPort = None # 'cause __del__ is called anyway raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
Assuming your device is well-behaved, all you must do is this: close your serial port (serial.Serial instance) find the COMX name of your port again open the serial port The 2nd part is problematic because Windows tries to be clever. In your case the following happens: USB device is connected and is assigned name COM2 Your program opens the device USB disconnects USB reconnects quickly before your program noticed that device died Windows sees that COM2 is busy and assigns a different name to this USB device (optional) your program closes the device your program tries to open COM2 again, but there's no hardware at that name The are way to get around Windows being clever -- you can specifically assign fixed COMX name to this device in Device Manager, COM ports, your port, advanced options. Another option is to detect device dying very fast and closing the file handle. If you are lucky then by the time device reconnects original COM2 is free again. Yet another option is to use a USB-serial converter from another manufacturer that uses another driver. Somehow COMX letter assignment is driver-specific. Better drivers may give you a stable name.
I've come across this problem as well. Sometimes my program has locked up when the device is plugged in again. NB. I have fixed the COMx name of the port as mentioned by #qarma I've rearranged my program so that as soon as an exception is thrown from the read() or write() methods of Serial I stop calling those methods. I then have a function which periodically retries opening the port to try to detect when the device has been plugged in again. This function creates a new instance of Serial with the same parameters as the original and tries to open it: def try_to_open_new_port(self): ret = False test = serial.Serial(baudrate=9600, timeout=0, writeTimeout=0) test.port = self.current_port_name try: test.open() if test.isOpen(): test.close() ret = True except serial.serialutil.SerialException: pass return ret A return of True indicates that the port is present once again.