├── myo32.dll ├── myo64.dll ├── hello-myo.exe ├── multiple-myos.exe ├── emg-data-sample.exe ├── myo ├── Var.py ├── platform.py ├── six.py ├── tools.py ├── enum.py ├── __init__.py └── lowlevel.py ├── terminate.m ├── pyquit.m ├── terminate.py ├── LICENSE ├── MATLAB_LICENSE ├── PYTHON_LICENSE └── MYOSDK_LICENSE.txt ├── init_python.m ├── README.md ├── myo_workfile.m ├── python.m ├── getEmg.py ├── getPose.py ├── getOrient.py ├── getAccel.py ├── getGyro.py ├── getAllData.py └── Myo.m /myo32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yijuilee/myomatlab/HEAD/myo32.dll -------------------------------------------------------------------------------- /myo64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yijuilee/myomatlab/HEAD/myo64.dll -------------------------------------------------------------------------------- /hello-myo.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yijuilee/myomatlab/HEAD/hello-myo.exe -------------------------------------------------------------------------------- /multiple-myos.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yijuilee/myomatlab/HEAD/multiple-myos.exe -------------------------------------------------------------------------------- /emg-data-sample.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yijuilee/myomatlab/HEAD/emg-data-sample.exe -------------------------------------------------------------------------------- /myo/Var.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | sys.path.append(os.path.join('path','to','myo-python')) 3 | -------------------------------------------------------------------------------- /terminate.m: -------------------------------------------------------------------------------- 1 | %% Terminate all background Python scripts 2 | % Returns error for catch block response 3 | python('terminate.py') 4 | exit -------------------------------------------------------------------------------- /pyquit.m: -------------------------------------------------------------------------------- 1 | %% Opens new MATLAB session and terminates all background Python scripts 2 | % Does not force an error for catch block response 3 | eval('!matlab -nodesktop -nosplash -minimize -r ", try, terminate, catch, exit, end" &') -------------------------------------------------------------------------------- /terminate.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Niklas Rosenstein 2 | # All rights reserved. 3 | 4 | #import sys 5 | #sys.exit() 6 | #this does not kill python scripts across different interpreter ?? 7 | 8 | import os 9 | os.system('taskkill /f /im python.exe') 10 | 11 | 12 | -------------------------------------------------------------------------------- /myo/platform.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Niklas Rosenstein 2 | # All rights reserved. 3 | 4 | from __future__ import absolute_import 5 | 6 | import os 7 | import sys 8 | import platform as _platform 9 | 10 | def select(): 11 | arch = 'x64' if sys.maxsize > (2 ** 32) else 'x86' 12 | platform = _platform.platform().split('-')[0] 13 | 14 | if platform.startswith('Windows'): 15 | result = 'Windows' 16 | elif platform.startswith('Darwin'): 17 | result = 'Darwin' 18 | else: 19 | raise EnvironmentError('unsupported platform %s' % platform) 20 | 21 | return result, arch 22 | 23 | platform, arch = select() 24 | 25 | -------------------------------------------------------------------------------- /LICENSE/MATLAB_LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Yi Jui Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LICENSE/PYTHON_LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Niklas Rosenstein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /init_python.m: -------------------------------------------------------------------------------- 1 | % ####################################################################### 2 | % 3 | % Authored by Yi Jui Lee 4 | % 5 | % Tested on MATLAB 2013a, Python 2.7 6 | % 7 | % *********************************************************************** 8 | % Filename : init_python.m 9 | % Depends on Myo.m official development version 10 | % 11 | % Version 1 (15 August 2015) 12 | % *********************************************************************** 13 | 14 | %% Execute Python script corresponding to the call function 15 | 16 | if exist('r1','var') 17 | if r1 == 1 18 | r1 = 0; 19 | python('getAccel.py') 20 | exit 21 | end 22 | elseif exist('r2','var') 23 | if r2 == 1 24 | r2 = 0; 25 | python('getGyro.py') 26 | exit 27 | end 28 | elseif exist('r3','var') 29 | if r3 == 1 30 | r3 = 0; 31 | python('getOrient.py') 32 | exit 33 | end 34 | elseif exist('r4','var') 35 | if r4 == 1 36 | r4 = 0; 37 | python('getPose.py') 38 | exit 39 | end 40 | elseif exist('r5','var') 41 | if r5 == 1 42 | r5 = 0; 43 | python('getEmg.py') 44 | exit 45 | end 46 | elseif exist('r6','var') 47 | if r6 == 1 48 | r6 = 0; 49 | python('getAllData.py') 50 | exit 51 | end 52 | end 53 | exit -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # myomatlab 2 | 3 | Myo MATLAB Data Streaming Interface. Version 1 (August 15, 2015) 4 | 5 | Tested on Window 7, Windows 8 6 | 7 | MATLAB 2013a, Python 2.7.9, myo-sdk-win-0.9.0 8 | 9 | This is the simplified source code for the Myo Sphero MATLAB Interface (https://www.youtube.com/watch?v=E3m9V6yv0do) 10 | 11 | The Myo MATLAB data streaming interface relies on real time data read from the text files updated by Python. Python is used to communicate with Myo Connect/Myo. Special thanks to NiklasRosenstein and the contributors to the Python interface (https://github.com/NiklasRosenstein/myo-python). 12 | 13 | 1. Download Python 2.7.9 (Other version of Python have not been tested for the interface). 14 | 2. Make sure to check include Python in your path during the installation. 15 | 3. Download Myo Connect. 16 | 4. Please follow the steps prompted on Myo Connect if Myo is not added to the application. 17 | 5. Run the Myo interface (Refer to myo_workfile.m for the working examples and Myo.m for the source). 18 | 19 | Important note: 20 | - This version is tested on Python 2.7. If other versions of Python were used or the Python directory is installed in a custom directory, please update the python.m code in line 63 to match the appropriate directory of Python in your drive. (Other Python versions has not been tested for this interface.) 21 | - Please ensure that Myo Connect is on and running while the interface is running. 22 | - As of this version (Version 1), the MATLAB function, pyquit terminates all existing Python processes. 23 | -------------------------------------------------------------------------------- /myo/six.py: -------------------------------------------------------------------------------- 1 | """Utilities for writing code that runs on Python 2 and 3""" 2 | 3 | # Copyright (C) 2014 Niklas Rosenstein 4 | # All rights reserved. 5 | r""" 6 | myo.six - minimalistic Python 2/3 compatibility layer 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | This is a minimalistic clone of the original *six* module 10 | with focus on the Python 3 style. 11 | 12 | .. seealso:: https://pypi.python.org/pypi/six 13 | """ 14 | 15 | import sys 16 | PY2 = sys.version_info[0] < 3 17 | PY3 = not PY2 18 | 19 | if PY2: 20 | #print('Using Python 2') 21 | string_types = (basestring,) 22 | 23 | range = xrange 24 | def print_(*args, **kwargs): 25 | r""" print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) 26 | 27 | Prints the values to a stream, or to sys.stdout by default. 28 | Optional keyword arguments: 29 | file: a file-like object (stream); defaults to the current sys.stdout. 30 | sep: string inserted between values, default a space. 31 | end: string appended after the last value, default a newline. 32 | flush: whether to forcibly flush the stream. """ 33 | 34 | sep = kwargs.pop('sep', ' ') 35 | end = kwargs.pop('end', '\n') 36 | file_ = kwargs.pop('file', sys.stdout) 37 | flush = kwargs.pop('flush', False) 38 | 39 | for arg in args[:-1]: 40 | file_.write(str(arg)) 41 | file_.write(str(sep)) 42 | 43 | if args: 44 | file_.write(str(args[-1])) 45 | file_.write(str(end)) 46 | if flush and hasattr(file_, 'flush'): 47 | file_.flush() 48 | else: 49 | #('Using Python 3') 50 | string_types = (str, bytes) 51 | 52 | range = __builtins__['range'] 53 | print_ = __builtins__['print'] 54 | 55 | def with_metaclass(meta, *bases): 56 | """Create a base class with a metaclass.""" 57 | # This requires a bit of explanation: the basic idea is to make a dummy 58 | # metaclass for one level of class instantiation that replaces itself with 59 | # the actual metaclass. 60 | class metaclass(meta): 61 | def __new__(cls, name, this_bases, d): 62 | return meta(name, bases, d) 63 | return type.__new__(metaclass, 'temporary_class', (), {}) 64 | -------------------------------------------------------------------------------- /myo_workfile.m: -------------------------------------------------------------------------------- 1 | %% Simple demo for the Myo MATLAB interface 2 | % ####################################################################### 3 | % 4 | % Authored by Yi Jui Lee 5 | % 6 | % Tested on MATLAB 2013a, Python 2.7 7 | % 8 | % *********************************************************************** 9 | % 10 | % Filename : myo_workfile.m 11 | % Depends on Myo.m official development version 12 | % 13 | % Version 1 (15 August 2015) 14 | % 15 | % *********************************************************************** 16 | % 17 | % Please refer to Myo's API and SDK Portal to learn more about the device 18 | 19 | %% Create Myo Object 20 | % Instantiates Myo object 21 | if exist('m') == 1 22 | clear 23 | end 24 | m = Myo(); 25 | 26 | %% Get Data Types 27 | % The sampling rate requested does not represent the true sampling rate of 28 | % the data stream. 29 | % For the purpose of demonstration, a plot function is called for each data 30 | % type. 31 | 32 | %% Get acceleration data in real time 33 | % acceleration is given in 3 axis 34 | % units in g 35 | close all 36 | m.getAcceleration(); 37 | 38 | %% Get gyro data in real time 39 | % gyroscope is given as the rate of rotation in 3 axis 40 | % units in deg/s 41 | close all 42 | m.getGyroscope(); 43 | 44 | %% Get orientation data in real time 45 | % Python interface returns quaternions x,y,z,w 46 | % Myo.m utilizes quat2angle to convert the quaternions to euler angles 47 | % roll pitch yaw units in radians 48 | close all 49 | m.getOrientation(); 50 | 51 | %% Get gestural data in real time 52 | % Please perform sync calibration (sync status will be indicated on Myo 53 | % Connect) 54 | % Gets predefined gestures 55 | % gesture statuses are fist, rest, waveout, wavein, fingerspread, doubletap 56 | close all 57 | m.getPose(); 58 | 59 | %% Get emg data in real time 60 | % Gets raw EMG data from the 8 pods on the Myo armband 61 | % Represents "activation" of the pods 62 | % unitless value from -127 to 127 63 | close all 64 | m.getEmg(); 65 | 66 | %% Get all data simultaneously in real time 67 | % Returns all 5 types of data simultaneously 68 | % Performance depends on various factors (machine computing speed, memory, 69 | % etc.) 70 | close all 71 | m.getAllData(); 72 | 73 | %% Get all data post-use 74 | % Acquires all 5 data types in post operation mode 75 | % The data can be acquired using the next method (see below) 76 | m.getPostData(); 77 | 78 | %% Data can be accessed through the Myo object (post-use) 79 | acceleration = m.acceleration; 80 | gyroscope = m.gyroscope; 81 | orientation = m.orientation; 82 | pose = m.pose; 83 | emg = m.emg; 84 | 85 | -------------------------------------------------------------------------------- /python.m: -------------------------------------------------------------------------------- 1 | function [result, status] = perl(varargin) 2 | %PERL Execute Perl command and return the result. 3 | % PERL(PERLFILE) calls perl script specified by the file PERLFILE 4 | % using appropriate perl executable. 5 | % 6 | % PERL(PERLFILE,ARG1,ARG2,...) passes the arguments ARG1,ARG2,... 7 | % to the perl script file PERLFILE, and calls it by using appropriate 8 | % perl executable. 9 | % 10 | % RESULT=PERL(...) outputs the result of attempted perl call. If the 11 | % exit status of perl is not zero, an error will be returned. 12 | % 13 | % [RESULT,STATUS] = PERL(...) outputs the result of the perl call, and 14 | % also saves its exit status into variable STATUS. 15 | % 16 | % If the Perl executable is not available, it can be downloaded from: 17 | % http://www.cpan.org 18 | % 19 | % See also SYSTEM, JAVA, MEX. 20 | 21 | % Copyright 1990-2012 The MathWorks, Inc. 22 | % $Revision: 1.1.4.12 $ 23 | 24 | cmdString = ''; 25 | 26 | % Add input to arguments to operating system command to be executed. 27 | % (If an argument refers to a file on the MATLAB path, use full file path.) 28 | for i = 1:nargin 29 | thisArg = varargin{i}; 30 | if ~ischar(thisArg) 31 | error(message('MATLAB:perl:InputsMustBeStrings')); 32 | end 33 | if i==1 34 | if exist(thisArg, 'file')==2 35 | % This is a valid file on the MATLAB path 36 | if isempty(dir(thisArg)) 37 | % Not complete file specification 38 | % - file is not in current directory 39 | % - OR filename specified without extension 40 | % ==> get full file path 41 | thisArg = which(thisArg); 42 | end 43 | else 44 | % First input argument is PerlFile - it must be a valid file 45 | error(message('MATLAB:perl:FileNotFound', thisArg)); 46 | end 47 | end 48 | 49 | % Wrap thisArg in double quotes if it contains spaces 50 | if isempty(thisArg) || any(thisArg == ' ') 51 | thisArg = ['"', thisArg, '"']; %#ok 52 | end 53 | 54 | % Add argument to command string 55 | cmdString = [cmdString, ' ', thisArg]; %#ok 56 | end 57 | 58 | % Execute Perl script 59 | if isempty(cmdString) 60 | error(message('MATLAB:perl:NoPerlCommand')); 61 | elseif ispc 62 | % PC 63 | perlCmd = fullfile('C:\Python27'); 64 | cmdString = ['python' cmdString]; 65 | perlCmd = ['set PATH=',perlCmd, ';%PATH%&' cmdString]; 66 | [status, result] = dos(perlCmd); 67 | a = result; 68 | a = str2num(a(:,1:end-138)); 69 | [result] = a; 70 | else 71 | % UNIX 72 | [status, ~] = unix('which perl'); 73 | if (status == 0) 74 | cmdString = ['perl', cmdString]; 75 | [status, result] = unix(cmdString); 76 | else 77 | error(message('MATLAB:perl:NoExecutable')); 78 | end 79 | end 80 | 81 | % Check for errors in shell command 82 | if nargout < 2 && status~=0 83 | error(message('MATLAB:perl:ExecutionError', result, cmdString)); 84 | end 85 | 86 | -------------------------------------------------------------------------------- /myo/tools.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Niklas Rosenstein 2 | # All rights reserved. 3 | r""" 4 | myo.tools 5 | ~~~~~~~~~ 6 | 7 | """ 8 | 9 | from myo import six 10 | import sys 11 | 12 | class ShortcutAccess(object): 13 | r""" Wrapper for any kind of object to make the access to 14 | attributes easier. Prefixes all accssed attribute names with 15 | the string supplied upon construction. """ 16 | 17 | __slots__ = ('_ShortcutAccess__x', '_ShortcutAccess__prefix') 18 | 19 | def __init__(self, x, prefix): 20 | super(ShortcutAccess, self).__init__() 21 | 22 | if not isinstance(prefix, six.string_types): 23 | raise TypeError('prefix must be string') 24 | 25 | super(ShortcutAccess, self).__setattr__('_ShortcutAccess__x', x) 26 | super(ShortcutAccess, self).__setattr__('_ShortcutAccess__prefix', prefix) 27 | 28 | def __getattr__(self, name): 29 | return getattr(self.__x, self.__prefix + name) 30 | 31 | def __setattr__(self, name, value): 32 | setattr(self.__x, self.__prefix + name, value) 33 | 34 | class MacAddress(object): 35 | r""" This class represents an immutable MAC address. """ 36 | 37 | @staticmethod 38 | def int_to_string(x): 39 | r""" Converts *x* being an integral number to a string MAC 40 | address. Raises a ValueError if *x* is a negative number or 41 | exceeds the MAC address range. """ 42 | 43 | if x > (16 ** 12 - 1): 44 | raise ValueError('value exceeds MAC address range') 45 | if x < 0: 46 | raise ValueError('value must not be negative') 47 | 48 | # todo: convert to the right byte order. the resulting 49 | # mac address is reversed on my machine compared to the 50 | # mac address displayed by the hello-myo SDK sample. 51 | # See issue #7 52 | 53 | string = ('%x' % x).rjust(12, '0') 54 | assert len(string) == 12 55 | 56 | result = ':'.join(''.join(pair) for pair in zip(*[iter(string)]*2)) 57 | return result.upper() 58 | 59 | @staticmethod 60 | def string_to_int(s): 61 | r""" Converts *s* being a string MAC address to an integer 62 | version. Raises a ValueError if the string is not a valid 63 | MAC address. """ 64 | 65 | s = s.replace(':', '') 66 | if len(s) != 12: 67 | raise ValueError('not a valid MAC address') 68 | 69 | try: 70 | return int(s, 16) 71 | except ValueError: 72 | return ValueError('not a valid MAC address') 73 | 74 | def __new__(cls, value): 75 | if isinstance(value, MacAddress): 76 | return value 77 | else: 78 | obj = object.__new__(cls) 79 | obj.__init__(value) 80 | return obj 81 | 82 | def __init__(self, value): 83 | super(MacAddress, self).__init__() 84 | 85 | if isinstance(value, six.string_types): 86 | value = MacAddress.string_to_int(value) 87 | elif not isinstance(value, (int, long)): 88 | message = 'expected string or int for MacAddress, got %s' 89 | raise TypeError(message % value.__class__.__name__) 90 | 91 | self._string = MacAddress.int_to_string(value) 92 | self._value = value 93 | 94 | def __str__(self): 95 | return self._string 96 | 97 | def __repr__(self): 98 | return '' % self._string 99 | 100 | @property 101 | def strval(self): 102 | return self._string 103 | 104 | @property 105 | def intval(self): 106 | return self._value 107 | 108 | -------------------------------------------------------------------------------- /getEmg.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Niklas Rosenstein, MIT License 2 | # Last modified by Yi Jui Lee (August 15 2015) 3 | 4 | from __future__ import division 5 | import sys 6 | from sys import exit 7 | import myo 8 | from myo.lowlevel import pose_t, stream_emg 9 | from myo.six import print_ 10 | import random 11 | import time 12 | 13 | open('Emg', 'w').close() 14 | 15 | temp = [] 16 | with open('PythonVars.txt') as f: 17 | for val in f: 18 | temp.append(int(val)) 19 | 20 | samplerate = temp[0] 21 | t_s = 1/samplerate 22 | print "\n\nSample rate is adjusted to %.0f Hz" % (samplerate) 23 | print "Collecting emg data every %.3f seconds" % (t_s) 24 | 25 | T = temp[1] 26 | print "\n\nThis program will terminate in %.1f seconds\n" %(T) 27 | 28 | myo.init() 29 | r""" 30 | There can be a lot of output from certain data like acceleration and orientation. 31 | This parameter controls the percent of times that data is shown. 32 | """ 33 | 34 | 35 | class Listener(myo.DeviceListener): 36 | # return False from any method to stop the Hub 37 | 38 | def on_connect(self, myo, timestamp): 39 | print_("Connected to Myo") 40 | myo.vibrate('short') 41 | myo.set_stream_emg(stream_emg.enabled) 42 | myo.request_rssi() 43 | global start 44 | start = time.time() 45 | 46 | def on_rssi(self, myo, timestamp, rssi): 47 | print_("RSSI:", rssi) 48 | 49 | def on_event(self, event): 50 | r""" Called before any of the event callbacks. """ 51 | 52 | def on_event_finished(self, event): 53 | r""" Called after the respective event callbacks have been 54 | invoked. This method is *always* triggered, even if one of 55 | the callbacks requested the stop of the Hub. """ 56 | 57 | def on_pair(self, myo, timestamp): 58 | print_('Paired') 59 | print_("If you don't see any responses to your movements, try re-running the program or making sure the Myo works with Myo Connect (from Thalmic Labs).") 60 | print_("Double tap enables EMG.") 61 | print_("Spreading fingers disables EMG.\n") 62 | 63 | def on_disconnect(self, myo, timestamp): 64 | print_('on_disconnect') 65 | 66 | def on_emg(self, myo, timestamp, emg): 67 | r = 'Emg.txt' 68 | global start 69 | global t2 70 | global t_s 71 | current = time.time() 72 | tdiff = current - start 73 | t2 = timestamp 74 | if 't1' not in globals(): 75 | global t1 76 | t1 = timestamp 77 | if tdiff > t_s: 78 | start = time.time() 79 | show_output('emg', emg, r) 80 | 81 | def on_unlock(self, myo, timestamp): 82 | print_('unlocked') 83 | 84 | def on_lock(self, myo, timestamp): 85 | print_('locked') 86 | 87 | def on_sync(self, myo, timestamp): 88 | print_('synced') 89 | 90 | def on_unsync(self, myo, timestamp): 91 | print_('unsynced') 92 | 93 | def show_output(message, data, r): 94 | global t2 95 | global t1 96 | global T 97 | if t2 - t1 < (T*1000000): 98 | with open(r, "a") as text_file: 99 | text_file.write("{0}\n".format(data)) 100 | else: 101 | exit() 102 | 103 | def main(): 104 | hub = myo.Hub() 105 | hub.set_locking_policy(myo.locking_policy.none) 106 | hub.run(1000, Listener()) 107 | 108 | # Listen to keyboard interrupts and stop the 109 | # hub in that case. 110 | try: 111 | while hub.running: 112 | myo.time.sleep(0.2) 113 | except KeyboardInterrupt: 114 | print_("Quitting ...") 115 | hub.stop(True) 116 | 117 | if __name__ == '__main__': 118 | main() 119 | 120 | -------------------------------------------------------------------------------- /getPose.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Niklas Rosenstein, MIT License 2 | # Last modified by Yi Jui Lee (August 15 2015) 3 | 4 | from __future__ import division 5 | import sys 6 | from sys import exit 7 | import myo 8 | from myo.lowlevel import pose_t, stream_emg 9 | from myo.six import print_ 10 | import random 11 | import time 12 | 13 | open('Pose.txt', 'w').close() 14 | 15 | temp = [] 16 | with open('PythonVars.txt') as f: 17 | for val in f: 18 | temp.append(int(val)) 19 | 20 | samplerate = temp[0] 21 | t_s = 1/samplerate 22 | print "\n\nSample rate is adjusted to %.0f Hz" % (samplerate) 23 | print "Collecting gestural data every %.3f seconds" % (t_s) 24 | 25 | T = temp[1] 26 | print "\n\nThis program will terminate in %.1f seconds\n" %(T) 27 | 28 | myo.init() 29 | r""" 30 | There can be a lot of output from certain data like acceleration and orientation. 31 | This parameter controls the percent of times that data is shown. 32 | """ 33 | 34 | 35 | class Listener(myo.DeviceListener): 36 | # return False from any method to stop the Hub 37 | 38 | def on_connect(self, myo, timestamp): 39 | print_("Connected to Myo") 40 | myo.vibrate('short') 41 | myo.set_stream_emg(stream_emg.enabled) 42 | myo.request_rssi() 43 | global start 44 | global start2 45 | start = time.time() 46 | start2 = time.time() 47 | 48 | def on_rssi(self, myo, timestamp, rssi): 49 | print_("RSSI:", rssi) 50 | 51 | 52 | def on_event(self, event): 53 | r""" Called before any of the event callbacks. """ 54 | 55 | def on_event_finished(self, event): 56 | r""" Called after the respective event callbacks have been 57 | invoked. This method is *always* triggered, even if one of 58 | the callbacks requested the stop of the Hub. """ 59 | 60 | def on_pair(self, myo, timestamp): 61 | print_('Paired') 62 | print_("If you don't see any responses to your movements, try re-running the program or making sure the Myo works with Myo Connect (from Thalmic Labs).") 63 | print_("Double tap enables EMG.") 64 | print_("Spreading fingers disables EMG.\n") 65 | 66 | def on_disconnect(self, myo, timestamp): 67 | print_('on_disconnect') 68 | 69 | def on_pose(self, myo, timestamp, pose): 70 | r = 'Pose.txt' 71 | global start 72 | current = time.time() 73 | tdiff = current - start 74 | global t2 75 | t2 = timestamp 76 | if 't1' not in globals(): 77 | global t1 78 | t1 = timestamp 79 | show_output('pose', pose, r) 80 | #with open("Pose.txt", "a") as text_file: 81 | # text_file.write("{0}\n".format(pose)) 82 | 83 | def on_unlock(self, myo, timestamp): 84 | print_('unlocked') 85 | 86 | def on_lock(self, myo, timestamp): 87 | print_('locked') 88 | 89 | def on_sync(self, myo, timestamp): 90 | print_('synced') 91 | 92 | def on_unsync(self, myo, timestamp): 93 | print_('unsynced') 94 | 95 | def show_output(message, data, r): 96 | global t2 97 | global t1 98 | if t2 - t1 < (T*1000000): 99 | with open(r, "a") as text_file: 100 | text_file.write("{0}\n".format(data)) 101 | else: 102 | exit() 103 | 104 | def main(): 105 | hub = myo.Hub() 106 | hub.set_locking_policy(myo.locking_policy.none) 107 | hub.run(1000, Listener()) 108 | 109 | # Listen to keyboard interrupts and stop the 110 | # hub in that case. 111 | try: 112 | while hub.running: 113 | myo.time.sleep(0.2) 114 | except KeyboardInterrupt: 115 | print_("Quitting ...") 116 | hub.stop(True) 117 | 118 | if __name__ == '__main__': 119 | main() 120 | 121 | -------------------------------------------------------------------------------- /getOrient.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Niklas Rosenstein, MIT License 2 | # Last modified by Yi Jui Lee (August 15 2015) 3 | 4 | from __future__ import division 5 | import sys 6 | from sys import exit 7 | import myo 8 | from myo.lowlevel import pose_t, stream_emg 9 | from myo.six import print_ 10 | import random 11 | import time 12 | 13 | open('Orientation', 'w').close() 14 | 15 | temp = [] 16 | with open('PythonVars.txt') as f: 17 | for val in f: 18 | temp.append(int(val)) 19 | 20 | samplerate = temp[0] 21 | t_s = 1/samplerate 22 | print "\n\nSample rate is adjusted to %.0f Hz" % (samplerate) 23 | print "Collecting orientation data every %.3f seconds" % (t_s) 24 | 25 | T = temp[1] 26 | print "\n\nThis program will terminate in %.1f seconds\n" %(T) 27 | 28 | myo.init() 29 | r""" 30 | There can be a lot of output from certain data like acceleration and orientation. 31 | This parameter controls the percent of times that data is shown. 32 | """ 33 | 34 | 35 | class Listener(myo.DeviceListener): 36 | # return False from any method to stop the Hub 37 | 38 | def on_connect(self, myo, timestamp): 39 | print_("Connected to Myo") 40 | myo.vibrate('short') 41 | myo.set_stream_emg(stream_emg.enabled) 42 | myo.request_rssi() 43 | global start 44 | start = time.time() 45 | 46 | def on_rssi(self, myo, timestamp, rssi): 47 | print_("RSSI:", rssi) 48 | 49 | def on_event(self, event): 50 | r""" Called before any of the event callbacks. """ 51 | 52 | def on_event_finished(self, event): 53 | r""" Called after the respective event callbacks have been 54 | invoked. This method is *always* triggered, even if one of 55 | the callbacks requested the stop of the Hub. """ 56 | 57 | def on_pair(self, myo, timestamp): 58 | print_('Paired') 59 | print_("If you don't see any responses to your movements, try re-running the program or making sure the Myo works with Myo Connect (from Thalmic Labs).") 60 | print_("Double tap enables EMG.") 61 | print_("Spreading fingers disables EMG.\n") 62 | 63 | def on_disconnect(self, myo, timestamp): 64 | print_('on_disconnect') 65 | 66 | def on_orientation_data(self, myo, timestamp, orientation): 67 | r = 'Orientation.txt' 68 | global start 69 | global t2 70 | global t_s 71 | current = time.time() 72 | tdiff = current - start 73 | t2 = timestamp 74 | if 't1' not in globals(): 75 | global t1 76 | t1 = timestamp 77 | if tdiff > t_s: 78 | #print_(orientation) 79 | start = time.time() 80 | show_output('orientation', orientation, r) 81 | 82 | def on_unlock(self, myo, timestamp): 83 | print_('unlocked') 84 | 85 | def on_lock(self, myo, timestamp): 86 | print_('locked') 87 | 88 | def on_sync(self, myo, timestamp): 89 | print_('synced') 90 | 91 | def on_unsync(self, myo, timestamp): 92 | print_('unsynced') 93 | 94 | def show_output(message, data, r): 95 | global t2 96 | global t1 97 | global T 98 | if t2 - t1 < (T*1000000): 99 | with open(r, "a") as text_file: 100 | text_file.write("{0}\n".format(data)) 101 | else: 102 | exit() 103 | 104 | def main(): 105 | hub = myo.Hub() 106 | hub.set_locking_policy(myo.locking_policy.none) 107 | hub.run(1000, Listener()) 108 | 109 | # Listen to keyboard interrupts and stop the 110 | # hub in that case. 111 | try: 112 | while hub.running: 113 | myo.time.sleep(0.2) 114 | except KeyboardInterrupt: 115 | print_("Quitting ...") 116 | hub.stop(True) 117 | 118 | if __name__ == '__main__': 119 | main() 120 | 121 | -------------------------------------------------------------------------------- /getAccel.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Niklas Rosenstein, MIT License 2 | # Last modified by Yi Jui Lee (August 15 2015) 3 | 4 | from __future__ import division 5 | import sys 6 | from sys import exit 7 | import myo 8 | from myo.lowlevel import pose_t, stream_emg 9 | from myo.six import print_ 10 | import random 11 | import time 12 | 13 | open('Acceleration.txt', 'w').close() 14 | 15 | temp = [] 16 | with open('PythonVars.txt') as f: 17 | for val in f: 18 | temp.append(int(val)) 19 | 20 | samplerate = temp[0] 21 | t_s = 1/samplerate 22 | print "\n\nSample rate is adjusted to %.0f Hz" % (samplerate) 23 | print "Collecting acceleration data every %.3f seconds" % (t_s) 24 | 25 | T = temp[1] 26 | print "\n\nThis program will terminate in %.1f seconds\n" %(T) 27 | 28 | myo.init() 29 | r""" 30 | There can be a lot of output from certain data like acceleration and orientation. 31 | This parameter controls the percent of times that data is shown. 32 | """ 33 | 34 | 35 | class Listener(myo.DeviceListener): 36 | # return False from any method to stop the Hub 37 | 38 | def on_connect(self, myo, timestamp): 39 | print_("Connected to Myo") 40 | myo.vibrate('short') 41 | myo.set_stream_emg(stream_emg.enabled) 42 | myo.request_rssi() 43 | global start 44 | start = time.time() 45 | 46 | def on_rssi(self, myo, timestamp, rssi): 47 | print_("RSSI:", rssi) 48 | 49 | def on_event(self, event): 50 | r""" Called before any of the event callbacks. """ 51 | 52 | def on_event_finished(self, event): 53 | r""" Called after the respective event callbacks have been 54 | invoked. This method is *always* triggered, even if one of 55 | the callbacks requested the stop of the Hub. """ 56 | 57 | def on_pair(self, myo, timestamp): 58 | print_('Paired') 59 | print_("If you don't see any responses to your movements, try re-running the program or making sure the Myo works with Myo Connect (from Thalmic Labs).") 60 | print_("Double tap enables EMG.") 61 | print_("Spreading fingers disables EMG.\n") 62 | 63 | def on_disconnect(self, myo, timestamp): 64 | print_('on_disconnect') 65 | 66 | def on_accelerometor_data(self, myo, timestamp, acceleration): 67 | r = 'Acceleration.txt' 68 | global start 69 | global t2 70 | global t_s 71 | current = time.time() 72 | tdiff = current - start 73 | t2 = timestamp 74 | if 't1' not in globals(): 75 | global t1 76 | t1 = timestamp 77 | if tdiff > t_s: 78 | #print_(acceleration) 79 | start = time.time() 80 | show_output('acceleration', acceleration, r) 81 | 82 | def on_unlock(self, myo, timestamp): 83 | print_('unlocked') 84 | 85 | def on_lock(self, myo, timestamp): 86 | print_('locked') 87 | 88 | def on_sync(self, myo, timestamp): 89 | print_('synced') 90 | 91 | def on_unsync(self, myo, timestamp): 92 | print_('unsynced') 93 | 94 | def show_output(message, data, r): 95 | global t2 96 | global t1 97 | global T 98 | if t2 - t1 < (T*1000000): 99 | with open(r, "a") as text_file: 100 | text_file.write("{0}\n".format(data)) 101 | else: 102 | exit() 103 | 104 | def main(): 105 | hub = myo.Hub() 106 | hub.set_locking_policy(myo.locking_policy.none) 107 | hub.run(1000, Listener()) 108 | 109 | # Listen to keyboard interrupts and stop the 110 | # hub in that case. 111 | try: 112 | while hub.running: 113 | myo.time.sleep(0.2) 114 | except KeyboardInterrupt: 115 | print_("Quitting ...") 116 | hub.stop(True) 117 | 118 | if __name__ == '__main__': 119 | main() 120 | 121 | -------------------------------------------------------------------------------- /getGyro.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Niklas Rosenstein, MIT License 2 | # Last modified by Yi Jui Lee (August 15 2015) 3 | 4 | from __future__ import division 5 | import sys 6 | from sys import exit 7 | import myo 8 | from myo.lowlevel import pose_t, stream_emg 9 | from myo.six import print_ 10 | import random 11 | import time 12 | 13 | open('Gyroscope.txt', 'w').close() 14 | 15 | temp = [] 16 | with open('PythonVars.txt') as f: 17 | for val in f: 18 | temp.append(int(val)) 19 | 20 | samplerate = temp[0] 21 | t_s = 1/samplerate 22 | print "\n\nSample rate is adjusted to %.0f Hz" % (samplerate) 23 | print "Collecting acceleration data every %.3f seconds" % (t_s) 24 | 25 | T = temp[1] 26 | print "\n\nThis program will terminate in %.1f seconds\n" %(T) 27 | 28 | myo.init() 29 | r""" 30 | There can be a lot of output from certain data like acceleration and orientation. 31 | This parameter controls the percent of times that data is shown. 32 | """ 33 | 34 | 35 | class Listener(myo.DeviceListener): 36 | # return False from any method to stop the Hub 37 | 38 | def on_connect(self, myo, timestamp): 39 | print_("Connected to Myo") 40 | myo.vibrate('short') 41 | myo.set_stream_emg(stream_emg.enabled) 42 | myo.request_rssi() 43 | global start 44 | global start2 45 | start = time.time() 46 | start2 = time.time() 47 | 48 | def on_rssi(self, myo, timestamp, rssi): 49 | print_("RSSI:", rssi) 50 | 51 | 52 | def on_event(self, event): 53 | r""" Called before any of the event callbacks. """ 54 | 55 | def on_event_finished(self, event): 56 | r""" Called after the respective event callbacks have been 57 | invoked. This method is *always* triggered, even if one of 58 | the callbacks requested the stop of the Hub. """ 59 | 60 | def on_pair(self, myo, timestamp): 61 | print_('Paired') 62 | print_("If you don't see any responses to your movements, try re-running the program or making sure the Myo works with Myo Connect (from Thalmic Labs).") 63 | print_("Double tap enables EMG.") 64 | print_("Spreading fingers disables EMG.\n") 65 | 66 | def on_disconnect(self, myo, timestamp): 67 | print_('on_disconnect') 68 | 69 | def on_gyroscope_data(self, myo, timestamp, gyroscope): 70 | r = 'Gyroscope.txt' 71 | global start 72 | global t2 73 | global t_s 74 | current = time.time() 75 | tdiff = current - start 76 | t2 = timestamp 77 | if 't1' not in globals(): 78 | global t1 79 | t1 = timestamp 80 | if tdiff > t_s: 81 | #print_(gyroscope) 82 | start = time.time() 83 | show_output('gyroscope', gyroscope, r) 84 | 85 | def on_unlock(self, myo, timestamp): 86 | print_('unlocked') 87 | 88 | def on_lock(self, myo, timestamp): 89 | print_('locked') 90 | 91 | def on_sync(self, myo, timestamp): 92 | print_('synced') 93 | 94 | def on_unsync(self, myo, timestamp): 95 | print_('unsynced') 96 | 97 | def show_output(message, data, r): 98 | global t2 99 | global t1 100 | if t2 - t1 < (T*1000000): 101 | with open(r, "a") as text_file: 102 | text_file.write("{0}\n".format(data)) 103 | else: 104 | exit() 105 | 106 | 107 | 108 | def main(): 109 | hub = myo.Hub() 110 | hub.set_locking_policy(myo.locking_policy.none) 111 | hub.run(1000, Listener()) 112 | 113 | # Listen to keyboard interrupts and stop the 114 | # hub in that case. 115 | try: 116 | while hub.running: 117 | myo.time.sleep(0.2) 118 | except KeyboardInterrupt: 119 | print_("Quitting ...") 120 | hub.stop(True) 121 | 122 | if __name__ == '__main__': 123 | main() 124 | 125 | -------------------------------------------------------------------------------- /getAllData.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Niklas Rosenstein, MIT License 2 | # Last modified by Yi Jui Lee (August 15 2015) 3 | 4 | from __future__ import division 5 | import sys 6 | from sys import exit 7 | import myo 8 | from myo.lowlevel import pose_t, stream_emg 9 | from myo.six import print_ 10 | import random 11 | import time 12 | 13 | open('Acceleration.txt', 'w').close() 14 | open('Gyroscope.txt','w').close() 15 | open('Orientation.txt', 'w').close() 16 | open('Emg.txt', 'w').close() 17 | open('Pose.txt', 'w').close() 18 | 19 | temp = [] 20 | with open('PythonVars.txt') as f: 21 | for val in f: 22 | temp.append(int(val)) 23 | 24 | samplerate = temp[0] 25 | t_s = 1/samplerate 26 | print "\n\nSample rate is adjusted to %.0f Hz" % (samplerate) 27 | print "Collecting all data every %.3f seconds" % (t_s) 28 | 29 | T = temp[1] 30 | print "\n\nThis program will terminate in %.1f seconds\n" %(T) 31 | 32 | myo.init() 33 | r""" 34 | There can be a lot of output from certain data like acceleration and orientation. 35 | This parameter controls the percent of times that data is shown. 36 | """ 37 | 38 | class Listener(myo.DeviceListener): 39 | # return False from any method to stop the Hub 40 | 41 | def on_connect(self, myo, timestamp): 42 | print_("Connected to Myo") 43 | myo.vibrate('short') 44 | myo.set_stream_emg(stream_emg.enabled) 45 | myo.request_rssi() 46 | global start 47 | global start2 48 | global start3 49 | global start4 50 | start = time.time() 51 | start2 = time.time() 52 | start3 = time.time() 53 | start4 = time.time() 54 | 55 | def on_rssi(self, myo, timestamp, rssi): 56 | print_("RSSI:", rssi) 57 | 58 | 59 | def on_event(self, event): 60 | r""" Called before any of the event callbacks. """ 61 | 62 | def on_event_finished(self, event): 63 | r""" Called after the respective event callbacks have been 64 | invoked. This method is *always* triggered, even if one of 65 | the callbacks requested the stop of the Hub. """ 66 | 67 | def on_pair(self, myo, timestamp): 68 | print_('Paired') 69 | print_("If you don't see any responses to your movements, try re-running the program or making sure the Myo works with Myo Connect (from Thalmic Labs).") 70 | print_("Double tap enables EMG.") 71 | print_("Spreading fingers disables EMG.\n") 72 | 73 | def on_disconnect(self, myo, timestamp): 74 | print_('on_disconnect') 75 | 76 | def on_pose(self, myo, timestamp, pose): 77 | #print_('on_pose', pose) 78 | r = 'Pose.txt' 79 | with open("Pose.txt", "a") as text_file: 80 | text_file.write("{0}\n".format(pose)) 81 | 82 | def on_orientation_data(self, myo, timestamp, orientation): 83 | r = "Orientation.txt" 84 | global start 85 | global t_s 86 | current = time.time() 87 | tdiff = current - start 88 | global t2 89 | t2 = timestamp 90 | if 't1' not in globals(): 91 | global t1 92 | t1 = timestamp 93 | if tdiff > t_s: 94 | start = time.time() 95 | show_output('orientation', orientation, r) 96 | 97 | def on_accelerometor_data(self, myo, timestamp, acceleration): 98 | r = 'Acceleration.txt' 99 | global start2 100 | global t_s 101 | current2 = time.time() 102 | tdiff2 = current2 - start2 103 | if tdiff2 > t_s: 104 | start2 = time.time() 105 | #print_(acceleration) 106 | show_output('acceleration', acceleration, r) 107 | 108 | def on_gyroscope_data(self, myo, timestamp, gyroscope): 109 | r = 'Gyroscope.txt' 110 | global start3 111 | global t_s 112 | current3 = time.time() 113 | tdiff3 = current3 - start3 114 | if tdiff3 > t_s: 115 | start3 = time.time() 116 | show_output('gyroscope', gyroscope, r) 117 | 118 | def on_unlock(self, myo, timestamp): 119 | print_('unlocked') 120 | 121 | def on_lock(self, myo, timestamp): 122 | print_('locked') 123 | 124 | def on_sync(self, myo, timestamp): 125 | print_('synced') 126 | 127 | def on_unsync(self, myo, timestamp): 128 | print_('unsynced') 129 | 130 | def on_emg(self, myo, timestamp, emg): 131 | r = 'Emg.txt' 132 | global start4 133 | global t_s 134 | current4 = time.time() 135 | tdiff4 = current4 - start4 136 | if tdiff4 > t_s: 137 | start4 = time.time() 138 | show_output('emg', emg, r) 139 | 140 | def show_output(message, data, r): 141 | global t2 142 | global t1 143 | if t2 - t1 < (T*1000000): 144 | with open(r, "a") as text_file: 145 | text_file.write("{0}\n".format(data)) 146 | else: 147 | exit() 148 | 149 | 150 | def main(): 151 | hub = myo.Hub() 152 | hub.set_locking_policy(myo.locking_policy.none) 153 | hub.run(1000, Listener()) 154 | 155 | # Listen to keyboard interrupts and stop the 156 | # hub in that case. 157 | try: 158 | while hub.running: 159 | myo.time.sleep(0.2) 160 | except KeyboardInterrupt: 161 | print_("Quitting ...") 162 | hub.stop(True) 163 | 164 | if __name__ == '__main__': 165 | main() 166 | 167 | -------------------------------------------------------------------------------- /myo/enum.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Niklas Rosenstein 2 | # All rights reserved. 3 | r""" 4 | myo.enum - Enumeration type-base 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | """ 8 | 9 | import ctypes 10 | from myo import six 11 | 12 | class NoSuchEnumerationValue(Exception): 13 | r""" Raised when an Enumeration object was attempted to be 14 | created from an integer value but there was no enumeration 15 | object for this value. 16 | 17 | Note that you can specify ``__fallback_value__`` on an 18 | Enumeration class to not let it raise an exception. """ 19 | 20 | pass 21 | 22 | class Data(object): 23 | r""" Small class that can be used to specify data on an 24 | enumeration that should not be converted and interpreted 25 | as an enumeration value. """ 26 | 27 | def __init__(self, value): 28 | super(Data, self).__init__() 29 | self.value = value 30 | 31 | class EnumerationMeta(type): 32 | r""" This is the meta class for the :class:`Enumeration` 33 | base class which handles the automatic conversion of integer 34 | values to instances of the Enumeration class. There are no 35 | other types allowed other than int or :class:`Data` which 36 | will be unpacked on the Enumeration class. 37 | 38 | If an ``__fallback__`` was defined on class-level as 39 | an integer, the :class:`Enumeration` constructor will not 40 | raise a :class:`NoSuchEnumerationValue` exception if the 41 | passed value did not match the enumeration values, but 42 | instead return that fallback value. 43 | 44 | This fallback is not taken into account when attempting 45 | to create a new Enumeration object by a string. """ 46 | 47 | _values = None 48 | __fallback__ = None 49 | 50 | def __new__(cls, name, bases, data): 51 | 52 | # Unpack all Data objects and create a dictionary of 53 | # values that will be converted to instances of the 54 | # enumeration class later. 55 | enum_values = {} 56 | for key, value in data.items(): 57 | # Unpack Data objects into the class. 58 | if isinstance(value, Data): 59 | data[key] = value.value 60 | 61 | # Integers will be enumeration values. 62 | elif isinstance(value, int): 63 | enum_values[key] = value 64 | 65 | # We don't accept anything else. 66 | elif not key.startswith('_'): 67 | message = 'Enumeration must consist of ints or Data objects ' \ 68 | 'only, got %s for \'%s\'' 69 | raise TypeError(message % (value.__class__.__name__, key)) 70 | 71 | # Create the new class object and give it the dictionary 72 | # that will map the integral values to the instances. 73 | class_ = type.__new__(cls, name, bases, data) 74 | class_._values = {} 75 | 76 | # Iterate over all entries in the data entries and 77 | # convert integral values to instances of the enumeration 78 | # class. 79 | for key, value in enum_values.items(): 80 | 81 | # Create the new object. We must not use the classes' 82 | # __new__() method as it resolves the object from the 83 | # existing values. 84 | obj = object.__new__(class_) 85 | object.__init__(obj) 86 | 87 | obj.value = value 88 | obj.name = key 89 | 90 | if key == '__fallback__': 91 | obj.name = '-invalid-' 92 | else: 93 | class_._values[value] = obj 94 | setattr(class_, key, obj) 95 | 96 | return class_ 97 | 98 | def __iter__(self): 99 | r""" Iterator over value-sorted enumeration values. """ 100 | 101 | values = list(self._values.values()) 102 | values.sort(key=lambda x: x.value) 103 | return iter(values) 104 | 105 | class Enumeration(six.with_metaclass(EnumerationMeta)): 106 | r""" This is the base class for listing enumerations. All 107 | components of the class that are integers will be automatically 108 | converted to instances of the Enumeration class. Creating new 109 | instances of the class will only work if the value is an existing 110 | enumeration value. """ 111 | 112 | def __new__(cls, value, _allow_fallback=True): 113 | r""" Creates a new instance of the Enumeration. *value* must 114 | be the integral number of one of the existing enumerations. 115 | :class:`NoSuchEnumerationValue` is raised in any other case. 116 | 117 | If a fallback was defined, it is returned only if *value* 118 | is an integer, not if it is a string. """ 119 | 120 | # Try to find the actual instance of the Enumeration class 121 | # for the integer value and return it if it is available. 122 | if isinstance(value, int): 123 | try: 124 | value = cls._values[value] 125 | except KeyError: 126 | 127 | # If a fallback value was specified, use it 128 | # instead of raising an exception. 129 | if _allow_fallback and cls.__fallback__ is not None: 130 | return cls.__fallback__ 131 | 132 | raise NoSuchEnumerationValue(cls.__name__, value) 133 | 134 | # Or by name? 135 | elif isinstance(value, six.string_types): 136 | try: 137 | new_value = getattr(cls, value) 138 | if type(new_value) != cls: 139 | raise AttributeError 140 | except AttributeError: 141 | raise NoSuchEnumerationValue(cls.__name__, value) 142 | 143 | value = new_value 144 | 145 | # At this point, value must be an object of the Enumeration 146 | # class, otherwise an invalid value was passed. 147 | if type(value) == cls: 148 | return value 149 | 150 | raise TypeError('value must be %s or int' % cls.__name__) 151 | 152 | def __hash__(self): 153 | return hash(self.value) 154 | 155 | def __eq__(self, other): 156 | if type(other) == self.__class__: 157 | return other.value == self.value 158 | elif isinstance(other, six.string_types): 159 | return other == self.name 160 | return False 161 | 162 | def __ne__(self, other): 163 | return not (self == other) 164 | 165 | def __int__(self): 166 | return self.value 167 | 168 | def __str__(self): 169 | class_name = self.__class__.__name__ 170 | return '<%s: %s>' % (class_name, self.name) 171 | 172 | def __repr__(self): 173 | class_name = self.__class__.__name__ 174 | return '<%s: [%d] %s>' % (class_name, self.value, self.name) 175 | 176 | def __index__(self): 177 | return self.value 178 | 179 | # ctypes support 180 | 181 | @property 182 | def _as_parameter_(self): 183 | return ctypes.c_int(self.value) 184 | 185 | @Data 186 | @classmethod 187 | def from_param(cls, obj): 188 | if isinstance(obj, (int,) + (six.string_types,)): 189 | obj = cls(obj) 190 | if type(obj) != cls: 191 | c1 = cls.__name__ 192 | c2 = obj.__class__.__name__ 193 | raise TypeError('can not create %s from %s' % (c1, c2)) 194 | 195 | return ctypes.c_int(obj.value) 196 | 197 | Enumeration.Data = Data 198 | 199 | -------------------------------------------------------------------------------- /myo/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Niklas Rosenstein 2 | # All rights reserved. 3 | r""" 4 | myo - Highlevel Myo SDK Interface 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Create a Hub, a DeviceListener and get started! 8 | 9 | --------------------------------- 10 | 11 | __Copyright (C) 2014 Niklas Rosenstein__, 12 | All rights reserved. 13 | """ 14 | 15 | __author__ = ('Niklas Rosenstein', 'rosensteinniklas@gmail.com') 16 | __version__ = (0, 1, 0) 17 | 18 | # The latest version number of the Myo SDK that this library 19 | # is compatible with. 20 | sdk_version = 5 21 | 22 | __all__ = ( 23 | # High level classes 24 | 'Hub', 'DeviceListener', 'Event', 25 | 26 | # Initializers and global functions. 27 | 'init_myo', 'myo_initialized', 'now', 28 | 29 | # Enumerations 30 | 'event_type', 'pose', 'locking_policy' 31 | ) 32 | 33 | from myo import lowlevel as _myo 34 | from myo.lowlevel import init, initialized, now 35 | from myo.lowlevel import MyoError, ResultError, InvalidOperation 36 | from myo.lowlevel import event_type_t as event_type, pose_t as pose 37 | from myo.lowlevel import locking_policy_t as locking_policy 38 | import time 39 | import threading 40 | import traceback 41 | import sys 42 | 43 | init_myo = init 44 | myo_initialized = initialized 45 | 46 | class Hub(object): 47 | r""" Wrapper for a Myo Hub which manages the data processing 48 | and event triggering for a Myo device. 49 | 50 | .. note:: There can only be one Hub instance. The constructor 51 | of the :class:`Hub` class will return the existing instance if 52 | it has not been shut down since then. """ 53 | 54 | def __init__(self): 55 | super(Hub, self).__init__() 56 | 57 | self._lock = threading.RLock() 58 | self._hub = _myo.hub_t.init_hub() 59 | self._running = False 60 | self._stopped = False 61 | self._exception = None 62 | self._thread = None 63 | 64 | def __str__(self): 65 | parts = ['' 76 | 77 | def __nonzero__(self): 78 | return bool(self._hub) 79 | __bool__ = __nonzero__ 80 | 81 | def _assert_running(self): 82 | with self._lock: 83 | if not self._running: 84 | raise RuntimeError('Hub is not running') 85 | 86 | @property 87 | def running(self): 88 | r""" True when the Hub is still running (ie. processing data 89 | from Myo(s) in another thread). """ 90 | 91 | with self._lock: 92 | return self._running 93 | 94 | @property 95 | def stopped(self): 96 | r""" True if the Hub has been stopped with a call to 97 | :meth:`stop`, False if not. When this is True, the Hub 98 | could still be :attr:`running`. """ 99 | 100 | with self._lock: 101 | return self._stopped 102 | 103 | @property 104 | def exception(self): 105 | r""" Set when an exception occured within the listener. The 106 | Hub can not be re-run if this is set. Use :meth:`clear_exception` 107 | to remove the exception from the Hub. """ 108 | 109 | with self._lock: 110 | return self._exception 111 | 112 | def clear_exception(self): 113 | r""" If an exception is set, the Hub can not be re-run. This 114 | method will clear the stored exception if there is any. """ 115 | 116 | with self._lock: 117 | self._exception = None 118 | 119 | def pair_any(self, n=1): 120 | with self._lock: 121 | self._assert_running() 122 | self._hub.pair_any(n) 123 | 124 | def pair_by_mac_address(self, mac_address): 125 | with self._lock: 126 | self._assert_running() 127 | self._hub.pair_by_mac_address(mac_address) 128 | 129 | def pair_adjacent(self, n=1): 130 | with self._lock: 131 | self._assert_running() 132 | self._hub.pair_adjacent(n) 133 | 134 | def set_locking_policy(self, locking_policy): 135 | with self._lock: 136 | self._hub.set_locking_policy(locking_policy) 137 | 138 | def _run(self, duration_ms, listener): 139 | r""" Private version of the :meth:`run` method. Does not 140 | re-set the :attr:`running` attribute. Used by :meth:`run`. 141 | """ 142 | 143 | if not isinstance(listener, DeviceListener): 144 | raise TypeError('listener must be DeviceListener instance') 145 | 146 | # If there is an exception set, an exception occured 147 | # in the listener and we will not do anything further! 148 | with self._lock: 149 | if self._exception: 150 | message = 'exception occured in listener, can not rerun' 151 | raise RuntimeError(message, self._exception) 152 | 153 | def callback(listener, event): 154 | # Stop immediately if the Hub was stopped via the 155 | # stop() method. 156 | with self._lock: 157 | if self._stopped: 158 | return False 159 | 160 | # Invoke the listener but catch the event. 161 | try: 162 | return _invoke_listener(listener, event) 163 | except Exception as exc: 164 | traceback.print_exc() 165 | with self._lock: 166 | self._exception = exc 167 | 168 | return False 169 | 170 | return self._hub.run(duration_ms, callback, listener) 171 | 172 | def run(self, interval_ms, listener, lil_sleep=0.01): 173 | r""" Run the Hub with an execution interval of *interval_ms* 174 | and the specified *listener* until the Hub was stopped. This 175 | method does not block the main thread. Returns the thread 176 | object that was created. 177 | 178 | The Hub and its thread will stop as soon as :meth:`stop` 179 | was called or the :class:`DeviceListener` returns False 180 | from one of its callback methods. 181 | 182 | *lil_sleep* specifies a number of seconds to sleep after 183 | the Hub has been started. This will allow the Hub thread 184 | to start before anything else is called.""" 185 | 186 | if not isinstance(listener, DeviceListener): 187 | raise TypeError('listener must be DeviceListener instance') 188 | 189 | # Make sure the Hub doesn't run already and set 190 | # the running flag to True. 191 | with self._lock: 192 | if self._running: 193 | raise RuntimeError('Hub is already running') 194 | self._running = True 195 | 196 | # This is the worker function that is running in 197 | # a new thread. 198 | def worker(): 199 | while not self.stopped: 200 | if not self._run(interval_ms, listener): 201 | self.stop() 202 | 203 | with self._lock: 204 | self._running = False 205 | 206 | with self._lock: 207 | self._thread = threading.Thread(target=worker) 208 | self._thread.start() 209 | 210 | # Little sleeping so we can immediately call pair_any() 211 | # or variants. 212 | if lil_sleep: 213 | time.sleep(lil_sleep) 214 | 215 | def stop(self, join=False): 216 | r""" Request the Stop of the Hub when it is running. When 217 | *join* is True, this function will block the current thread 218 | until the Hub is not :attr:`running` anymore. """ 219 | 220 | with self._lock: 221 | self._stopped = True 222 | if join: self.join() 223 | 224 | def join(self, timeout=None): 225 | r""" If the Hub was run with a thread, it can be joined (waiting 226 | blocked) with this method. If the Hub was not started within a 227 | thread, this method will do nothing. """ 228 | 229 | with self._lock: 230 | if not self._thread: 231 | return 232 | if not self._thread.is_alive(): 233 | self._thread = None 234 | return 235 | thread = self._thread 236 | 237 | thread.join(timeout) 238 | with self._lock: 239 | if not thread.is_alive(): 240 | self._thread = None 241 | 242 | def shutdown(self): 243 | r""" Shut the hub down. Will happen automatically when 244 | the Hub is being deleted. This method will cause the Hub 245 | to stop if it was still running. """ 246 | 247 | self.stop() 248 | try: 249 | self.join() 250 | except RuntimeError: 251 | message = 'Hub.shutdown() must not be called from DeviceListener' 252 | raise RuntimeError(message) 253 | 254 | self._hub.shutdown() 255 | 256 | class DeviceListener(object): 257 | r""" Interface for listening to data sent from a Myo device. 258 | Return False from one of its callback methods to instruct 259 | the Hub to stop processing. """ 260 | 261 | def on_event(self, event): 262 | r""" Called before any of the event callbacks. """ 263 | 264 | def on_event_finished(self, event): 265 | r""" Called after the respective event callbacks have been 266 | invoked. This method is *always* triggered, even if one of 267 | the callbacks requested the stop of the Hub. """ 268 | 269 | def on_pair(self, myo, timestamp): 270 | pass 271 | 272 | def on_connect(self, myo, timestamp): 273 | pass 274 | 275 | def on_disconnect(self, myo, timestamp): 276 | pass 277 | 278 | def on_pose(self, myo, timestamp, pose): 279 | pass 280 | 281 | def on_orientation_data(self, myo, timestamp, orientation): 282 | pass 283 | 284 | def on_accelerometor_data(self, myo, timestamp, acceleration): 285 | pass 286 | 287 | def on_gyroscope_data(self, myo, timestamp, gyroscope): 288 | pass 289 | 290 | def on_rssi(self, myo, timestamp, rssi): 291 | pass 292 | 293 | def on_emg(self, myo, timestamp, emg): 294 | pass 295 | 296 | class Event(object): 297 | r""" Copy of a Myo SDK event object that can be accessed even 298 | after the event has been destroyed. Must be constructed with 299 | a :class:`myo.lowlevel.event_t` object. 300 | 301 | This type of object is passed to :meth:`DeviceListener.on_event`. """ 302 | 303 | def __init__(self, low_event): 304 | if not isinstance(low_event, _myo.event_t): 305 | raise TypeError('expected event_t object') 306 | super(Event, self).__init__() 307 | self.type = low_event.type 308 | self.myo = low_event.myo 309 | self.timestamp = low_event.timestamp 310 | 311 | if self.type in [event_type.paired, event_type.connected]: 312 | self.firmware_version = low_event.firmware_version 313 | elif self.type == event_type.orientation: 314 | self.orientation = low_event.orientation 315 | self.acceleration = low_event.acceleration 316 | self.gyroscope = low_event.gyroscope 317 | elif self.type == event_type.pose: 318 | self.pose = low_event.pose 319 | elif self.type == event_type.rssi: 320 | self.rssi = low_event.rssi 321 | elif self.type == event_type.emg: 322 | self.emg = low_event.emg 323 | 324 | def __str__(self): 325 | return '' % self.type 326 | 327 | def _invoke_listener(listener, event): 328 | r""" Invokes the :class:`DeviceListener` callback methods for 329 | the specified :class:`event`. If any 330 | of the callbacks return False, this function will return False 331 | as well. It also issues a warning when a DeviceListener method 332 | did not return None or a boolean value. 333 | 334 | :meth:`DeviceListener.on_event_finished` is always called, 335 | event when any of the calls in between returned False already. """ 336 | 337 | event = Event(event) 338 | myo = event.myo 339 | timestamp = event.timestamp 340 | def _(name, *args, **kwargs): 341 | defaults = kwargs.pop('defaults', True) 342 | if kwargs: 343 | raise TypeError('unexpected arguments') 344 | 345 | if defaults: 346 | args = (myo, timestamp) + tuple(args) 347 | method = getattr(listener, name) 348 | result = method(*args) 349 | 350 | if result is None: 351 | return True 352 | elif not isinstance(result, bool): 353 | sys.stderr.write('DeviceListener.%s() must return None or bool\n' % name) 354 | result = False 355 | 356 | return result 357 | 358 | kind = event.type 359 | result = _('on_event', event, defaults=False) 360 | 361 | if kind == _myo.event_type_t.paired: 362 | result = result and _('on_pair') 363 | 364 | elif kind == _myo.event_type_t.connected: 365 | result = result and _('on_connect') 366 | 367 | elif kind == _myo.event_type_t.disconnected: 368 | result = result and _('on_disconnect') 369 | 370 | elif kind == _myo.event_type_t.pose: 371 | result = result and _('on_pose', event.pose) 372 | 373 | elif kind == _myo.event_type_t.orientation: 374 | result = result and _('on_orientation_data', event.orientation) 375 | result = result and _('on_accelerometor_data', event.acceleration) 376 | result = result and _('on_gyroscope_data', event.gyroscope) 377 | 378 | elif kind == _myo.event_type_t.rssi: 379 | result = result and _('on_rssi', event.rssi) 380 | 381 | elif kind == _myo.event_type_t.emg: 382 | result = result and _('on_emg', event.emg) 383 | 384 | elif kind == _myo.event_type_t.arm_unsynced: 385 | result = result and _('on_unsync') 386 | elif kind == _myo.event_type_t.arm_synced: 387 | result = result and _('on_sync') 388 | 389 | elif kind == _myo.event_type_t.unlocked: 390 | result = result and _('on_unlock') 391 | 392 | elif kind == _myo.event_type_t.locked: 393 | result = result and _('on_lock') 394 | 395 | else: 396 | print('invalid event type: %s' % kind) 397 | 398 | if not _('on_event_finished', event, defaults=False): 399 | result = False 400 | return result 401 | 402 | -------------------------------------------------------------------------------- /LICENSE/MYOSDK_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Myo SDK license agreement 2 | 3 | Version Date: December 17, 2014 4 | 5 | Thanks for your interest in the Myo armband from Thalmic Labs! We are excited that you want to develop software using our Myo SDK. Your use of our Myo SDK is subject to our Myo SDK license terms, as set forth here. By using the Myo SDK, you are agreeing to adhere to and be bound by these terms, and also signifying that you can legally be bound by these terms. If you are using the Myo SDK to develop software on behalf of a third party, like your employer, you are also agreeing to these terms on their behalf and you must have the authority to bind them to these terms. If you do not or cannot agree, then we do not permit you to use, and you must not use, the Myo SDK in any way. 6 | 7 | THE BOTTOM LINE: The Myo SDK is being provided to you free of charge, so you are accepting all risks in using the Myo SDK, and you are also agreeing to be liable for anything arising from your use of the Myo SDK, such as software you develop. We own and are responsible for the Myo SDK; you own and are responsible for any software you develop using the Myo SDK, but if you develop any gesture recognition algorithms using the Myo SDK, you will let us use them at no charge and without any restrictions. We will only be responsible for issues relating to the Myo SDK that are wholly within our control, and then only to the limited extent that the law says that we must be responsible. 8 | 9 | THE DETAILS (NUMBERED SUMMARY HEADINGS PROVIDED FOR CONVENIENCE ONLY): 10 | 11 | 1. You and Thalmic Labs are entering into this agreement. 12 | 13 | The parties to this agreement are you, on behalf of yourself as an individual and/or as a representative of an employer, company or other third party entity (being the party for whose benefit the Myo SDK is being used), and Thalmic Labs Inc., an Ontario corporation with principal place of business at 24 Charles Street West, Kitchener, ON N2G 1H2 (Thalmic). 14 | 15 | 2. This is a license agreement allowing you to develop Applications using the Myo SDK. 16 | 17 | This is a software license agreement for the Myo SDK (meaning the system files, redistributables, libraries, tools, data, APIs, sample code, documentation, and other software materials, as well as any updates to the foregoing, which are made available to you by Thalmic in connection with this agreement) for use in developing Applications (meaning any software developed, built, created, or otherwise produced using the Myo SDK) for the Myo armband (meaning the Myo gesture control armband). 18 | 19 | 3. You can develop Applications as long as you comply with all laws, do not damage us or the Myo SDK in any way, and use the Myo SDK the way we have said it is intended to be used. You are free to copy, distribute, modify, and create derivative works of the sample code that we provide and to redistribute the redistributable files that are necessary for your Application to run. 20 | 21 | Subject to the terms of this agreement, Thalmic grants you a limited, worldwide, royalty-free, non-assignable and non-exclusive license to use the Myo SDK solely to develop Applications for the Myo armband. Your Application and your use of the Myo SDK must comply with: (a) this agreement, and (b) any applicable laws, regulations or other mandatory requirements applicable to you and/or the Application (including any laws regarding the export of data or software). 22 | 23 | Except to the extent required by applicable third party licenses (if any), you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Myo SDK or any part of the Myo SDK. Notwithstanding the foregoing, you are permitted to modify and/or create derivative works of any sample code included in the Myo SDK, to distribute such modifications and/or derivative works of sample code with your Application, and, if your employer is bound by this agreement, to copy/redistribute the Myo SDK to other employees of your employer. You are also permitted to redistribute, with your Application, any redistributable file from the Myo SDK (such as myo.dll in the Windows version, myo.framework in the Mac version, and the like) that is required in order for your Application to run. 24 | 25 | You agree that if you use the Myo SDK to develop an Application for general public users, you will protect the privacy and legal rights of those users. You also agree that you will not engage in any illicit or illegal activity with the Myo SDK, including the development or distribution of any Application that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party, including Thalmic. 26 | 27 | 4. There may be software in the Myo SDK owned by third parties (i.e., not Thalmic and not you), so when you use the Myo SDK, you need to comply with their license agreements as well. 28 | 29 | Use, reproduction and distribution of components of the Myo SDK licensed under a third party software license (including but not limited to an open source software license) are governed solely by the terms of that third party software license and not this agreement. Such licenses, if applicable, may be found in the documentation accompanying the Myo SDK. 30 | 31 | 5. We own everything else having to do with the Myo SDK and the Myo armband (except the third party software mentioned in #4 above). 32 | 33 | You agree that Thalmic or third parties own all legal right, title and interest in and to the Myo SDK, including any intellectual property rights (patents, copyrights, trademarks, etc.) that subsist in the Myo SDK. You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Myo SDK. Thalmic reserves all rights not expressly granted to you under this agreement. 34 | 35 | Thalmic reserves the right to discontinue, change or remove features, or change the form and nature of the Myo SDK at any time without notice. Future versions of the Myo SDK may be incompatible with Applications developed on previous versions of the Myo SDK. This agreement may also be modified by Thalmic in future versions of the Myo SDK, and you are responsible for ensuring that you and your Application(s) are in compliance with the then-current version. 36 | 37 | 6. You own your Application, but Thalmic does get full license rights to any gesture recognition algorithms that you may develop using the Myo SDK. Ongoing compatibility between your Application and the Myo armband / Myo SDK is your responsibility, not the responsibility of Thalmic. You are also accountable for anything to do with your Application (such as how it is developed, licensed or sold, and its operation), and for your handling of any third party data that you collect through the Myo armband or your Application. 38 | 39 | With the exception of any algorithms, methods, processes, or techniques for gesture recognition (Algorithms) that you develop using the Myo SDK, Thalmic agrees that it obtains no right, title or interest from you (or your licensors) under this agreement in or to any Application(s) that you develop, including any Intellectual Property Rights that subsist in such Application(s). If you develop any Algorithms, you hereby grant to Thalmic an irrevocable, unlimited, worldwide, royalty-free, perpetual, and non-exclusive license to execute, copy, reproduce, perform, make, produce, modify, maintain, sell, market, promote, distribute, export, import, transmit, broadcast, sub-license, create derivative works of, and otherwise use in any way that Thalmic deems appropriate, any such Algorithm. You agree to share full details of any Algorithm that you develop with Thalmic, including data and source code if applicable, upon request by Thalmic. 40 | 41 | You agree that you are solely responsible for (and that Thalmic has no responsibility to you or to any third party for) any data, content, or resources that you and/or users of your Application create, collect, or transmit by a Myo armband and/or by your Application, and for the consequences of your actions (including any loss or damage which Thalmic may suffer) by doing so. AS INFORMATION AND DATA THAT YOU COLLECT BY USING THE MYO ARMBAND AND/OR YOUR APPLICATION MAY BE CONSIDERED THIRD PARTY PERSONAL OR PROPRIETARY INFORMATION, YOU ARE SOLELY RESPONSIBLE FOR COMPLYING WITH ALL APPLICABLE LAWS (INCLUDING PRIVACY LAWS) RESPECTING SUCH COLLECTION, INCLUDING BY OBTAINING ALL RELEVANT PERMISSIONS FROM ANY PERSONS TO COLLECT AND USE SUCH INFORMATION AND DATA IN THE MANNER THAT YOU CONTEMPLATE. You agree that you are solely responsible for the operation, marketing, compatibility, and all other aspects of your Application(s), and for complying with all applicable laws regarding such Application(s). Thalmic expressly disclaims all liability for any claims, losses or damages arising from your Application(s), your marketing, distribution or other handling of such Application(s), and/or your collection and/or handling of data and information through the Myo armband or the Application, and you agree to indemnify Thalmic against all such claims, losses and damages, in accordance with this agreement. 42 | 43 | 7. We are providing the Myo SDK without any warranties, and you are accepting all risk in using the Myo SDK. We have no liability to you for any damages relating to your use of the Myo SDK or your reliance on any data that you may obtain through your use of the Myo SDK. 44 | 45 | YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE MYO SDK IS AT YOUR SOLE RISK AND THAT THE MYO SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM THALMIC. THALMIC EXPRESSLY DISCLAIMS ALL OTHER REPRESENTATIONS, WARRANTIES AND CONDITIONS, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY EXPRESS OR IMPLIED REPRESENTATIONS, WARRANTIES OR CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, TITLE, NON-INFRINGEMENT, OR ANY OTHER WARRANTY OR CONDITION ARISING BY STATUTE, CUSTOM OR USAGE OF TRADE RELATED TO THE MYO SDK PROVIDED HEREUNDER. THALMIC SPECIFICALLY DOES NOT WARRANT THAT THE OPERATION OF THE MYO SDK WILL BE UNINTERRUPTED OR ERROR-FREE. In particular, you acknowledge that Thalmic does not warrant or recommend the Myo armband for use in any application (such as vehicular control) for which a failure or fault may result in death, personal injury or damage to property. 46 | YOUR USE OF THE MYO SDK AND ANY MATERIAL PRODUCED, DOWNLOADED OR OTHERWISE OBTAINED THROUGH YOUR USE OF THE MYO SDK, INCLUDING ANY DATA YOU COLLECT AND ANY APPLICATION(S) YOU DEVELOP, IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO ANY PERSON OR PROPERTY OR LOSS OF DATA THAT RESULTS FROM SUCH USE. Without limiting any other provision of this Agreement, under no circumstance will Thalmic be liable for any loss or damage caused by your reliance on, or use of, any information or data obtained through the Myo SDK, your Application or otherwise through the Myo armband, and it is solely your responsibility to evaluate the accuracy, completeness or usefulness of any such data or information. 47 | 48 | Some jurisdictions may not allow the exclusion or limitation of implied warranties and conditions. To the extent permitted by law, any implied warranties or conditions relating to the Myo SDK, to the extent that they cannot be excluded as set out above, are limited to thirty (30) days from the date that you first download the Myo SDK. 49 | 50 | The only type of damages that can be recovered against Thalmic arising from or related to this agreement (including without limitation in relation to the Myo armband, the Myo SDK and your use under this agreement thereof), shall be your direct damages, if any, to the extent arising from gross negligence of or wilful misconduct by Thalmic. In no event shall the aggregate liability of Thalmic exceed the amount paid by you for the portion of the Myo SDK that gave rise to the claim. EXCEPT FOR THE LIMITED DIRECT DAMAGES SPECIFIED ABOVE, TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL THALMIC BE LIABLE FOR ANY DAMAGES WHATSOEVER, TO YOU OR TO ANY THIRD PARTY (INCLUDING, WITHOUT LIMITATION, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL OR PUNITIVE DAMAGES, FAILURES TO TRANSMIT OR RECEIVE ANY DATA, COMPUTER OR MOBILE DEVICE FAILURE, PROBLEMS, LOSS OR DAMAGE ASSOCIATED WITH ANY USE OF THE MYO SDK, YOUR APPLICATION(S), OR THE MYO ARMBAND, OR OTHER PECUNIARY LOSS ARISING OUT OF OR RELATED TO THIS AGREEMENT), WHETHER OR NOT SUCH DAMAGES WERE FORESEEN OR UNFORESEEN INCLUDING WITHOUT LIMITATION THE USE OF OR INABILITY TO USE THE MYO SDK, EVEN IF THALMIC HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 51 | 52 | 8. We want our customers to have a consistent and enjoyable experience and wish to protect our name and reputation, so you need to follow our guidelines in developing your Application and in referencing us or our products. 53 | 54 | You agree to follow the guidelines for the naming, branding, and general presentation of Applications for the Myo armband, viewable at https://developer.getmyo.com/branding and the guidelines for the user experience provided by Applications for the Myo armband, viewable at https://developer.getmyo.com/ux (collectively, the Guidelines). 55 | 56 | Thalmic reserves the right to update and/or modify the Guidelines at any time in its sole discretion. You must ensure that any Application that you develop complies with the current Guidelines before you distribute the Application. 57 | 58 | Except as otherwise expressly provided herein, you are prohibited from making any references to Thalmic, the Myo armband, the Myo SDK, or any other Thalmic products and services (whether in conjunction with your Application or otherwise), and especially shall not make any representations, guarantees or warranties to any third party in relation to Thalmic, the Myo armband, the Myo SDK, or any other Thalmic products and services. Except to the limited extent provided by the Guidelines, nothing in this agreement gives you a right to use any of the trade names, trademarks, service marks, logos, domain names, or other brand features owned by Thalmic. 59 | 60 | 9. Unless you opt-out, we may automatically collect certain information from your use of the Myo SDK to help us improve our products and services. The same goes for users of your Application, and your use of an Application developed by a third party. 61 | 62 | In order to continually innovate and improve the Myo SDK and/or the Myo armband, Thalmic may collect certain usage statistics related to the Myo SDK, Applications, and/or the Myo armband, including without limitation: a unique identifier of the Myo armband being used, an associated IP address, a version number of the Myo SDK and/or Application, a version number of the firmware of the Myo armband being used, information on which tools and/or services in the Myo SDK and/or Application are being used and how they are being used, and/or gesture data collected and stored during use of the Myo SDK and/or Application. Any or all of this information may be transmitted to Thalmic from you unless you opt out of data collection as described in the documentation accompanying the Myo SDK. Likewise, any or all of this information may be transmitted to Thalmic from users of your Application unless users of your Application opt out of data collection as described in the documentation accompanying the Myo SDK. It is your responsibility to inform users of your Application that this information may be automatically collected and to ensure that your Application is compatible with the opt out technique(s) described in the documentation accompanying the Myo SDK. The data collected is examined in the aggregate to improve the Myo SDK and/or the Myo armband and is maintained in accordance with the Thalmic Privacy Policy, available at: https://thalmic.com/privacy. 63 | 64 | 10. As part of your acceptance of risks under this agreement, you bear full responsibility for any claims made against us due to your Application and/or your acts or omissions, but you will not be responsible for any claims caused use of the Algorithms by Thalmic. 65 | 66 | You agree to indemnify, defend and hold harmless Thalmic, its parents, subsidiaries, affiliates, officers and employees, including costs and attorneys' fees, from any claim or demand made by any third party due to or arising out of: (a) your access, use or misuse of the Myo SDK and/or the Myo armband, (b) your Application or other code developed or marketed by you in using the Myo SDK, (c) any breach of this agreement by you, (d) the infringement by you, or any third party obtaining access to the Myo SDK or Application through you, of any intellectual property or other right of any person or entity, or (e) your violation of any third-party rights or any applicable laws. Thalmic reserves the right, at your expense, to assume the exclusive defence and control of any matter otherwise subject to indemnification by you, in which event you will cooperate with Thalmic, at your expense, in asserting any available defences. The foregoing indemnity shall not apply to the extent that any claim or demand is caused solely by use of the Algorithms by Thalmic pursuant to the license granted to Thalmic in Section 6. 67 | 68 | 11. This agreement will continue to apply until terminated by either you or Thalmic. 69 | 70 | If you want to terminate this agreement, you may do so by ceasing your use of the Myo SDK. Thalmic may at any time, terminate this agreement with you if: (A) you have breached any provision of this agreement; (B) Thalmic is required to do so by law; (C) Thalmic decides to no longer make available the Myo SDK or certain parts of the Myo SDK to users in the country in which you are resident or from which you use the Myo SDK; or (D) the provision of the Myo SDK to you by Thalmic is, in the sole discretion of Thalmic, no longer commercially viable. 71 | 72 | When this agreement comes to an end, all of the legal rights, obligations and liabilities that you and Thalmic have benefited from, been subject to (or which have accrued over time while this agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 12 shall continue to apply to such rights, obligations and liabilities indefinitely. 73 | 74 | 12. This section explains how this agreement will be interpreted and enforced. 75 | 76 | This agreement constitutes the whole legal agreement between the parties governing your use of the Myo SDK and completely replaces any prior agreement(s) between the parties in relation to the Myo SDK. This agreement is governed by the laws of the Province of Ontario, Canada, without regard to conflict of laws provisions, and you agree to submit to the exclusive jurisdiction of the courts located in the Province of Ontario, Canada. The parties expressly agree that neither the United Nations Convention on Contracts for the International Sale of Goods nor the Uniform Computer Information Transactions Act shall apply to this agreement. If any part of this agreement is determined to be invalid or unenforceable pursuant to applicable law, then the invalid or unenforceable provision will be deemed superseded by a valid, enforceable provision that most closely matches the intent of the original provision and the remainder of this agreement shall continue in full force and effect. You agree that if Thalmic does not exercise or enforce any legal right or remedy which is contained in this agreement (or which Thalmic has the benefit of under any applicable law), this will not be taken to be a waiver of any Thalmic rights and that those rights or remedies will still be available to Thalmic. The rights granted in this agreement may not be assigned or transferred by either party without the prior written approval of the other party. Neither party shall be permitted to delegate their responsibilities or obligations under this agreement without the prior written approval of the other party. 77 | -------------------------------------------------------------------------------- /Myo.m: -------------------------------------------------------------------------------- 1 | % ####################################################################### 2 | % 3 | % Authored by Yi Jui Lee 4 | % 5 | % Tested on MATLAB 2013a, Python 2.7 6 | % 7 | % *********************************************************************** 8 | % Filename : Myo.m 9 | % 10 | % Version 1 (15 August 2015) 11 | % *********************************************************************** 12 | 13 | 14 | %% Official Myo MATLAB Interface 15 | classdef Myo < handle 16 | properties 17 | acceleration = []; 18 | gyroscope = []; 19 | orientation = []; 20 | pose = []; 21 | emg = []; 22 | end 23 | %% 24 | methods 25 | function m = Myo() 26 | disp('###########################################################################'); 27 | disp('# Myo Object Created #'); 28 | disp('# Please make sure that Myo Connect is running and Myo is connected #'); 29 | disp('###########################################################################'); 30 | disp(' '); 31 | end 32 | %% 33 | function a1 = getAcceleration(m) 34 | clc; 35 | a1 = [0 0 0]; 36 | FileID1 = fopen('Acceleration.txt','w'); 37 | FileID2 = fopen('PythonVars.txt','wt'); 38 | SampleRate = input('Please type in desired sample rate (0-50Hz): '); 39 | T = input('Please indicate the duration of program (seconds): '); 40 | pythonvars = [SampleRate, T]; 41 | fprintf(FileID2,'%d\n',pythonvars); 42 | fclose(FileID2); 43 | eval('!matlab -nodesktop -nosplash -minimize -r "r1 = 1, try, terminate, catch, try, init_python, catch, exit, end, end" &'); 44 | t_initial = clock; ii = 0; t = 0; 45 | while t < T 46 | ii = ii+1; 47 | t2 = clock; 48 | t(ii) = etime(t2,t_initial); 49 | disp(['Progress: ',num2str(((t(ii))/T)*100,'% .0f'),' % done...']); 50 | FileID1 = fopen('Acceleration.txt'); 51 | Acceleration = textscan(FileID1,'%s %s %s'); 52 | fclose(FileID1); 53 | if length(a1) < length(Acceleration{1}) 54 | FileID1 = fopen('Acceleration.txt'); 55 | Acceleration = textscan(FileID1,'%s %s %s','HeaderLines',length(a1)); 56 | fclose(FileID1); 57 | for i = 1:length(Acceleration{1}) 58 | s = {Acceleration{1,1}{i,1} Acceleration{1,2}{i,1} Acceleration{1,3}{i,1}}; 59 | temp = strtok(s,'[ ]'); 60 | a1(end+1,:) = str2double(temp); 61 | plot(a1) 62 | drawnow 63 | end 64 | end 65 | end 66 | m.acceleration = a1; 67 | pyquit; 68 | end 69 | %% 70 | function a2 = getGyroscope(m) 71 | clc 72 | close all 73 | a2 = [0 0 0]; 74 | FileID1 = fopen('Gyroscope.txt','w'); 75 | FileID2 = fopen('PythonVars.txt','wt'); 76 | SampleRate = input('Please type in desired sample rate (0-50Hz): '); 77 | T = input('Please indicate the duration of program (seconds): '); 78 | pythonvars = [SampleRate, T]; 79 | fprintf(FileID2,'%d\n',pythonvars); 80 | fclose(FileID2); 81 | eval('!matlab -nodesktop -nosplash -minimize -r "r2 = 1, try, terminate, catch, try, init_python, catch, exit, end, end" &') 82 | t_initial = clock; 83 | ii = 0; 84 | t = 0; 85 | while t < T 86 | ii = ii+1; 87 | t2 = clock; 88 | t(ii) = etime(t2,t_initial); 89 | disp(['Progress: ',num2str(((t(ii))/T)*100,'% .0f'),' % done...']); 90 | FileID1 = fopen('Gyroscope.txt'); 91 | Gyroscope = textscan(FileID1,'%s %s %s'); 92 | fclose(FileID1); 93 | if length(a2) < length(Gyroscope{1}) 94 | FileID1 = fopen('Gyroscope.txt'); 95 | Gyroscope = textscan(FileID1,'%s %s %s','HeaderLines',length(a2)); 96 | fclose(FileID1); 97 | for i = 1:length(Gyroscope{1}) 98 | s = {Gyroscope{1,1}{i,1} Gyroscope{1,2}{i,1} Gyroscope{1,3}{i,1}}; 99 | temp = strtok(s,'[ ]'); 100 | a2(end+1,:) = str2double(temp); 101 | 102 | plot(a2) 103 | drawnow 104 | end 105 | end 106 | end 107 | m.gyroscope = a2; 108 | pyquit 109 | end 110 | %% 111 | function a3 = getOrientation(m) 112 | clc; 113 | a3 = [0 0 0 0]; roll = 0; pitch = 0; yaw = 0; a3_e = [roll pitch yaw]; 114 | FileID3 = fopen('Orientation.txt','w'); 115 | FileID2 = fopen('PythonVars.txt','wt'); 116 | SampleRate = input('Please type in desired sample rate (0-50Hz): '); 117 | T = input('Please indicate the duration of program (seconds): '); 118 | pythonvars = [SampleRate, T]; 119 | fprintf(FileID2,'%d\n',pythonvars); 120 | fclose(FileID2); 121 | eval('!matlab -nodesktop -nosplash -minimize -r "r3 = 1, try, terminate, catch, try, init_python, catch, exit, end, end" &') 122 | t_initial = clock; 123 | ii = 0; 124 | t = 0; 125 | 126 | while t < T 127 | ii = ii+1; 128 | t2 = clock; 129 | t(ii) = etime(t2,t_initial); 130 | disp(['Progress: ',num2str(((t(ii))/T)*100,'% .0f'),' % done...']); 131 | FileID3 = fopen('Orientation.txt'); 132 | Orientation = textscan(FileID3,'%s %s %s %s'); 133 | fclose(FileID3); 134 | [p1,q1] = size(a3); 135 | [p2] = length(Orientation{1}); 136 | if (p1 < p2); 137 | FileID3 = fopen('Orientation.txt'); 138 | Orientation = textscan(FileID3,'%s %s %s %s','HeaderLines',p1); 139 | fclose(FileID3); 140 | for i = 1:length(Orientation{1}); 141 | s = {Orientation{1,1}{i,1} Orientation{1,2}{i,1} Orientation{1,3}{i,1}, Orientation{1,4}{i,1}}; 142 | temp = strtok(s,'[ ]'); 143 | a3(end+1,:) = str2double(temp); 144 | 145 | [roll, pitch, yaw] = quat2angle(a3(end,:)); 146 | a3_e(end+1,:) = [roll pitch yaw]; 147 | plot(a3_e); 148 | drawnow 149 | end 150 | end 151 | end 152 | m.orientation = a3_e; 153 | pyquit 154 | end 155 | %% 156 | function a4 = getPose(m) 157 | clc; 158 | FileID2 = fopen('PythonVars.txt','wt'); 159 | SampleRate = 50; % assign random number 160 | T = input('Please indicate the duration of program (seconds): '); 161 | pythonvars = [SampleRate, T]; 162 | fprintf(FileID2,'%d\n',pythonvars); 163 | fclose(FileID2); 164 | eval('!matlab -nodesktop -nosplash -minimize -r "r4 = 1, try, terminate, catch, try, init_python, catch, exit, end, end" &') 165 | t_initial = clock; 166 | ii = 0; 167 | t = 0; 168 | a4{1,1} = 'rest>'; 169 | FileID4 = fopen('Pose.txt','w'); 170 | pin = 0; 171 | while t < T 172 | ii = ii+1; 173 | t2 = clock; 174 | t(ii) = etime(t2,t_initial); 175 | disp(['Progress: ',num2str(((t(ii))/T)*100,'% .0f'),' % done...']); 176 | FileID4 = fopen('Pose.txt'); 177 | Pose = textscan(FileID4,'%s %s'); 178 | fclose(FileID4); 179 | if pin < length(Pose{1,2}) 180 | FileID4 = fopen('Pose.txt'); 181 | Pose = textscan(FileID4,'%s %s','HeaderLines',pin); 182 | fclose(FileID4); 183 | pin = pin + length(Pose{1,2}); 184 | 185 | for i = 1:length(Pose{1,2}) 186 | p = char([Pose{1,2}{i,1}]) 187 | a4{end+1,1} = p; 188 | end 189 | end 190 | 191 | end 192 | m.pose = a4; 193 | pyquit 194 | end 195 | %% 196 | function a5 = getEmg(m) 197 | clc; 198 | FileID2 = fopen('PythonVars.txt','wt'); 199 | SampleRate = input('Please type in desired sample rate (0-200Hz): '); 200 | T = input('Please indicate the duration of program (seconds): '); 201 | pythonvars = [SampleRate, T]; 202 | fprintf(FileID2,'%d\n',pythonvars); 203 | fclose(FileID2); 204 | eval('!matlab -nodesktop -nosplash -minimize -r "r5 = 1, try, terminate, catch, try, init_python, catch, exit, end, end" &') 205 | t_initial = clock; 206 | ii = 0; 207 | t = 0; 208 | a5 = [0 0 0 0 0 0 0 0]; 209 | FileID5 = fopen('Emg.txt','w'); 210 | 211 | while t < T 212 | ii = ii+1; 213 | t2 = clock; 214 | t(ii) = etime(t2,t_initial); 215 | disp(['Progress: ',num2str(((t(ii))/T)*100,'% .0f'),' % done...']); 216 | FileID5 = fopen('Emg.txt'); 217 | Emg = textscan(FileID5,'%s %s %s %s %s %s %s %s'); 218 | fclose(FileID5); 219 | [p1,q1] = size(a5); 220 | [p2] = length(Emg{1}); 221 | if (p1 < p2); 222 | FileID5 = fopen('Emg.txt'); 223 | Emg = textscan(FileID5,'%s %s %s %s %s %s %s %s','HeaderLines',p1); 224 | fclose(FileID5); 225 | for i = 1:length(Emg{1}); 226 | s = {Emg{1,1}{i,1} Emg{1,2}{i,1} Emg{1,3}{i,1} Emg{1,4}{i,1} Emg{1,5}{i,1} Emg{1,6}{i,1} Emg{1,7}{i,1} Emg{1,8}{i,1}}; 227 | temp = strtok(s,'[ ]'); 228 | a5(end+1,:) = str2double(temp); 229 | plot(a5) 230 | drawnow 231 | end 232 | end 233 | end 234 | m.emg = a5; 235 | pyquit 236 | end 237 | %% 238 | function [a1, a2, a3, a4, a5] = getAllData(m) 239 | clc; 240 | FileID7 = fopen('PythonVars.txt','wt'); 241 | SampleRate = input('Please type in desired sample rate (0-50Hz): '); 242 | T = input('Please indicate the duration of program (seconds): '); 243 | pythonvars = [SampleRate, T]; 244 | fprintf(FileID7,'%d\n',pythonvars); 245 | fclose(FileID7); 246 | eval('!matlab -nodesktop -nosplash -minimize -r "r6 = 1, try, terminate, catch, try, init_python, catch, exit, end, end" &') 247 | t_initial = clock; 248 | ii = 0; 249 | t = 0; 250 | a1 = [0 0 0]; 251 | a2 = [0 0 0]; 252 | a3 = [0 0 0 0]; 253 | a3_e = [0 0 0]; 254 | roll = 0; pitch = 0; yaw = 0; a3_e(end+1,:) = [roll pitch yaw]; 255 | a4{1,1} = 'rest>'; 256 | a5 = [0 0 0 0 0 0 0 0]; 257 | FileID1 = fopen('Acceleration.txt','w'); 258 | FileID2 = fopen('Gyroscope.txt','w'); 259 | FileID3 = fopen('Orientation.txt','w'); 260 | FileID4 = fopen('Pose.txt','w'); 261 | FileID5 = fopen('Emg.txt','w'); 262 | 263 | while t < T 264 | ii = ii+1; 265 | t2 = clock; 266 | t(ii) = etime(t2,t_initial); 267 | disp(['Progress: ',num2str(((t(ii))/T)*100,'% .0f'),' % done...']); 268 | FileID1 = fopen('Acceleration.txt'); 269 | FileID2 = fopen('Gyroscope.txt'); 270 | FileID3 = fopen('Orientation.txt'); 271 | FileID4 = fopen('Pose.txt'); 272 | FileID5 = fopen('Emg.txt'); 273 | Acceleration = textscan(FileID1,'%s %s %s'); 274 | Gyroscope = textscan(FileID2,'%s %s %s'); 275 | Orientation = textscan(FileID3,'%s %s %s %s'); 276 | Pose = textscan(FileID4,'%s %s'); 277 | Emg = textscan(FileID4,'%s %s %s %s %s %s %s %s'); 278 | fclose(FileID1); 279 | fclose(FileID2); 280 | fclose(FileID3); 281 | fclose(FileID4); 282 | fclose(FileID5); 283 | [p1,q1] = size(a1); 284 | [p2] = length(Acceleration{1}); 285 | if (p1 < p2); 286 | FileID1 = fopen('Acceleration.txt'); 287 | FileID2 = fopen('Gyroscope.txt'); 288 | FileID3 = fopen('Orientation.txt'); 289 | FileID4 = fopen('Pose.txt'); 290 | FileID5 = fopen('Emg.txt'); 291 | [p3,q3] = size(a1); 292 | [p4,q4] = size(a2); 293 | [p5,q5] = size(a3); 294 | [p6,q6] = size(a4); 295 | [p7,q7] = size(a5); 296 | Acceleration = textscan(FileID1,'%s %s %s','HeaderLines',p3); 297 | Gyroscope = textscan(FileID2,'%s %s %s','HeaderLines',p4); 298 | Orientation = textscan(FileID3,'%s %s %s %s','HeaderLines',p5); 299 | Pose = textscan(FileID4,'%s %s','HeaderLines',p6); 300 | Emg = textscan(FileID5,'%s %s %s %s %s %s %s %s','HeaderLines',p7); 301 | fclose(FileID1); 302 | fclose(FileID2); 303 | fclose(FileID3); 304 | fclose(FileID4); 305 | fclose(FileID5); 306 | 307 | for i = 1:length(Acceleration{1}); 308 | s = {Acceleration{1,1}{i,1} Acceleration{1,2}{i,1} Acceleration{1,3}{i,1}}; 309 | temp = strtok(s,'[ ]'); 310 | a1(end+1,:) = str2double(temp); 311 | plot(a1) 312 | drawnow 313 | end 314 | 315 | for i = 1:length(Gyroscope{1}); 316 | s = {Gyroscope{1,1}{i,1} Gyroscope{1,2}{i,1} Gyroscope{1,3}{i,1}}; 317 | temp = strtok(s,'[ ]'); 318 | a2(end+1,:) = str2double(temp); 319 | 320 | end 321 | 322 | for i = 1:length(Orientation{1}); 323 | s = {Orientation{1,1}{i,1} Orientation{1,2}{i,1} Orientation{1,3}{i,1}, Orientation{1,4}{i,1}}; 324 | temp = strtok(s,'[ ]'); 325 | a3(end+1,:) = str2double(temp); 326 | 327 | [roll, pitch, yaw] = quat2angle(a3(end,:)); 328 | a3_e(end+1,:) = [roll pitch yaw]; 329 | 330 | end 331 | 332 | for i = 1:length(Pose{1,2}); 333 | a4{end+1,1} = [char([Pose{1,2}{i,1}])]; 334 | end 335 | 336 | for i = 1:length(Emg{1}); 337 | s = {Emg{1,1}{i,1} Emg{1,2}{i,1} Emg{1,3}{i,1} Emg{1,4}{i,1} Emg{1,5}{i,1} Emg{1,6}{i,1} Emg{1,7}{i,1} Emg{1,8}{i,1}}; 338 | temp = strtok(s,'[ ]'); 339 | a5(end+1,:) = str2double(temp); 340 | end 341 | end 342 | 343 | end 344 | m.acceleration = a1; 345 | m.gyroscope = a2; 346 | m.orientation = a3_e; 347 | m.pose = a4; 348 | m.emg = a5; 349 | pyquit 350 | end 351 | %% 352 | function [a1, a2, a3_e, a4, a5] = getPostData(m) 353 | % Data is processed and shown in the workspace (not in real time) 354 | a1 = [0 0 0]; 355 | a2 = [0 0 0]; 356 | a3 = [0 0 0 0]; 357 | a4{1,1} = 'rest>'; 358 | a5 = [0 0 0 0 0 0 0 0]; 359 | a3_e = [0 0 0]; 360 | while 1 361 | FileID1 = fopen('Acceleration.txt'); 362 | FileID2 = fopen('Gyroscope.txt'); 363 | FileID3 = fopen('Orientation.txt'); 364 | FileID4 = fopen('Pose.txt'); 365 | FileID5 = fopen('Emg.txt'); 366 | Acceleration = textscan(FileID1,'%s %s %s'); 367 | Gyroscope = textscan(FileID2,'%s %s %s'); 368 | Orientation = textscan(FileID3,'%s %s %s %s'); 369 | Pose = textscan(FileID4,'%s %s'); 370 | Emg = textscan(FileID5,'%s %s %s %s %s %s %s %s'); 371 | fclose(FileID1); 372 | fclose(FileID2); 373 | fclose(FileID3); 374 | fclose(FileID4); 375 | fclose(FileID5); 376 | [p1,q1] = size(a1); 377 | 378 | [p2] = length(Gyroscope{1}); 379 | if (p1 < p2); 380 | FileID1 = fopen('Acceleration.txt'); 381 | FileID2 = fopen('Gyroscope.txt'); 382 | FileID3 = fopen('Orientation.txt'); 383 | FileID4 = fopen('Pose.txt'); 384 | FileID5 = fopen('Emg.txt'); 385 | [p3,q3] = size(a1); 386 | [p4,q4] = size(a2); 387 | [p5,q5] = size(a3); 388 | [p6,q6] = size(a4); 389 | [p7,q7] = size(a5); 390 | % Read data from the last retrieved row 391 | Acceleration = textscan(FileID1,'%s %s %s','HeaderLines',p3); 392 | Gyroscope = textscan(FileID2,'%s %s %s','HeaderLines',p4); 393 | Orientation = textscan(FileID3,'%s %s %s %s','HeaderLines',p5); 394 | Pose = textscan(FileID4,'%s %s','HeaderLines',p6); 395 | Emg = textscan(FileID5,'%s %s %s %s %s %s %s %s','HeaderLines',p7); 396 | fclose(FileID1); 397 | fclose(FileID2); 398 | fclose(FileID3); 399 | fclose(FileID4); 400 | fclose(FileID5); 401 | 402 | % Convert to real numbers 403 | for i = 1:length(Acceleration{1}); 404 | a1(end+1,:) = str2num([Acceleration{1,1}{i,1} Acceleration{1,2}{i,1} Acceleration{1,3}{i,1}]); 405 | end 406 | 407 | for i = 1:length(Gyroscope{1}); 408 | a2(end+1,:) = str2num([Gyroscope{1,1}{i,1} Gyroscope{1,2}{i,1} Gyroscope{1,3}{i,1}]); 409 | end 410 | 411 | for i = 1:length(Orientation{1}); 412 | a3(end+1,:) = str2num([Orientation{1,1}{i,1} Orientation{1,2}{i,1} Orientation{1,3}{i,1}, Orientation{1,4}{i,1}]); 413 | % % quaternion conversion 414 | [roll, pitch, yaw] = quat2angle(a3(end,:)); 415 | a3_e(end+1,:) = [roll pitch yaw]; 416 | end 417 | 418 | for i = 1:length(Pose{1,2}); 419 | a4{end+1,1} = [char([Pose{1,2}{i,1}])]; 420 | end 421 | 422 | for i = 1:length(Emg{1}); 423 | a5(end+1,:) = str2num([Emg{1,1}{i,1} Emg{1,2}{i,1} Emg{1,3}{i,1} Emg{1,4}{i,1} Emg{1,5}{i,1} Emg{1,6}{i,1} Emg{1,7}{i,1} Emg{1,8}{i,1}]); 424 | end 425 | 426 | 427 | end 428 | 429 | if [p1,q1] == size(a1); 430 | break 431 | end 432 | 433 | end 434 | m.acceleration = a1; 435 | m.gyroscope = a2; 436 | m.orientation = a3_e; 437 | m.pose = a4; 438 | m.emg = a5; 439 | end 440 | end 441 | end 442 | 443 | -------------------------------------------------------------------------------- /myo/lowlevel.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Niklas Rosenstein 2 | # All rights reserved. 3 | r""" 4 | myo.lowlevel - Lowlevel Myo SDK interface 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | """ 8 | 9 | __all__ = ( 10 | # enumerations 11 | 'result_t', 'vibration_type_t', 'pose_t', 'event_type_t', 12 | 'version_component_t', 'orientation_index_t', 'handler_result_t', 13 | 14 | # structure wrappers 15 | 'error_details_t', 'hub_t', 'myo_t', 16 | # REMOVED IN 0.8.6.2 'training_dataset_t', 17 | 'event_t', 18 | 19 | # callback types 20 | # REMOVED IN 0.8.6.2 'training_collect_status_t', 21 | 'handler_t', 22 | 23 | # exceptions 24 | 'MyoError', 'ResultError', 'InvalidOperation', 25 | 26 | # functions 27 | 'init', 'initialized', 28 | # REMOVED IN 0.8.6.2 'now', 29 | ) 30 | 31 | import os 32 | import sys 33 | import warnings 34 | import traceback 35 | 36 | import ctypes 37 | from ctypes import byref, POINTER as asptr, PYFUNCTYPE as py_functype 38 | 39 | from myo import six 40 | from myo.enum import Enumeration, Data as Enumeration_Data 41 | from myo.tools import ShortcutAccess, MacAddress 42 | from myo.platform import platform 43 | 44 | 45 | class _Uninitialized(object): 46 | r""" Datatype used as the pre-init state for the internal 47 | shared library handle that raises an exception as soon as 48 | it is tried to be used. """ 49 | 50 | def __getattribute__(self, name): 51 | message = 'Call myo.init() before using any SDK contents...' 52 | raise RuntimeError(message) 53 | 54 | lib = _Uninitialized() 55 | 56 | initializers = [] 57 | 58 | def is_initializer(type_): 59 | r""" Decorator for classes that provide an ``_init_lib()`` 60 | static method which is called when the :mod:`myo.lowlevel` 61 | module is initialized to initialize the contents of :data:`lib`. """ 62 | 63 | assert hasattr(type_, '_init_lib') 64 | assert callable(type_._init_lib) 65 | initializers.append(type_) 66 | 67 | return type_ 68 | 69 | def init_func(name, restype, *argtypes): 70 | r""" Initializes the *restype* and *argtypes* of a function in 71 | with the specified *name* on the global :data:`lib`. ``'libmyo_'`` 72 | is preprended to *name* as the :data:`lib` is wrapped by a 73 | :class:`ShortcutAccess` object. """ 74 | 75 | func = getattr(lib, name) 76 | func.restype = restype 77 | func.argtypes = argtypes 78 | 79 | 80 | def init(dist_path=None, add_to_path=True): 81 | r""" Determines which myo shared library to load and does so. 82 | If *dist_path* is given, it must be the parent directory of 83 | the myo library to load. When *add_to_path* is True in that 84 | case, the ``PATH`` environment variable will be extended by 85 | that path. """ 86 | 87 | global lib 88 | if not isinstance(lib, _Uninitialized): 89 | raise RuntimeError('already initialized') 90 | 91 | # Determine the architecture so we can actually load 92 | # the right version of the library. 93 | if sys.maxsize <= 2 ** 32: 94 | arch = 32 95 | else: 96 | arch = 64 97 | 98 | # Determine the name which can be used to load the library 99 | # based on the current platform. 100 | if platform == 'Windows': 101 | lib_name = 'myo%d.dll' % arch 102 | elif platform == 'Darwin': 103 | # lib name is just 'myo' as per: 104 | # https://developer.thalmic.com/forums/topic/541/?page=2 105 | lib_name = 'myo' 106 | else: 107 | raise EnvironmentError('unsupported platform %s' % platform) 108 | 109 | # Load the library from an absolute path if *dist_path* 110 | # is specified. 111 | if dist_path: 112 | dist_path = os.path.normpath(os.path.abspath(dist_path)) 113 | 114 | # Extend the PATH variable if that is desired. 115 | if add_to_path: 116 | PATH = os.environ['PATH'] 117 | os.environ['PATH'] = os.pathsep.join([dist_path, PATH]) 118 | 119 | # Or create an absolute filename. 120 | else: 121 | lib_name = os.path.join(dist_path, lib_name) 122 | 123 | # Load the library and initialize the required contents. 124 | try: 125 | lib = ctypes.cdll.LoadLibrary(lib_name) 126 | except OSError: 127 | sys.stderr.write('Error loading "%s". Make sure that it is in your path.\n' % lib_name) 128 | raise 129 | 130 | lib = ShortcutAccess(lib, 'libmyo_') 131 | 132 | for class_ in initializers: 133 | class_._init_lib() 134 | 135 | # Initialize global library functions. 136 | # REMOVED IN 0.8.6.2 init_func('now', ctypes.c_uint64) 137 | 138 | def initialized(): 139 | r""" Returns True if :meth:`init` has been called successfully 140 | already, False if not. """ 141 | 142 | return not isinstance(lib, _Uninitialized) 143 | 144 | 145 | class result_t(Enumeration): 146 | 147 | success = 0 148 | error = 1 149 | error_invalid_argument = 2 150 | error_runtime = 3 151 | 152 | __fallback__ = -1 153 | 154 | class vibration_type_t(Enumeration): 155 | 156 | short = 0 157 | medium = 1 158 | long = 2 159 | 160 | __fallback__ = -1 161 | 162 | class stream_emg(Enumeration): 163 | 164 | # Do not send EMG data. 165 | disabled = 0 166 | # Send EMG data. 167 | enabled = 1 168 | 169 | __fallback__ = -1 170 | 171 | class pose_t(Enumeration): 172 | 173 | rest = 0 174 | fist = 1 175 | wave_in = 2 176 | wave_out = 3 177 | fingers_spread = 4 178 | double_tap = 5 179 | 180 | __fallback__ = -1 181 | num_poses = Enumeration_Data(6) 182 | 183 | class event_type_t(Enumeration): 184 | 185 | paired = 0 186 | # beta 3 187 | unpaired = 1 188 | connected = 2 189 | disconnected = 3 190 | arm_synced = 4 191 | arm_unsynced = 5 192 | orientation = 6 193 | pose = 7 194 | rssi = 8 195 | unlocked = 9 196 | locked = 10 197 | emg = 11 198 | 199 | __fallback__ = -1 200 | 201 | class version_component_t(Enumeration): 202 | 203 | major = 0 204 | minor = 1 205 | patch = 2 206 | 207 | __fallback__ = -1 208 | 209 | class orientation_index_t(Enumeration): 210 | 211 | x = 0 212 | y = 1 213 | z = 2 214 | w = 3 215 | 216 | __fallback__ = -1 217 | 218 | class handler_result_t(Enumeration): 219 | 220 | continue_ = 0 221 | stop = 1 222 | 223 | __fallback__ = -1 224 | 225 | #Locking policy added in beta7 226 | 227 | class locking_policy_t(Enumeration): 228 | none = 0 # Pose events are always sent. 229 | standard =1 # (default) Pose events are not sent while a Myo is locked. 230 | 231 | __fallback__ = -1 232 | 233 | class base_void_p(ctypes.c_void_p): 234 | r""" Base class for the Myo void\* pointer types which implements 235 | a few convenience methods to check for nullptr and even automatically 236 | raising a MemoryError. """ 237 | 238 | def _notnull(self): 239 | r""" Protected. Raises a RuntimeError when the internal pointer 240 | is a nullptr. """ 241 | 242 | if not self: 243 | class_name = self.__class__.__name__ 244 | message = '%s object is a nullptr' % class_name 245 | raise RuntimeError(message) 246 | 247 | def _memraise(self): 248 | r""" Raises a MemoryError when the internal pointer is a nullptr 249 | as a successful memory allocation was expected. """ 250 | 251 | if not self: 252 | class_name = self.__class__.__name__ 253 | raise MemoryError('Could not allocate %s object. Make sure that Myo Connect is running and a Myo is paired.' % class_name) 254 | 255 | @is_initializer 256 | class error_details_t(base_void_p): 257 | 258 | @staticmethod 259 | def _init_lib(): 260 | init_func('error_cstring', ctypes.c_char_p, error_details_t) 261 | init_func('error_kind', result_t, error_details_t) 262 | init_func('free_error_details', None, error_details_t) 263 | 264 | def __del__(self): 265 | if self: 266 | lib.free_error_details(self) 267 | self.value = None 268 | 269 | def __repr__(self): 270 | if not self: 271 | return '' 272 | return '' % (self.kind.name, self.message) 273 | 274 | @property 275 | def kind(self): 276 | self._notnull() 277 | return lib.error_kind(self) 278 | 279 | @property 280 | def message(self): 281 | self._notnull() 282 | return str(lib.error_cstring(self)) 283 | 284 | def raise_on_error(self): 285 | r""" Raises a :class:`error` when this error_details_t 286 | represents an errornous state. Does nothing if it does not. """ 287 | 288 | if self: 289 | raise ResultError(self.kind, self.message) 290 | 291 | @is_initializer 292 | class hub_t(base_void_p): 293 | 294 | @staticmethod 295 | def _init_lib(): 296 | init_func('init_hub', result_t, 297 | asptr(hub_t), asptr(error_details_t)) 298 | # libmyo_result_t libmyo_shutdown_hub(libmyo_hub_t hub, libmyo_error_details_t* out_error); 299 | init_func('shutdown_hub', result_t, 300 | hub_t, asptr(error_details_t)) 301 | #Added in beta 7 302 | init_func('set_locking_policy', result_t, hub_t, locking_policy_t, asptr(error_details_t) ) 303 | 304 | # REMOVED IN 0.8.6.2 305 | # init_func('pair_any', result_t, 306 | # hub_t, ctypes.c_uint, asptr(error_details_t)) 307 | # init_func('pair_by_mac_address', result_t, 308 | # hub_t, ctypes.c_uint64, asptr(error_details_t)) 309 | # init_func('pair_adjacent', result_t, 310 | # hub_t, ctypes.c_uint, asptr(error_details_t)) 311 | init_func('run', result_t, 312 | hub_t, ctypes.c_uint, handler_t, ctypes.py_object, error_details_t) 313 | 314 | @staticmethod 315 | def init_hub(): 316 | r""" Creates a new hub_t object and returns it. Raises a 317 | :class:`ResultError` when an error occurred. """ 318 | 319 | hub = hub_t() 320 | error = error_details_t() 321 | lib.init_hub(byref(hub), byref(error)) 322 | error.raise_on_error() 323 | hub._memraise() 324 | return hub 325 | 326 | def shutdown(self): 327 | r""" Shuts the hub down. The object is not usable after 328 | calling this function. """ 329 | 330 | self._notnull() 331 | error = error_details_t() 332 | result = lib.shutdown_hub(self, byref(error)) 333 | self.value = None 334 | error.raise_on_error() 335 | return result 336 | 337 | def set_locking_policy(self, locking_policy): 338 | r""" Sets the myo locking policy (see locking_policy_t enumeration)""" 339 | 340 | self._notnull() 341 | error = error_details_t() 342 | result = lib.set_locking_policy(self, locking_policy, byref(error)) 343 | error.raise_on_error() 344 | return result 345 | 346 | def pair_any(self, n=1): 347 | r""" Pairs with any *n* devices. The device listener will 348 | receive the connection events. """ 349 | 350 | self._notnull() 351 | if n <= 0: 352 | raise ValueError('n must be a non-zero positive number') 353 | 354 | error = error_details_t() 355 | result = lib.pair_any(self, n, byref(error)) 356 | error.raise_on_error() 357 | return result 358 | 359 | @DeprecationWarning 360 | def pair_by_mac_address(self, mac_address): 361 | r""" Pairs with a Myo of a specific *mac_address*. The 362 | address can be either an integer representing the mac 363 | address or a string. """ 364 | 365 | self._notnull() 366 | mac_address = MacAddress(mac_address) 367 | 368 | error = error_details_t() 369 | result = lib.pair_by_mac_address(self, mac_address.intval, byref(error)) 370 | error.raise_on_error() 371 | return result 372 | 373 | @DeprecationWarning 374 | def pair_adjacent(self, n=1): 375 | r""" Pair with *n* adjacent devices. """ 376 | 377 | self._notnull() 378 | if n <= 0: 379 | raise ValueError('n must be a non-zero positive number') 380 | 381 | error = error_details_t() 382 | result = lib.pair_adjacent(self, n, byref(error)) 383 | error.raise_on_error() 384 | return result 385 | 386 | def run(self, duration_ms, callback, ud=None): 387 | r""" Runs the hub for *duration_ms* milliseconds and invokes 388 | *callback* for events. It must be a callable object which accepts 389 | *ud* and a :class:`event_t` object. When the *callback* returns 390 | True, it signals the hub that is should continue to process 391 | events. If it returns False, it will not continue to process 392 | events. 393 | 394 | This function returns True if the run was complete, False 395 | if the *callback* caused the Hub to stop by returning False. """ 396 | 397 | self._notnull() 398 | 399 | if not isinstance(duration_ms, int): 400 | raise TypeError('duration_ms must be integer') 401 | if not callable(callback): 402 | raise TypeError('callback must be callable') 403 | 404 | # Wrapper that makes sure the callback returns the 405 | # right values and handles the stop-request of the 406 | # listener (when it returns False). 407 | def wrapper(ud, event): 408 | 409 | # Invoke the callback and process the result. It 410 | # should be a bool, and if it is notm we want to 411 | # warn the user. 412 | try: 413 | result = callback(ud, event) 414 | except Exception: 415 | traceback.print_exc() 416 | result = False 417 | 418 | # Warn the user if the callback did not return a 419 | # boolean value (we really only accept that!). 420 | if not isinstance(result, bool): 421 | n1 = callback.__name__ 422 | n2 = result.__class__.__name__ 423 | message = 'callback %s() should return bool, got %s' 424 | warnings.warn(message % (n1, n2)) 425 | 426 | # Invalidate the event object completely. It must 427 | # not be used after this function has ended. 428 | event.value = 0 429 | 430 | if result: 431 | return handler_result_t.continue_ 432 | else: 433 | wrapper.stopped = True 434 | return handler_result_t.stop 435 | 436 | # Run the function which will block the current thread. 437 | error = error_details_t() 438 | result = lib.run(self, duration_ms, handler_t(wrapper), ud, byref(error)) 439 | error.raise_on_error() 440 | 441 | # Return True if the run was complete, meaning the callback 442 | # did not request to halt the Hub. 443 | return not getattr(wrapper, 'stopped', False) 444 | 445 | def __del__(self): 446 | if self: 447 | self.shutdown() 448 | 449 | @is_initializer 450 | class myo_t(base_void_p): 451 | 452 | @staticmethod 453 | def _init_lib(): 454 | # REMOVED IN 0.8.6.2 455 | #init_func('get_mac_address', ctypes.c_uint64, myo_t) 456 | init_func('vibrate', result_t, 457 | myo_t, vibration_type_t, asptr(error_details_t)) 458 | init_func('request_rssi', result_t, myo_t, asptr(error_details_t)) 459 | init_func('set_stream_emg', result_t, myo_t, stream_emg, asptr(error_details_t)) 460 | # REMOVED IN 0.8.6.2 461 | #init_func('training_is_available', ctypes.c_int, myo_t) 462 | #init_func('training_load_profile', result_t, 463 | # myo_t, ctypes.c_char_p, asptr(error_details_t)) 464 | 465 | @property 466 | def mac_address(self): 467 | self._notnull() 468 | return MacAddress(lib.get_mac_address(self)) 469 | 470 | def vibrate(self, vibration_type): 471 | self._notnull() 472 | error = error_details_t() 473 | try: 474 | return lib.vibrate(self, vibration_type, byref(error)) 475 | finally: 476 | error.raise_on_error() 477 | 478 | def request_rssi(self): 479 | self._notnull() 480 | error = error_details_t() 481 | try: 482 | return lib.request_rssi(self, byref(error)) 483 | finally: 484 | error.raise_on_error() 485 | 486 | def set_stream_emg(self, emg): 487 | self._notnull() 488 | error = error_details_t() 489 | try: 490 | return lib.set_stream_emg(self, emg, byref(error)) 491 | finally: 492 | error.raise_on_error() 493 | 494 | def training_load_profile(self, filename=None): 495 | self._notnull() 496 | error = error_details_t() 497 | try: 498 | return lib.training_load_profile(self, filename, byref(error)) 499 | finally: 500 | error.raise_on_error() 501 | 502 | @property 503 | def training_is_available(self): 504 | self._notnull() 505 | return lib.training_is_available(self) != 0 506 | 507 | @DeprecationWarning 508 | @is_initializer 509 | class training_dataset_t(base_void_p): 510 | 511 | @staticmethod 512 | def _init_lib(): 513 | # REMOVED IN 0.8.6.2 514 | # init_func('training_create_dataset', result_t, 515 | # myo_t, asptr(training_dataset_t), asptr(error_details_t)) 516 | # init_func('training_collect_data', result_t, 517 | # training_dataset_t, pose_t, training_collect_status_t, 518 | # base_void_p, asptr(error_details_t)) 519 | # init_func('training_train_from_dataset', result_t, 520 | # training_dataset_t, asptr(error_details_t)) 521 | # init_func('training_free_dataset', None, training_dataset_t) 522 | # init_func('training_store_profile', result_t, 523 | # myo_t, ctypes.c_char_p, asptr(error_details_t)) 524 | # init_func('training_send_training_data', result_t, 525 | # training_dataset_t, asptr(error_details_t)) 526 | # init_func('training_annotate_training_data', result_t, 527 | # training_dataset_t, ctypes.c_char_p, ctypes.c_char_p, 528 | # asptr(error_details_t)) 529 | pass 530 | 531 | @is_initializer 532 | class event_t(base_void_p): 533 | 534 | @staticmethod 535 | def _init_lib(): 536 | init_func('event_get_type', event_type_t, event_t) 537 | init_func('event_get_timestamp', ctypes.c_uint64, event_t) 538 | init_func('event_get_myo', myo_t, event_t) 539 | init_func('event_get_firmware_version', ctypes.c_uint, 540 | event_t, version_component_t) 541 | init_func('event_get_orientation', ctypes.c_float, 542 | event_t, orientation_index_t) 543 | init_func('event_get_accelerometer', ctypes.c_float, 544 | event_t, ctypes.c_uint) 545 | init_func('event_get_gyroscope', ctypes.c_float, 546 | event_t, ctypes.c_uint) 547 | init_func('event_get_pose', pose_t, event_t) 548 | init_func('event_get_rssi', ctypes.c_int8, event_t) 549 | init_func('event_get_emg', ctypes.c_int8, event_t, ctypes.c_uint) 550 | 551 | def _checktype(self, current_op, *types): 552 | r""" Ensures that the event *self* is of one of the specified 553 | event *\*types*. Raises an InvalidOperation exception if it is 554 | not the case. *current_op* is a string that identifies the 555 | attempted operation. """ 556 | 557 | self._notnull() 558 | 559 | # Check if one of the *types are the same as the actual event type. 560 | found = False 561 | self_type = self.type 562 | for type_ in types: 563 | if type_ == self_type: 564 | found = True 565 | break 566 | 567 | if not found: 568 | message = 'operation `%s` not allowed in `%s` event' 569 | raise InvalidOperation(message % (current_op, self_type.name)) 570 | 571 | @property 572 | def type(self): 573 | self._notnull() 574 | return lib.event_get_type(self) 575 | 576 | @property 577 | def timestamp(self): 578 | self._notnull() 579 | return lib.event_get_timestamp(self) 580 | 581 | @property 582 | def myo(self): 583 | self._notnull() 584 | return lib.event_get_myo(self) 585 | 586 | @property 587 | def firmware_version(self): 588 | self._checktype('get firmware_version', 589 | event_type_t.paired, event_type_t.connected) 590 | major = lib.event_get_firmware_version(self, version_component_t.major) 591 | minor = lib.event_get_firmware_version(self, version_component_t.minor) 592 | patch = lib.event_get_firmware_version(self, version_component_t.patch) 593 | return (major, minor, patch) 594 | 595 | @property 596 | def orientation(self): 597 | self._checktype('get orientation', event_type_t.orientation) 598 | return [lib.event_get_orientation(self, i) for i in orientation_index_t] 599 | 600 | @property 601 | def acceleration(self): 602 | self._checktype('get acceleration', event_type_t.orientation) 603 | return [lib.event_get_accelerometer(self, i) for i in six.range(3)] 604 | 605 | @property 606 | def gyroscope(self): 607 | self._checktype('get gyroscope', event_type_t.orientation) 608 | return [lib.event_get_gyroscope(self, i) for i in six.range(3)] 609 | 610 | @property 611 | def pose(self): 612 | self._checktype('get pose', event_type_t.pose) 613 | return lib.event_get_pose(self) 614 | 615 | @property 616 | def rssi(self): 617 | self._checktype('get rssi', event_type_t.rssi) 618 | return lib.event_get_rssi(self) 619 | 620 | @property 621 | def emg(self): 622 | self._checktype('get emg', event_type_t.emg) 623 | return [lib.event_get_emg(self, i) for i in six.range(8)] 624 | 625 | def now(): 626 | r""" Returns the current timestamp. """ 627 | 628 | return lib.now() 629 | 630 | 631 | # Callback function for the training_collect_data(). The 632 | # training_dataset_t.collect_data() expects a slightly different interface. 633 | training_collect_status_t = py_functype(None, ctypes.c_uint8, ctypes.c_uint8) 634 | 635 | # Callback function type for libmyo_run(). hub_t.run() expects 636 | # a slightly different interface. 637 | handler_t = py_functype(ctypes.c_int, ctypes.py_object, event_t) 638 | 639 | 640 | class MyoError(Exception): 641 | pass 642 | 643 | class ResultError(MyoError): 644 | 645 | def __init__(self, kind, message): 646 | super(ResultError, self).__init__() 647 | self.kind = kind 648 | self.message = message 649 | 650 | def __str__(self): 651 | return str((self.kind, self.message)) 652 | 653 | class InvalidOperation(MyoError): 654 | pass 655 | 656 | --------------------------------------------------------------------------------