问题
I'm new to Python and trying to run a demo provide by Invensense. They provide a Python client which should take COM traffic and manipulate a graphic. The demo seems to crash out of the box and I'm not sure if I have something wrong with pyserial that I installed. The requirements were python2.7, pyserial and pygame. The pyserial executable serialwin32.py throws this error:
Traceback (most recent call last):
.......
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 47, in open
if port.upper().startswith('COM') and int(port[3:]) > 8:
AttributeError: 'int' object has no attribute 'upper'
Using input from user 101 (not sure how to thank you in the system - but THANKS!)
port = str(self.name)
This error is resolved. However as is always the case the next error presents a couple of lines farther down when windows seems to deny access:
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 66, in open
raise SerialException("could not open port %r: %r" % (self.portstr, ctypes.WinError()))
serial.serialutil.SerialException: could not open port 'COM6': WindowsError(5, 'Access is denied.')
The partial code reference seems to be:
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 %r: %r" % (self.portstr, ctypes.WinError()))
Full Code excerpt at end.
Questions:
1) Any ideas how to get past this error?
2) My speculation :-( is that this may be a privileges issue but being new to python I'm not sure how to address if Windows 10 thinks it's protecting me...
3) I agree that I shouldn't have to modify pyserial at all (lots of people have likely tried it) so I suspect some other problem. However, I'm clueless so I'm posting the client python code here too.
---------- client application which requires pyserial,pygame ----------
#!/usr/bin/python
# eMPL_client.py
# A PC application for use with Embedded MotionApps.
# Copyright 2012 InvenSense, Inc. All Rights Reserved.
import serial, sys, time, string, pygame from ponycube import *
class eMPL_packet_reader:
def __init__(self, port, quat_delegate=None, debug_delegate=None, data_delegate=None ):
self.s = serial.Serial(port,115200)
self.s.setTimeout(0.1)
self.s.setWriteTimeout(0.2)
# TODO: Will this break anything?
##Client attempts to write to eMPL.
#try:
#self.s.write("\n")
#except serial.serialutil.SerialTimeoutException:
#pass # write will timeout if umpl app is already started.
if quat_delegate:
self.quat_delegate = quat_delegate
else:
self.quat_delegate = empty_packet_delegate()
if debug_delegate:
self.debug_delegate = debug_delegate
else:
self.debug_delegate = empty_packet_delegate()
if data_delegate:
self.data_delegate = data_delegate
else:
self.data_delegate = empty_packet_delegate()
self.packets = []
self.length = 0
self.previous = None
def read(self):
NUM_BYTES = 23
p = None
while self.s.inWaiting() >= NUM_BYTES:
rs = self.s.read(NUM_BYTES)
if ord(rs[0]) == ord('$'):
pkt_code = ord(rs[1])
if pkt_code == 1:
d = debug_packet(rs)
self.debug_delegate.dispatch(d)
elif pkt_code == 2:
p = quat_packet(rs)
self.quat_delegate.dispatch(p)
elif pkt_code == 3:
d = data_packet(rs)
self.data_delegate.dispatch(d)
else:
print "no handler for pkt_code",pkt_code
else:
c = ' '
print "serial misaligned!"
while not ord(c) == ord('$'):
c = self.s.read(1)
self.s.read(NUM_BYTES-1)
def write(self,a):
self.s.write(a)
def close(self):
self.s.close()
def write_log(self,fname):
f = open(fname,'w')
for p in self.packets:
f.write(p.logfile_line())
f.close()
# =========== PACKET DELEGATES ==========
class packet_delegate(object):
def loop(self,event):
print "generic packet_delegate loop w/event",event
def dispatch(self,p):
print "generic packet_delegate dispatched",p
class empty_packet_delegate(packet_delegate):
def loop(self,event):
pass
def dispatch(self,p):
pass
class cube_packet_viewer (packet_delegate):
def __init__(self):
self.screen = Screen(480,400,scale=1.5)
self.cube = Cube(30,60,10)
self.q = Quaternion(1,0,0,0)
self.previous = None # previous quaternion
self.latest = None # latest packet (get in dispatch, use in loop)
def loop(self,event):
packet = self.latest
if packet:
q = packet.to_q().normalized()
self.cube.erase(self.screen)
self.cube.draw(self.screen,q)
pygame.display.flip()
self.latest = None
def dispatch(self,p):
if isinstance(p,quat_packet):
self.latest = p
class debug_packet_viewer (packet_delegate):
def loop(self,event):
pass
def dispatch(self,p):
assert isinstance(p,debug_packet);
p.display()
class data_packet_viewer (packet_delegate):
def loop(self,event):
pass
def dispatch(self,p):
assert isinstance(p,data_packet);
p.display()
# =============== PACKETS =================
# For 16-bit signed integers.
def two_bytes(d1,d2):
d = ord(d1)*256 + ord(d2)
if d > 32767:
d -= 65536
return d
# For 32-bit signed integers.
def four_bytes(d1, d2, d3, d4):
d = ord(d1)*(1<<24) + ord(d2)*(1<<16) + ord(d3)*(1<<8) + ord(d4)
if d > 2147483648:
d-= 4294967296
return d
class debug_packet (object):
# body of packet is a debug string
def __init__(self,l):
sss = []
for c in l[3:21]:
if ord(c) != 0:
sss.append(c)
self.s = "".join(sss)
def display(self):
sys.stdout.write(self.s)
class data_packet (object):
def __init__(self, l):
self.data = [0,0,0,0,0,0,0,0,0]
self.type = ord(l[2])
if self.type == 0: # accel
self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
elif self.type == 1: # gyro
self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
elif self.type == 2: # compass
self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
elif self.type == 3: # quat
self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<30)
self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<30)
self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<30)
self.data[3] = four_bytes(l[15],l[16],l[17],l[18]) * 1.0 / (1<<30)
elif self.type == 4: # euler
self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
elif self.type == 5: # rot
self.data[0] = two_bytes(l[3],l[4]) * 1.0 / (1<<14)
self.data[1] = two_bytes(l[5],l[6]) * 1.0 / (1<<14)
self.data[2] = two_bytes(l[7],l[8]) * 1.0 / (1<<14)
self.data[3] = two_bytes(l[9],l[10]) * 1.0 / (1<<14)
self.data[4] = two_bytes(l[11],l[12]) * 1.0 / (1<<14)
self.data[5] = two_bytes(l[13],l[14]) * 1.0 / (1<<14)
self.data[6] = two_bytes(l[15],l[16]) * 1.0 / (1<<14)
self.data[7] = two_bytes(l[17],l[18]) * 1.0 / (1<<14)
self.data[8] = two_bytes(l[19],l[20]) * 1.0 / (1<<14)
elif self.type == 6: # heading
self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
else: # unsupported
pass
def display(self):
if self.type == 0:
print 'accel: %7.3f %7.3f %7.3f' % \
(self.data[0], self.data[1], self.data[2])
elif self.type == 1:
print 'gyro: %9.5f %9.5f %9.5f' % \
(self.data[0], self.data[1], self.data[2])
elif self.type == 2:
print 'compass: %7.4f %7.4f %7.4f' % \
(self.data[0], self.data[1], self.data[2])
elif self.type == 3:
print 'quat: %7.4f %7.4f %7.4f %7.4f' % \
(self.data[0], self.data[1], self.data[2], self.data[3])
elif self.type == 4:
print 'euler: %7.4f %7.4f %7.4f' % \
(self.data[0], self.data[1], self.data[2])
elif self.type == 5:
print 'rotation matrix: \n%7.3f %7.3f %7.3f\n%7.3f %7.3f %7.3f\n%7.3f %7.3f %7.3f' % \
(self.data[0], self.data[1], self.data[2], self.data[3], \
self.data[4], self.data[5], self.data[6], self.data[7], \
self.data[8])
elif self.type == 6:
print 'heading: %7.4f' % self.data[0]
else:
print 'what?'
class quat_packet (object):
def __init__(self, l):
self.l = l
self.q0 = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<30)
self.q1 = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<30)
self.q2 = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<30)
self.q3 = four_bytes(l[15],l[16],l[17],l[18]) * 1.0 / (1<<30)
def display_raw(self):
l = self.l
print "".join(
[ str(ord(l[0])), " "] + \
[ str(ord(l[1])), " "] + \
[ str(ord(a)).ljust(4) for a in
[ l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10] ] ] + \
[ str(ord(a)).ljust(4) for a in
[ l[8], l[9], l[10] , l[11], l[12], l[13]] ]
)
def display(self):
if 1:
print "qs " + " ".join([str(s).ljust(15) for s in
[ self.q0, self.q1, self.q2, self.q3 ]])
if 0:
euler0, euler1, euler2 = self.to_q().get_euler()
print "eulers " + " ".join([str(s).ljust(15) for s in
[ euler0, euler1, euler2 ]])
if 0:
euler0, euler1, euler2 = self.to_q().get_euler()
print "eulers " + " ".join([str(s).ljust(15) for s in
[ (euler0 * 180.0 / 3.14159) - 90 ]])
def to_q(self):
return Quaternion(self.q0, self.q1, self.q2, self.q3)
# =============== MAIN ======================
if __name__ == "__main__":
if len(sys.argv) == 2:
comport = int(sys.argv[1]) - 1
else:
print "usage: " + sys.argv[0] + " port"
sys.exit(-1)
pygame.init()
viewer = cube_packet_viewer()
debug = debug_packet_viewer()
data = data_packet_viewer()
reader = eMPL_packet_reader(comport,
quat_delegate = viewer,
debug_delegate = debug,
data_delegate = data)
while 1:
event = pygame.event.poll()
# TODO: Allow exit via keystroke.
if event.type == pygame.QUIT:
viewer.close()
break
if event.type == pygame.KEYDOWN:
reader.write(pygame.key.name(event.key))
reader.read()
viewer.loop(event)
debug.loop(event)
data.loop(event)
# TODO: If system load is too high, increase this sleep time.
pygame.time.delay(0)
---------------- Full file below of pyserial -----------
#! python
import ctypes
import time
from serial import win32
import serial
from serial.serialutil import SerialBase, SerialException, to_bytes, portNotOpenError, writeTimeoutError
class Serial(SerialBase):
"""Serial port implementation for Win32 based on ctypes."""
BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200)
def __init__(self, *args, **kwargs):
super(SerialBase, self).__init__()
self._port_handle = None
self._overlapped_read = None
self._overlapped_write = None
SerialBase.__init__(self, *args, **kwargs)
def open(self):
"""\
Open port with current settings. This may throw a SerialException
if the port cannot be opened.
"""
if self._port is None:
raise SerialException("Port must be configured before it can be used.")
if self.is_open:
raise SerialException("Port is already open.")
# the "\\.\COMx" format is required for devices other than COM1-COM8
# not all versions of windows seem to support this properly
# so that the first few ports are used with the DOS device name
str port = self.name
try:
if port.upper().startswith('COM') and int(port[3:]) > 8:
port = '\\\\.\\' + port
except ValueError:
# for like COMnotanumber
pass
self._port_handle = 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._port_handle == win32.INVALID_HANDLE_VALUE:
self._port_handle = None # 'cause __del__ is called anyway
raise SerialException("could not open port %r: %r" % (self.portstr, ctypes.WinError()))
try:
self._overlapped_read = win32.OVERLAPPED()
self._overlapped_read.hEvent = win32.CreateEvent(None, 1, 0, None)
self._overlapped_write = win32.OVERLAPPED()
#~ self._overlapped_write.hEvent = win32.CreateEvent(None, 1, 0, None)
self._overlapped_write.hEvent = win32.CreateEvent(None, 0, 0, None)
# Setup a 4k buffer
win32.SetupComm(self._port_handle, 4096, 4096)
# Save original timeout values:
self._orgTimeouts = win32.COMMTIMEOUTS()
win32.GetCommTimeouts(self._port_handle, ctypes.byref(self._orgTimeouts))
self._reconfigure_port()
# Clear buffers:
# Remove anything that was there
win32.PurgeComm(
self._port_handle,
win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
except:
try:
self._close()
except:
# ignore any exception when closing the port
# also to keep original exception that happened when setting up
pass
self._port_handle = None
raise
else:
self.is_open = True
-----------#### rest of file removed for space------
回答1:
To answer 1) Because this relies on the hardware available, it is perfectly possible that the test code worked in the environment it was written on, but doesn't work in your environment - may be quite likely if you are on Windows and this was written on Linux. The code uses port 0 - don't know how that maps to COM1 etc.
2) On Windows, COM ports used to have DOS names like COM1, COM2 - i.e. A string, not an int (they aren't like TCP/IP port numbers). More recently in Windows there is the \\.\COMnotanumber format which allows a more generic name, I've seen these used by a USB to serial converter. Having had a quick look at the source code of pyserial SerialBase in serialutil.py, it's a bit odd IMO, because AFAICT self.name only gets set when you use an explicit port setting by calling self.port(portname). You might want to try intializing the serial port instance with serport = Serial(0) then explicitly calling serport.port('COM1') (or whatever your port name is instead of COM1).
回答2:
You may have the wrong version of serialwin32.py. I had the same error messages until I tried a different version. I am using 2.7 from here https://pypi.python.org/pypi/pyserial/2.7. Then I simply typed 'empl-client.py 8' and the error messages were gone. I also did not have the driver installed for the 'Embedded MotionApps' device. So, I found the eMPL_CDC.inf in the motion_driver_6.12 folder and installed it through device manager.
Now the problem I have is that the Embedded MotionApps device continuously connects and reconnects in Windows. Pygame is now running though but just sits there with a black screen. Invensense tell me that means it is connected and waiting for data.
It looks like there is data on the I2C bus and if the port would stay connected perhaps it might work. Though the data disappears from the bus when the port disconnects, so maybe the complete program is resetting. Actually there is a msp430_reset() function within the code and it does look like that is being called.
回答3:
The possibility to use numbers as ports has been removed in pySerial 3.x. Use device names (strings) instead, e.g. "/dev/ttyS0"
, "COM4"
etc.
Those numbers were not consistent across operating systems and sometimes did not even include all devices. You can use the serial.tools.list_port
module to enumerate actually available serial ports on most operating systems.
来源:https://stackoverflow.com/questions/34574311/pyserial-serialwin32-py-has-attribute-error