serialwin32.py and serialutil.py error when run In

2019-07-28 11:27发布

问题:

Good days, I'm new to python and trying to run a demo provided by Invensense.(9-axis MPU9250 connects a STM32F407G discovery board, I used code and python client in motion_driver_6.12 which downloaded from Invensense website.) the whole python part are python2.7, pysearil, pygame. I searched my issues in Stackoverflow, but the specific situations are a little different, and most of the solutions are useless for me. First, I show my issues.

UART connects the PC, run Invensense's python client through cmd.exe, pygame window appears briefly and disappear and I get the following error

D:\motion_driver_6.12\eMPL-pythonclient>python eMPL-client.py 7
Traceback (most recent call last):
File "eMPL-client.py", line 273, in <module>
def four_bytes(d1, d2, d3, d4):
File "eMPL-client.py", line 12, in __init__

File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 31, in 
__init__
super(Serial, self).__init__(*args, **kwargs)
File "C:\Python27\lib\site-packages\serial\serialutil.py", line 218, in 
__init__
self.port = port
File "C:\Python27\lib\site-packages\serial\serialutil.py", line 264, in port
raise ValueError('"port" must be None or a string, not 
{}'.format(type(port)))
ValueError: "port" must be None or a string, not <type 'int'>

Second, through the similar questions, what I have done until now:

  1. open the file "serialwin32.py" .Change port = self.name to port = str(self.name). It doesn't work, same error messages.
  2. uninstall the pyserial3.3(the lastest version), using a pyserial2.7. The error meesages were gone but Pygmae now just sits there with a black screen.The old answer said "Invensense tells me that means it is connected and waiting for data".

----------------followed is eMPL-client.py, line 21 and line 273 are marked-----

#!/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:
//*********************line 21 __init__ begins********************//
    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.
//**************************273 begins*********************************//
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

----------------followed is serialutil.py(version 3.3) from line1 to line272, 218 and 264 are marked-------------

#! python
#
# Base class and support functions used by various backends.
#
# This file is part of pySerial. https://github.com/pyserial/pyserial
# (C) 2001-2016 Chris Liechti <cliechti@gmx.net>
#
# SPDX-License-Identifier:    BSD-3-Clause

import io
import time

# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)``
# isn't returning the contents (very unfortunate). Therefore we need special
# cases and test for it. Ensure that there is a ``memoryview`` object for older
# Python versions. This is easier than making every test dependent on its
# existence.
try:
    memoryview
except (NameError, AttributeError):
    # implementation does not matter as we do not really use it.
    # it just must not inherit from something else we might care for.
    class memoryview(object):   # pylint: disable=redefined-builtin,invalid-name
        pass

try:
    unicode
except (NameError, AttributeError):
    unicode = str       # for Python 3, pylint: disable=redefined-builtin,invalid-name

try:
    basestring
except (NameError, AttributeError):
    basestring = (str,)    # for Python 3, pylint: disable=redefined-builtin,invalid-name


# "for byte in data" fails for python3 as it returns ints instead of bytes
def iterbytes(b):
    """Iterate over bytes, returning bytes instead of ints (python3)"""
    if isinstance(b, memoryview):
        b = b.tobytes()
    i = 0
    while True:
        a = b[i:i + 1]
        i += 1
        if a:
            yield a
        else:
            break


# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11'
# so a simple ``bytes(sequence)`` doesn't work for all versions
def to_bytes(seq):
    """convert a sequence to a bytes type"""
    if isinstance(seq, bytes):
        return seq
    elif isinstance(seq, bytearray):
        return bytes(seq)
    elif isinstance(seq, memoryview):
        return seq.tobytes()
    elif isinstance(seq, unicode):
        raise TypeError('unicode strings are not supported, please encode to bytes: {!r}'.format(seq))
    else:
        # handle list of integers and bytes (one or more items) for Python 2 and 3
        return bytes(bytearray(seq))


# create control bytes
XON = to_bytes([17])
XOFF = to_bytes([19])

CR = to_bytes([13])
LF = to_bytes([10])


PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S'
STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2)
FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)

