Beispiel #1
0
class CyberGlove(object):
    """Interface the Cyberglove via a serial port. 
        
        Parameters (TODO)
        ----------
        s_port : str, optional, default: None
            Serial port name (e.g., 'COM1' in Windows). If set to None, the 
            first one available will be used.
        
        baud_rate : int, optional, default: 115200
            Baud rate.
        
            
        Attributes
        ----------
        
        TODO
        
    """
    def __init__(self,
                 n_df=None,
                 s_port=None,
                 baud_rate=115200,
                 buffered=True,
                 buf_size=1.,
                 calibration_file=None):

        # If n_df is not given assume 18-DOF Cyberglove but issue warning
        if n_df == None:
            warnings.warn("Cyberglove: number of DOFs not given, assuming 18.")
            self.n_df = 18
        else:
            if n_df not in [18, 22]:
                raise ValueError(
                    "Cyberglove can have either 18 or 22 degrees-of-freedom.")
            else:
                self.n_df = n_df

        # if port is not given use the first one available
        if s_port == None:
            try:
                s_port = serial.tools.list_ports.comports().next()[0]
            except StopIteration:
                print("No serial ports found.")

        self.si = serial.Serial(port=None,
                                baudrate=baud_rate,
                                timeout=0.05,
                                writeTimeout=0.05)
        self.si.port = s_port
        self.buffered = buffered
        self.buf_size = buf_size
        self.calibration_file = calibration_file

        self.__srate = 100  # Hardware sampling rate. TODO: Double-check this is correct
        if self.n_df == 18:
            self.__bytesPerRead = 20  # First and last bytes are reserved
        elif self.n_df == 22:
            self.__bytesPerRead = 24  # First and last bytes are reserved

        if self.buffered:
            self.__buf_size_samples = int(np.ceil(self.__srate *
                                                  self.buf_size))
            self.data = Buffer((self.__buf_size_samples, self.n_df))
            self.time = Buffer((self.__buf_size_samples, ))
        else:
            self.data = np.zeros((self.n_df, ))
            self.time = np.zeros((1, ))

        if self.calibration_file is None:
            self.calibration_ = False
        else:
            self.calibration_ = True
            (self.calibration_offset_,
             self.calibration_gain_) = load_calibration_file(
                 calibration_file, self.n_df)

    def __repr__(self):
        """TODO"""
        raise NotImplementedError

    def __str__(self):
        """TODO"""
        raise NotImplementedError

    def __del__(self):
        """Call stop() on destruct."""
        self.stop()

    def start(self):
        """Open port and perform check."""
        self.__networking = True
        self.si.open()
        self._startTime_ = timeit.default_timer()
        self.si.flushOutput()
        self.si.flushInput()
        thread.start_new_thread(self.networking, ())

    def stop(self):
        """Close port."""
        self.__networking = False
        time.sleep(
            0.1
        )  # Wait 100 ms before closing the port just in case data are being transmitted
        self._stopTime_ = timeit.default_timer()
        if self.si.isOpen():
            self.si.flushInput()
            self.si.flushOutput()
            self.si.close()

    def networking(self):
        while self.__networking:
            data = self.raw_measurement()
            if self.calibration_ is True:
                data = calibrate_data(data, self.calibration_offset_,
                                      self.calibration_gain_)
            timestamp = np.asarray([timeit.default_timer()])

            if self.buffered is True:
                self.data.push(data)
                self.time.push(timestamp)
            else:
                self.data = data
                self.time = timestamp
            time.sleep(1. / self.__srate
                       )  # Wait 10 ms until before sending the next command

    def raw_measurement(self):
        """Performs a single measurment read from device (all sensor values). 
        If this fails, it tries again.
        Returns the raw data (after reserved bytes have been removed).
        """

        fmt = '@' + "B" * self.__bytesPerRead  # Format for unpacking binary data
        self.si.flushInput()
        raw_measurement = None
        while raw_measurement is None:
            nb = self.si.write(bytes('\x47'))
            if nb == 1:
                msg = self.si.read(size=self.__bytesPerRead)
                if len(msg) is self.__bytesPerRead:
                    raw_measurement = struct.unpack(fmt, msg)
                    raw_measurement = np.asarray(raw_measurement)
        return raw_measurement[1:-1]  # First and last bytes are reserved
Beispiel #2
0
class MovingAverage(object):
    """Moving average smoother. 
    
    Parameters
    ----------
    
    shape : tuple
        Shape of signal to be smoothed.
    
    k : integer
        Number of windows to use for smoothing.
        
    weights : array, optional (default ones), shape = (k,)
        Weight vector. First element corresponds to weight for most recent
        observation.
        
    """
    
    def __init__(self, shape, k, weights=None):
        
        self.shape = shape
        self.__check_k_weights(k, weights)
        self.k = k 
        self.weights = np.ones((k,)) if weights is None else weights
        self.buffer_ = Buffer(size=self.__get_buf_size())
        
    def smooth(self, x):
        
        """Smooths data in x.
        
        Parameters
        ----------
        
        x : array
            Most recent raw measurement.
        
        Returns
        -------
        
        x_smoothed : array
            Smoothed measurement.
            
        """
        
        self.buffer_.push(x)
        return np.dot(np.flipud(self.weights), self.buffer_.buffer) / self.k
    
    def __check_k_weights(self, k, weights):
        
        if not isinstance(k, int):
            raise ValueError("k must be integer.")
            
        if weights is not None:
            weights = np.asarray(weights)
            if weights.ndim != 1 or weights.size != k:
                raise ValueError("Weight array must have shape ({},)".format(k))

    def __get_buf_size(self):
        """Returns a flattened tuple to be used as the buffer size."""
        
        return tuple(np.append(self.k, 
                               np.asarray([element for element in self.shape])))