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 __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 flush(self): ''' reset buffer ''' if self.buffered: self.data = [Buffer((self._emgBufSize, self.__numSensors)), \ Buffer((self._imuBufSize, self.__numSensors*self.__signalsPerImuSensor))] self.time = [Buffer((self._emgBufSize, 1)), \ Buffer((self._imuBufSize, 1))] else: self.data = [np.zeros((self.__numSensors,)), np.zeros((self.__numSensors*self.__signalsPerImuSensor,))] self.time = [np.zeros((1,)), np.zeros((1,))]
def __init__(self, buffered=True, host_ip='127.0.0.1', bufsize=1., samplesPerPacket=1, imu_type=None): self.host = host_ip self.dataPort = 50043 self.imuPort = 50044 self.sdkPort = 50040 self.emg = None self.imu = None self.sdk = None self.buffered = buffered self.bufsize = bufsize self.samplesPerPacket = samplesPerPacket self.imuType = 'raw' if imu_type is None else imu_type self.__numSensors = 16 self.__emgRate = 2000 self.__imuRate = 148.148148148148148148148148148148148148 self.__bytesPerSample = 4 self.__signalsPerEmgSensor = 1 if self.imuType == 'raw': self.__signalsPerImuSensor = 9 self.__signalsPerImuSensorTransmitted = 9 elif self.imuType == 'quat': self.__signalsPerImuSensor = 4 self.__signalsPerImuSensorTransmitted = 5 elif self.imuType == 'pry': self.__signalsPerImuSensor = 3 self.__signalsPerImuSensorTransmitted = 5 else: raise ValueError('Unrecognised type of IMU transmission.') if self.buffered: self._emgBufSize = int(np.ceil(self.__emgRate * self.bufsize)) self._imuBufSize = int(np.ceil(self.__imuRate * self.bufsize)) self.data = [Buffer((self._emgBufSize, self.__numSensors)), \ Buffer((self._imuBufSize, self.__numSensors * self.__signalsPerImuSensor))] self.time = [Buffer((self._emgBufSize, 1)), \ Buffer((self._imuBufSize, 1))] else: self.data = [np.zeros((self.__numSensors,)), \ np.zeros((self.__numSensors * self.__signalsPerImuSensor,))] self.time = [np.zeros((1, )), np.zeros((1, ))] self.exitFlag = True
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
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])))