PARITY_NAMES = {
    PARITY_NONE: 'None',
    PARITY_EVEN: 'Even',
    PARITY_ODD: 'Odd',
    PARITY_MARK: 'Mark',
    PARITY_SPACE: 'Space',
}


class SerialException(IOError):
    """Base class for serial port related exceptions."""


class SerialTimeoutException(SerialException):
    """Write timeouts give an exception"""


writeTimeoutError = SerialTimeoutException('Write timeout')
portNotOpenError = SerialException('Attempting to use a port that is not open')


class Timeout(object):
    """\
    Abstraction for timeout operations. Using time.monotonic() if available
    or time.time() in all other cases.

    The class can also be initialized with 0 or None, in order to support
    non-blocking and fully blocking I/O operations. The attributes
    is_non_blocking and is_infinite are set accordingly.
    """
    if hasattr(time, 'monotonic'):
        # Timeout implementation with time.monotonic(). This function is only
        # supported by Python 3.3 and above. It returns a time in seconds
        # (float) just as time.time(), but is not affected by system clock
        # adjustments.
        TIME = time.monotonic
    else:
        # Timeout implementation with time.time(). This is compatible with all
        # Python versions but has issues if the clock is adjusted while the
        # timeout is running.
        TIME = time.time

    def __init__(self, duration):
        """Initialize a timeout with given duration"""
        self.is_infinite = (duration is None)
        self.is_non_blocking = (duration == 0)
        self.duration = duration
        if duration is not None:
            self.target_time = self.TIME() + duration
        else:
            self.target_time = None

    def expired(self):
        """Return a boolean, telling if the timeout has expired"""
        return self.target_time is not None and self.time_left() <= 0

    def time_left(self):
        """Return how many seconds are left until the timeout expires"""
        if self.is_non_blocking:
            return 0
        elif self.is_infinite:
            return None
        else:
            delta = self.target_time - self.TIME()
            if delta > self.duration:
                # clock jumped, recalculate
                self.target_time = self.TIME() + self.duration
                return self.duration
            else:
                return max(0, delta)

    def restart(self, duration):
        """\
        Restart a timeout, only supported if a timeout was already set up
        before.
        """
        self.duration = duration
        self.target_time = self.TIME() + duration


class SerialBase(io.RawIOBase):
    """\
    Serial port base class. Provides __init__ function and properties to
    get/set port settings.
    """

    # default values, may be overridden in subclasses that do not support all values
    BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
                 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
                 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000,
                 3000000, 3500000, 4000000)
    BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS)
    PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE)
    STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO)

    def __init__(self,
                 port=None,
                 baudrate=9600,
                 bytesize=EIGHTBITS,
                 parity=PARITY_NONE,
                 stopbits=STOPBITS_ONE,
                 timeout=None,
                 xonxoff=False,
                 rtscts=False,
                 write_timeout=None,
                 dsrdtr=False,
                 inter_byte_timeout=None,
                 exclusive=None,
                 **kwargs):
        """\
        Initialize comm port object. If a "port" is given, then the port will be
        opened immediately. Otherwise a Serial port object in closed state
        is returned.
        """

        self.is_open = False
        self.portstr = None
        self.name = None
        # correct values are assigned below through properties
        self._port = None
        self._baudrate = None
        self._bytesize = None
        self._parity = None
        self._stopbits = None
        self._timeout = None
        self._write_timeout = None
        self._xonxoff = None
        self._rtscts = None
        self._dsrdtr = None
        self._inter_byte_timeout = None
        self._rs485_mode = None  # disabled by default
        self._rts_state = True
        self._dtr_state = True
        self._break_state = False
        self._exclusive = None

        # assign values using get/set methods using the properties feature
//**************218**************//
        self.port = port 
