if debug > 0: print("fsample", fsample) print("channels", channels) print("nchans", nchans) print("blocksize", blocksize) # switch from one-offset to zero-offset for i in range(nchans): channels[i]-=1; datatype = FieldTrip.DATATYPE_FLOAT32 ft_output.putHeader(nchans, float(fsample), datatype) try: # Connect to BITalino device = BITalino(device) except: print("Error: cannot connect to BITalino") exit() # Read BITalino version print((device.version())) # Set battery threshold device.battery(batterythreshold) # Start Acquisition device.start(fsample, channels) # Turn BITalino led on digitalOutput = [1,1]
def _start(): """Start the module This uses the global variables from setup and adds a set of global variables """ global parser, args, config, r, response, patch, name global monitor, debug, device, fsample, blocksize, channels, batterythreshold, nchans, startfeedback, countfeedback, ft_host, ft_port, ft_output, datatype, digitalOutput # this can be used to show parameters that have changed monitor = EEGsynth.monitor(name=name, debug=patch.getint("general", "debug")) # get the options from the configuration file debug = patch.getint("general", "debug") device = patch.getstring("bitalino", "device") fsample = patch.getfloat("bitalino", "fsample", default=1000) blocksize = patch.getint("bitalino", "blocksize", default=10) channels = patch.getint("bitalino", "channels", multiple=True) # these should be one-offset batterythreshold = patch.getint("bitalino", "batterythreshold", default=30) # switch from one-offset to zero-offset nchans = len(channels) for i in range(nchans): channels[i] -= 1 monitor.info("fsample = " + str(fsample)) monitor.info("channels = " + str(channels)) monitor.info("nchans = " + str(nchans)) monitor.info("blocksize = " + str(blocksize)) try: ft_host = patch.getstring("fieldtrip", "hostname") ft_port = patch.getint("fieldtrip", "port") monitor.success("Trying to connect to buffer on %s:%i ..." % (ft_host, ft_port)) ft_output = FieldTrip.Client() ft_output.connect(ft_host, ft_port) monitor.success("Connected to output FieldTrip buffer") except: raise RuntimeError("cannot connect to output FieldTrip buffer") datatype = FieldTrip.DATATYPE_FLOAT32 ft_output.putHeader(nchans, float(fsample), datatype) try: # Connect to BITalino device = BITalino(device) monitor.success((device.version())) except: raise RuntimeError("cannot connect to BITalino") # Set battery threshold device.battery(batterythreshold) # Start Acquisition device.start(fsample, channels) # Turn BITalino led on digitalOutput = [1, 1] device.trigger(digitalOutput) startfeedback = time.time() countfeedback = 0 # there should not be any local variables in this function, they should all be global if len(locals()): print("LOCALS: " + ", ".join(locals().keys()))
from bitalino import BITalino import pygame import pygame.mixer from pygame.locals import * import sys # ---------------------------------------- # デバイスの初期化 macAddress = "20:16:12:21:35:82" # MACアドレス samplingRate = 1000 # サンプリングレート acqChannels = [0] # 取得チャネル(A1) nSamples = 100 # 取得サンプル数 device = BITalino(macAddress) # デバイスの取得 print(device.version()) device.start(samplingRate, acqChannels) # データ取得開始 # ---------------------------------------- # ---------------------------------------- # 信号の取得 def selected(): BITS = 10 # 信号のビット幅 VCC = 3.3 # 操作電圧 GAIN = 1009 # センサーゲイン THRESHOLD = 0.3 # 閾値 data = device.read(nSamples) emg = (((((data[:,5] / 2**BITS) - 1/2) * VCC) / GAIN) * 1000) # 単位変換(mV)
def __init__(self, port, rate=1000, channels=("A1", "A2", "A3", "A4", "A5", "A6")): # Check port if not port.startswith("/dev/") and not port.startswith("COM"): raise ValueError(f"Invalid serial port: {port}") # Check rate if rate not in (1, 10, 100, 1000): raise ValueError(f"Invalid rate: {rate}") # Check channels unique_channels = set(channels) analog_channels = ["A1", "A2", "A3", "A4", "A5", "A6"] channels = [] for channel_num, channel_name in enumerate(analog_channels): if channel_name in unique_channels: channels.append(channel_num) # Set column names # Sequence number and numeric channels are always present self.columns = ["SEQ", "I1", "I2", "O1", "O2"] # Add required analog channels for channel in channels: self.columns.append(analog_channels[channel]) # Compute the sample size in bytes self.channel_count = len(channels) if self.channel_count <= 4: self.sample_size = int( np.ceil((12.0 + 10.0 * self.channel_count) / 8.0)) else: self.sample_size = int( np.ceil((52.0 + 6.0 * (self.channel_count - 4)) / 8.0)) # Connect to BITalino try: self.device = BITalino(port) except UnicodeDecodeError: # This can happen after an internal buffer overflow. # The solution seems to power off the device and repair. raise WorkerInterrupt("Unstable state. Could not connect.") except Exception as e: raise WorkerInterrupt(e) # Set battery threshold # The red led will light up at 5-10% self.device.battery(30) # Read BITalino version self.logger.info(self.device.version()) # Read state and show battery level # http://forum.bitalino.com/viewtopic.php?t=448 state = self.device.state() battery = round( 1 + (state["battery"] - 511) * ((99 - 1) / (645 - 511)), 2) self.logger.info("Battery: %.2f%%", battery) # Start Acquisition self.device.start(rate, channels) # Initialize counters for timestamp indices and continuity checks self.last_sample_counter = 15 self.time_device = np.datetime64(int(time.time() * 1e6), "us") self.time_local = self.time_device self.time_delta = np.timedelta64(int(1000 / rate), "ms") # Set meta self.meta = {"rate": rate}
class Bitalino(Node): """BITalino driver. This node connects to a BITalino device and streams data at a provided rate. It is based on the original BITalino Python library, with some performance improvements and careful timestamping. Two output streams are provided. The default output is the data read from the analog and digital channels. The ``o_offsets`` output provides continuous offsets between the local time and the estimated device time. This enables drift correction to be performed during post-processing, although no significant drift has been observed during testing. Attributes: o (Port): BITalino data, provides DataFrame. o_offsets (Port): Time offsets, provide DataFrame. Args: port (string): The serial port. e.g. ``COM3`` on Windows; ``/dev/tty.bitalino-DevB`` on MacOS; ``/dev/ttyUSB0`` on GNU/Linux. rate (int): The device rate in Hz. Possible values: ``1``, ``10``, ``100``, ``1000``. Default: ``1000``. channels (tupple): The analog channels to read from. Default: ``('A1', 'A2', 'A3', 'A4', 'A5', 'A6')``. Example: .. literalinclude:: /../examples/bitalino.yaml :language: yaml Notes: .. attention:: Make sure to set your graph rate to an high-enough value, otherwise the device internal buffer may saturate, and data may be lost. A 30Hz graph rate is recommended for a 1000Hz device rate. """ def __init__(self, port, rate=1000, channels=("A1", "A2", "A3", "A4", "A5", "A6")): # Check port if not port.startswith("/dev/") and not port.startswith("COM"): raise ValueError(f"Invalid serial port: {port}") # Check rate if rate not in (1, 10, 100, 1000): raise ValueError(f"Invalid rate: {rate}") # Check channels unique_channels = set(channels) analog_channels = ["A1", "A2", "A3", "A4", "A5", "A6"] channels = [] for channel_num, channel_name in enumerate(analog_channels): if channel_name in unique_channels: channels.append(channel_num) # Set column names # Sequence number and numeric channels are always present self.columns = ["SEQ", "I1", "I2", "O1", "O2"] # Add required analog channels for channel in channels: self.columns.append(analog_channels[channel]) # Compute the sample size in bytes self.channel_count = len(channels) if self.channel_count <= 4: self.sample_size = int( np.ceil((12.0 + 10.0 * self.channel_count) / 8.0)) else: self.sample_size = int( np.ceil((52.0 + 6.0 * (self.channel_count - 4)) / 8.0)) # Connect to BITalino try: self.device = BITalino(port) except UnicodeDecodeError: # This can happen after an internal buffer overflow. # The solution seems to power off the device and repair. raise WorkerInterrupt("Unstable state. Could not connect.") except Exception as e: raise WorkerInterrupt(e) # Set battery threshold # The red led will light up at 5-10% self.device.battery(30) # Read BITalino version self.logger.info(self.device.version()) # Read state and show battery level # http://forum.bitalino.com/viewtopic.php?t=448 state = self.device.state() battery = round( 1 + (state["battery"] - 511) * ((99 - 1) / (645 - 511)), 2) self.logger.info("Battery: %.2f%%", battery) # Start Acquisition self.device.start(rate, channels) # Initialize counters for timestamp indices and continuity checks self.last_sample_counter = 15 self.time_device = np.datetime64(int(time.time() * 1e6), "us") self.time_local = self.time_device self.time_delta = np.timedelta64(int(1000 / rate), "ms") # Set meta self.meta = {"rate": rate} def update(self): # Send BITalino data data, timestamps = self._read_all() self.o.set(data, timestamps, self.columns, self.meta) # Send time offsets if len(timestamps) > 0: offset = (self.time_local - self.time_device).astype(int) self.o_offsets.set( [[self.time_device, offset]], [self.time_local], ["time_device", "time_offset"], ) def _read_all(self): """Read all available data""" # Make sure the device is in aquisition mode if not self.device.started: raise Exception(ExceptionCode.DEVICE_NOT_IN_ACQUISITION) # We only support serial connections if not self.device.serial: raise Exception("Device must be opened in serial mode.") # Check buffer size and limits buffer_size = self.device.socket.in_waiting if buffer_size == 1020: # The device buffer can hold up to 1020 bytes self.logger.warn( "OS serial buffer saturated. Increase graph rate or decrease device rate." ) # Compute the maximum number of samples we can get sample_count = int(buffer_size / self.sample_size) # Infer timestamps from sample count and rate # Will fail dramatically if too much packets are lost # Tests show that there is no significant drift during a 2-hour session start = self.time_device stop = start + self.time_delta * sample_count self.time_device = stop timestamps = np.arange(start, stop, self.time_delta) self.time_local = np.datetime64(int(time.time() * 1e6), "us") # Infer timestamps from local time and rate # /!\ Not monotonic # stop = np.datetime64(int(time.time() * 1e6), 'us') # start = stop - (sample_count * self.time_delta) # timestamps = np.arange(start, stop, self.time_delta) # Read raw samples from device raw = self.device.socket.read(sample_count * self.sample_size) # Initialize the output matrix data = np.full((sample_count, 5 + self.channel_count), np.nan) # Parse the raw data # http://bitalino.com/datasheets/REVOLUTION_MCU_Block_Datasheet.pdf for sample_number in range(sample_count): # Extract sample start = sample_number * self.sample_size stop = start + self.sample_size sample = list( struct.unpack(self.sample_size * "B ", raw[start:stop])) # Is the sample corrupted? crc = sample[-1] & 0x0F sample[-1] = sample[-1] & 0xF0 x = 0 for i in range(self.sample_size): for bit in range(7, -1, -1): x = x << 1 if x & 0x10: x = x ^ 0x03 x = x ^ ((sample[i] >> bit) & 0x01) if crc != x & 0x0F: self.logger.warn("Checksum failed.") continue # Parse sample data[sample_number, 0] = sample[-1] >> 4 data[sample_number, 1] = sample[-2] >> 7 & 0x01 data[sample_number, 2] = sample[-2] >> 6 & 0x01 data[sample_number, 3] = sample[-2] >> 5 & 0x01 data[sample_number, 4] = sample[-2] >> 4 & 0x01 if self.channel_count > 0: data[sample_number, 5] = ((sample[-2] & 0x0F) << 6) | (sample[-3] >> 2) if self.channel_count > 1: data[sample_number, 6] = ((sample[-3] & 0x03) << 8) | sample[-4] if self.channel_count > 2: data[sample_number, 7] = (sample[-5] << 2) | (sample[-6] >> 6) if self.channel_count > 3: data[sample_number, 8] = ((sample[-6] & 0x3F) << 4) | (sample[-7] >> 4) if self.channel_count > 4: data[sample_number, 9] = ((sample[-7] & 0x0F) << 2) | (sample[-8] >> 6) if self.channel_count > 5: data[sample_number, 10] = sample[-8] & 0x3F # Did we miss any sample? # Check for discontinuity in the internal sample counter, encoded to 4 bits. sample_counter = data[sample_number, 0] if sample_counter == self.last_sample_counter + 1: pass elif sample_counter == 0 and self.last_sample_counter == 15: pass else: self.logger.warn("Missed sample.") self.last_sample_counter = sample_counter return data, timestamps def terminate(self): self.device.stop() self.device.close()
except: try: i = sys.argv.index("-o") filename = sys.argv[i + 1] except: filename = "PyBitSignals_" + re.sub( ':', '', macAddress) + "_" + time.strftime("%Y-%m-%d_%H-%M-%S") + ".txt" print("Using default filename:\n" + filename) # Setting other attributes batteryThreshold = 30 # Connect to BITalino print("\nConnecting to BITalino using MAC Address: " + macAddress) device = BITalino(macAddress) print("\nDevice Connected.\n") # Set battery threshold device.battery(batteryThreshold) # Read BITalino version print("Device Version: " + str(device.version())) # Show channels monitored print("Monitoring channels: " + str(acqChannels)) # Show sampling rate print("Sampling Rate: " + str(samplingRate) + " Hz.\n") # Start Acquisition
# 2 - EDA # 3 - EEG # 4 - ACC # 5 - LUX acqChannels = [1, 2, 4] columns = [ "seq_num", "digital_0", "digital_1", "digital_2", "digital_3", "ecg", "eda", "acc" ] samplingRate = 1000 nSamples = 100 digitalOutput = [1, 1] # Connect to BITalino device = BITalino(macAddress) # Set battery threshold device.battery(batteryThreshold) # Read BITalino version print(device.version()) # Start Acquisition device.start(samplingRate, acqChannels) start = time.time() end = time.time() collected_data = [] while (end - start) < running_time:
class BITalinoProcess(Process): """ BITalino acquisition process. """ def __init__(self, outQueue, goFlag, acqFlag, mac=None, channels=[0], step=100, SamplingRate=1000, timeout=5, bitCls=None): # run parent __init__ super(BITalinoProcess, self).__init__() # synchronization inputs self.queue = outQueue self.go = goFlag self.acq = acqFlag # BITalino settings self.mac = mac self.channels = channels self.step = step self.SamplingRate = int(SamplingRate) if bitCls is None: self.device = BITalino() else: self.device = bitCls() # trigger stuff c1, c2 = Pipe() self._outerPipe = c1 self._innerPipe = c2 self._trigout = 2 * self.step / float(self.SamplingRate) # timeout self.timeout = timeout @classmethod def instaStart(cls, *args, **kwargs): # do some class method magic here to instantiate and start the process outQueue = Queue() goFlag = Event() goFlag.set() acqFlag = Event() p = cls(outQueue, goFlag, acqFlag, *args, **kwargs) p.start() return p, outQueue, goFlag, acqFlag def _checkTrigger(self): # check if there is a trigger to act on if self._innerPipe.poll(): data = self._innerPipe.recv() try: mask = data['Mask'] except KeyError: # report failure self._innerPipe.send({'Ack': False}) else: # trigger self.device.trigger(mask) # report success self._innerPipe.send({'Ack': True}) def trigger(self, data=[0, 0, 0, 0]): # act on digital outputs if not self.acq.is_set(): return False # send mask self._outerPipe.send({'Mask': data}) # wait for ack if self._outerPipe.poll(self._trigout): out = self._outerPipe.recv() return out['Ack'] else: return False def connect(self): # connect to BITalino if self.device.open(self.mac, self.SamplingRate): time.sleep(1.5) print "successful" return True else: print "failed" return False def setup(self): # setup bitalino print "connecting to %s: " % self.mac while self.go.is_set(): if self.connect(): return True time.sleep(1.5) return False def on_start(self): # run immediately after acquisition starts pass def exit(self): # exit process self.acq.clear() self.go.clear() def processData(self, data): # process received data # send data self.queue.put(data) def on_stop(self): # run immediately before acquisition stops pass def run(self): # main loop # connect to device, proceed if successful if self.setup(): while self.go.is_set(): # wait for acquisition flag print "Waiting" self.acq.wait(timeout=self.timeout) if self.acq.is_set(): # start acquisition self.device.start(self.channels) # time.sleep(1) print "acquiring" self.on_start() while self.acq.is_set(): # read data data = self.device.read(self.step) # process data self.processData(data) # check trigger self._checkTrigger() # clean up self.on_stop() self.queue.put('') # stop acquisition self.device.stop() # print "blocked" print "acquisition stopped" # disconnect device self.device.close() print "disconnected"
# coding: utf_8 from bitalino import BITalino macAddress = "20:16:12:21:35:82" # MACアドレス device = BITalino(macAddress) # デバイスの取得 print(device.version()) # バージョンの表示 samplingRate = 1000 # サンプリングレート acqChannels = [0] # 取得チャネル(A1) nSamples = 10 # 取得サンプル数 device.start(samplingRate, acqChannels) # データ取得開始 data = device.read(nSamples) print(data) device.stop() device.close()
def launch_acquisition(msg): global isAcquiring, data, npending, stime isAcquiring = 1 macAddress = msg['payload']['macAddress'] # This example will collect data for 5 sec. running_time = 9 batteryThreshold = 30 acqChannels = [0, 1, 2, 3, 4, 5] samplingRate = 1000 nSamples = 10 digitalOutput = [1, 1] # Connect to BITalino device = BITalino(macAddress) # Set battery threshold device.battery(batteryThreshold) # Read BITalino version print(device.version()) # ON/OFF device.trigger([1, 1]) device.trigger([0, 0]) # Start Acquisition device.start(samplingRate, acqChannels) start = time.time() end = time.time() while (end - start) < running_time and isAcquiring == 1: # Read samples data = device.read(nSamples) print(data) msg['payload']['val'] = data.tolist() end = time.time() # Stop acquisition device.stop() # Close connection device.close() isAcquiring = 0 return ("success")
macAddress = "98:D3:31:B2:12:01" #macAddress = "98:D3:31:70:3D:CE" batteryThreshold = 30 acqChannels = [0,1,2,3,4,5] defaultChannel=4; samplingRate = 100 nSamples = 1 digitalOutput = [1,1,0,0] # Connect to BITalino connection=0 while connection is 0: try: print "connecting to BITalino(%s)..." %macAddress device = BITalino(macAddress) connection=1; break except TypeError: print "MAC address (%s) is not defined..." %macAddress print "connecting to BITalino(%s)..." except ValueError: print "MAC address (%s) is not defined..." %macAddress print "connecting to BITalino(%s)..." # Set battery threshold device.battery(batteryThreshold) # Read BITalino version print device.version() print "connected to BITalino(%s)" %macAddress print "creating Signal stream..."
ftc_port = patch.getint('fieldtrip', 'port') if debug > 0: print('Trying to connect to buffer on %s:%i ...' % (ftc_host, ftc_port)) ft_output = FieldTrip.Client() ft_output.connect(ftc_host, ftc_port) if debug > 0: print("Connected to output FieldTrip buffer") except: raise RuntimeError("cannot connect to output FieldTrip buffer") datatype = FieldTrip.DATATYPE_FLOAT32 ft_output.putHeader(nchans, float(fsample), datatype) try: # Connect to BITalino device = BITalino(device) except: raise RuntimeError("cannot connect to BITalino") # Read BITalino version print((device.version())) # Set battery threshold device.battery(batterythreshold) # Start Acquisition device.start(fsample, channels) # Turn BITalino led on digitalOutput = [1, 1] device.trigger(digitalOutput)
def connect(self): device = BITalino(self.MAC_ADDRESS) # Read BITalino version print("Connected to Device") print(device.version()) return device
rospy.init_node("bitalino") coco_data_pub = rospy.Publisher("/bitalino/cocontraction", Float32, queue_size=10) dir_data_pub = rospy.Publisher("/bitalino/direction", Float32, queue_size=10) # dir_data_pub = rospy.Publisher("/bitalino/direction", Float32, queue_size=10) macAddress = "20:16:07:18:15:11" # Bitalino setup batteryThreshold = 30 acqChannels = [2, 3] samplingRate = 1000 nSamples = 50 device = BITalino(macAddress) device.battery(batteryThreshold) rospy.loginfo(device.version()) device.start(samplingRate, acqChannels) msg = Float32() cocontract_data = 0 direction_data = 0 rospy.on_shutdown(clean_shutdown) rospy.loginfo("Finding neutral direction signal") max_cnt = 100 for i in range(0, max_cnt): # Read samples data = device.read(nSamples) # data = data[:] data = np.transpose(data)