//**************218**************//
        self.baudrate = baudrate
        self.bytesize = bytesize
        self.parity = parity
        self.stopbits = stopbits
        self.timeout = timeout
        self.write_timeout = write_timeout
        self.xonxoff = xonxoff
        self.rtscts = rtscts
        self.dsrdtr = dsrdtr
        self.inter_byte_timeout = inter_byte_timeout
        self.exclusive = exclusive

        # watch for backward compatible kwargs
        if 'writeTimeout' in kwargs:
            self.write_timeout = kwargs.pop('writeTimeout')
        if 'interCharTimeout' in kwargs:
            self.inter_byte_timeout = kwargs.pop('interCharTimeout')
        if kwargs:
            raise ValueError('unexpected keyword arguments: {!r}'.format(kwargs))

        if port is not None:
            self.open()

    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

    # to be implemented by subclasses:
    # def open(self):
    # def close(self):

    #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

    @property
    def port(self):
        """\
        Get the current port setting. The value that was passed on init or using
        setPort() is passed back.
        """
        return self._port

    @port.setter
    def port(self, port):
        """\
        Change the port.
        """
//*************************line 263**********************//
        if port is not None and not isinstance(port, basestring):
            raise ValueError('"port" must be None or a string, not {}'.format(type(port)))
        was_open = self.is_open
        if was_open:
            self.close()
        self.portstr = port
        self._port = port
        self.name = self.portstr
        if was_open:
            self.open()

-------------followed is serialwin32.py(version 3.3), 31 is marked-----------------------------------------

#! python
#
# backend for Windows ("win32" incl. 32/64 bit support)
#
# (C) 2001-2015 Chris Liechti <cliechti@gmx.net>
#
# This file is part of pySerial. https://github.com/pyserial/pyserial
# SPDX-License-Identifier:    BSD-3-Clause
#
# Initial patch to use ctypes by Giovanni Bajo <rasky@develer.com>

# pylint: disable=invalid-name,too-few-public-methods
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):
        self._port_handle = None
        self._overlapped_read = None
        self._overlapped_write = None
//**************31**************//
        super(Serial, self).__init__(*args, **kwargs)
//**************31**************//

Questions:

  • Any ideas how to solve the error?
  • Anyone who has used the MPU9250 with STM32F407G discovery board? Any suggestion?
  • two related issues on Stackoverflow
  • issue one: visit pyserial serialwin32.py has attribute error
  • issue two: visit Invensense Motion Driver 6.12 STM32 demo python don't work

回答1:

Looking online, I found this Github repo that appears to correspond to the code you are working with. It appears eMPL-client.py is incompatible with newer versions of pyserial. Specifically, the __main__ routine requires numeric port identifiers, but the pyserial 3.3 serial.Serial requires textual port identifiers. I do not have the setup to test this, but you can try the following.

  1. Install a fresh copy of Python 2.7, which is what eMPL-client.py targets. This is unrelated to pyserial 2.7.
  2. In the fresh copy, install pyserial 2.7 and the other dependencies. Per the source, pyserial 2.7 uses numbers for ports. Pyserial 3.3 uses names for ports, whence the "port must be a string" error.

That should get you past the initial error, which is similar to this answer to the question you linked. At that point, it's probably time to pull out your oscilloscope and make sure the board is generating signals. If so, check the speed/baud/parity. I see that the source runs at 115200bps; maybe try 57600 instead, if your hardware supports it.

An alternative

To use eMPL-client.py with pyserial 3.3, in eMPL-client.py, look for the lines:

if __name__ == "__main__":
    if len(sys.argv) == 2:
        comport = int(sys.argv[1]) - 1      #### This is the line that triggers the issue
    else:
        print "usage: " + sys.argv[0] + " port"
        sys.exit(-1)

Change the ####-marked line to

        comport = sys.argv[1]

(make sure to keep the indentation the same!)

Then, in cmd.exe, run

python eMPL-client.py COM7

with the string port name, e.g., COM7, instead of a port number, e.g., 7.