NiklasRosenstein / myo-python

Python bindings for the Myo SDK
Other
259 stars 102 forks source link

Multiple Myos #28

Open aditya17a opened 9 years ago

aditya17a commented 9 years ago

Hi, is it possible to use multiple Myos with these bindings? If so, how?

NiklasRosenstein commented 9 years ago

Hi Aditya, I don't have multiple Myos so I can't test it, but it should be possible without further ado. If you chose to implement a DeviceListener, you will receive an on_pair() and on_unpair() call for every Myo connected. Using the Feed class, you can get a list of the paired devices with Feed.get_devices().

shibshib commented 9 years ago

Hi Niklas,

I haven't gone through the code yet but I'm wondering whether it's possible to make it work with two USB dongles?

Thanks!

Ala

NiklasRosenstein commented 9 years ago

I have no idea, I only have one Myo. :)

sharkwheels commented 8 years ago

Hi Niklas,

Related to this: Is there a way to get the MAC Address of each Myo? Also could you please toss up an example on using Feed.get_devices() ?

Thanks!

NiklasRosenstein commented 8 years ago

@sharkwheels

Is there a way to get the MAC Address of each Myo?

The libmyo.h header from the 0.9.0 SDK declares a uint64_t libmyo_get_mac_address(libmyo_myo_t) function, but it doesn't seem to be actually exported to the myo dynamic libraries or was forgotten to be removed from the headers. Ergo, I can't add a function to read the MAC address of a Myo.

Also could you please toss up an example on using Feed.get_devices() ?

Could you tell me what is unclear about this function? You can add this line in the feed_myo.py example

print("Connected devices:", feed.get_devices())

and get something like

<MyoProxy (connected) at 0xc1a180>
sharkwheels commented 8 years ago

Could you tell me what is unclear about this function?

I was wondering how/where it might be used in the hello_myo example set up. I should have been clearer about that.

Ah, bummer, re: MAC Address. Was hoping that was possible.

NiklasRosenstein commented 8 years ago

@sharkwheels The "hello_myo" example implements a DeviceListener and does not use the Feed class. No way to use the Feed.get_devices() method then.

NiklasRosenstein commented 8 years ago

@sharkwheels As an alternative, you could use the memory address of the Myo C-object to identify a Myo. For a MyoProxy, you can use its hash() (added 9e6cfdb2606ad216e5e650bf5dd82b432a91113a). For a C-types lowlevel wrapper Myo object, you can use the .value property.

GanKunlu commented 8 years ago

Hi Niklas,

I want to get the sEMG data from two Myos, but some troubles make me at a loss. When I use the feed.get_connected_devices() to get every MyoProxy Objects and .emg to get the EMG data from each one, I got None EMG data. The code is:

from myo import init, Hub, Feed
import time
init()
feed = Feed()
hub = Hub()
hub.run(1000, feed)
try:
    myo = feed.get_connected_devices()
    print(myo)
    while hub.running:
        if myo:
            print(myo[0].emg)
            time.sleep(0.1)
            print(myo[1].emg)
finally:
    hub.shutdown()
NiklasRosenstein commented 8 years ago

Hi @GanKunlu,

you have to enable EMG streaming first. See MyoProxy.set_stream_emg() You have to pass it an enumeration value of StreamEmg.

myo.set_stream_emg(StreamEmg.enabled)

Note that myo.emg will be None until the first EMG data is received.

NiklasRosenstein commented 8 years ago

I've added an entry in the FAQ section of the docs. http://myo-python.readthedocs.io/en/latest/faq.html

mark-toma commented 8 years ago

Beware of attempting to stream EMG from two Myos using a single dongle. There isn't enough bandwidth in the hardware to support the required throughput.

https://developer.thalmic.com/forums/topic/2958/

umutdemirel commented 7 years ago

@NiklasRosenstein

If you chose to implement a DeviceListener, you will receive an on_pair() and on_unpair() call for every Myo connected.

By using this method, for 2 Myos, 2 on_pair() calls are received however myo values of the calls are unfortunately the same.

Hello, Myo! <Myo object at 0x1093f28c0> 390540611026 (1L, 5L, 1970L) Hello, Myo! <Myo object at 0x1093f28c0> 389946548255 (1L, 5L, 1970L)

Using the Feed class, you can get a list of the paired devices with Feed.get_devices().

By using this method, 2 different Myos can be used. However 200Hz for EMG and 50Hz for IMU cannot be reached.

[<MyoProxy (connected) at 0x7fc511a07af0>, <MyoProxy (connected) at 0x7fc511a0a890>] <MyoProxy (connected) at 0x7fc511a07af0> (0, 0, -2, -2, -75, -4, 0, -5) time between 2 captures : 0.0121109485626 <MyoProxy (connected) at 0x7fc511a0a890> (3, -3, 2, 4, 0, 0, -2, -8) time between 2 captures : 0.0121109485626 <MyoProxy (connected) at 0x7fc511a07af0> (-7, 0, 1, 0, -81, 0, 2, -6) time between 2 captures : 0.0154161453247 <MyoProxy (connected) at 0x7fc511a0a890> (0, 2, 5, 3, -2, -2, -5, -7) time between 2 captures : 0.0154161453247 <MyoProxy (connected) at 0x7fc511a07af0> (3, -6, -2, 0, 61, 1, -1, 4) time between 2 captures : 0.00678586959839 <MyoProxy (connected) at 0x7fc511a0a890> (0, 2, 5, 3, -2, -2, -5, -7) time between 2 captures : 0.00678586959839 <MyoProxy (connected) at 0x7fc511a07af0> (3, -6, -2, 0, 61, 1, -1, 4) time between 2 captures : 0.00690793991089 <MyoProxy (connected) at 0x7fc511a0a890> (-6, -2, -1, -6, -1, -3, -2, -5) time between 2 captures : 0.00690793991089 <MyoProxy (connected) at 0x7fc511a07af0> (-2, 2, 0, -2, -72, 2, -4, -3) time between 2 captures : 0.00649404525757 <MyoProxy (connected) at 0x7fc511a0a890> (3, 3, 1, 3, -2, -1, 1, -8) time between 2 captures : 0.00649404525757 <MyoProxy (connected) at 0x7fc511a07af0> (-2, 2, 0, -2, -72, 2, -4, -3) time between 2 captures : 0.00651812553406 <MyoProxy (connected) at 0x7fc511a0a890> (3, 3, 1, 3, -2, -1, 1, -8) time between 2 captures : 0.00651812553406 <MyoProxy (connected) at 0x7fc511a07af0> (1, -1, 0, -2, 70, 0, 2, 2) time between 2 captures : 0.00809502601624 <MyoProxy (connected) at 0x7fc511a0a890> (-5, 0, 3, -1, -2, 0, -3, -5) time between 2 captures : 0.00809502601624 <MyoProxy (connected) at 0x7fc511a07af0> (-7, -2, -3, 0, -60, -4, 0, -3) time between 2 captures : 0.00592494010925 <MyoProxy (connected) at 0x7fc511a0a890> (-5, 0, -2, -5, -4, -4, -3, -5) time between 2 captures : 0.00592494010925 <MyoProxy (connected) at 0x7fc511a07af0> (-7, -2, -3, 0, -60, -4, 0, -3) time between 2 captures : 0.00881695747375 <MyoProxy (connected) at 0x7fc511a0a890> (1, -2, 4, 0, -1, -2, -3, 2) time between 2 captures : 0.00881695747375 <MyoProxy (connected) at 0x7fc511a07af0> (-1, 3, -3, -6, 31, 0, -2, 2) time between 2 captures : 0.00545907020569

mark-toma commented 7 years ago

@umutdemirel

Just to clarify data streaming limitations with multiple Myos:

When using two Myos with one dongle (as must be the case when relying upon Myo Connect), EMG data must not be streaming. Another way to say this is that when EMG data is streaming, only one Myo can be used without having arbitrary data lost by a single dongle.

Since IMU data is always transmitted by Myo firmware, you can plan on having all of this data available. When using two Myos, I have found that all IMU data is received from both devices.

NiklasRosenstein commented 7 years ago

@umutdemirel

By using this method, for 2 Myos, 2 on_pair() calls are received however myo values of the calls are unfortunately the same.

Hello, Myo! <Myo object at 0x1093f28c0> 390540611026 (1L, 5L, 1970L)
Hello, Myo! <Myo object at 0x1093f28c0> 389946548255 (1L, 5L, 1970L)

That is strange, because the Feed class also just listens on the pair event.

https://github.com/NiklasRosenstein/myo-python/blob/d80f650d1205344317bebc8f181a1cd9f46cd6ac/myo/device_listener.py#L339-L341

Unfortunately, I won't be able to reproduce the issue. As mentioned above, I have only one Myo device. I'd be happy to review patches, though.

@mark-toma

When using two Myos with one dongle (as must be the case when relying upon Myo Connect).

Is there an alternative for Myo Connect?

mark-toma commented 7 years ago

@NiklasRosenstein

I can think of two such alternatives to Myo Connect. They both travel down the stack closer to Myo.

  1. Talk to the dongle's virtual serial port as is done by /dzhu/myo-raw. This is communicating over the dongle's virtual serial port to interact with its BLE stack. Developers can sniff Myo Connect transactions with the dongle and refer to the dongle datasheet (BlueGiga BLED112) for protocol "reversing" insight. This essentially replaces Myo Connect.
  2. Talk to the BLE protocol documented by Thalmic Labs here. Use your favorite BLE stack. This replaces Myo Connect and the BLE dongle.

Both of the above solutions afford the developer the freedom to avert the hardware bandwidth limitation affecting streaming EMG from multiple Myos.

umutdemirel commented 7 years ago

@NiklasRosenstein

More interesting results occured when I implemented on_event call of DeviceListener class.

(from on_event)event's myo : <Myo object at 0x10c012950> (from on_event)event's type : <EventType: paired> (from on_pair)Hello, Myo! <Myo object at 0x10c0128c0> 437608531172 (1L, 5L, 1970L)

(from on_event)event's myo : <Myo object at 0x10c012950> (from on_event)event's type : <EventType: connected> (from on_connect)connected: <Myo object at 0x10c0128c0> 437608531172 (1L, 5L, 1970L)

(from on_event)event's myo : <Myo object at 0x10c012950> (from on_event)event's type : <EventType: paired> (from on_pair)Hello, Myo! <Myo object at 0x10c0128c0> 437610019592 (1L, 5L, 1970L)

(from on_event)event's myo : <Myo object at 0x10c012950> (from on_event)event's type : <EventType: connected> (from on_connect)connected: <Myo object at 0x10c0128c0> 437610019592 (1L, 5L, 1970L)

on_event call always catches one of the Myos. And all other events like on_pair or on_connect catches the other Myo.

This is really weird, I wish you had the 2nd Myo :)

NiklasRosenstein commented 7 years ago

That's even more strange. on_event() and on_pair() are called for the "paired" event from the same function: https://github.com/NiklasRosenstein/myo-python/blob/d80f650d1205344317bebc8f181a1cd9f46cd6ac/myo/__init__.py#L291-L367

I recommend you use Myo.value though instead of the Python object ID to check if its actually the same Myo.

NiklasRosenstein commented 7 years ago

Ah yes, you actually have to use Myo.value to compare two Myos. Every event you will get a new instance of the Myo class, because it only wraps the underlying pointer to the Myo C structure. Please do your tests again and print myo.value instead of myo.

BczImHappy commented 6 years ago

I am trying to run my hub every 5 ms but I am getting the error AttributeError: 'Listener' object has no attribute 'emg' when I lower the duration time below 200 ms using hub.run(listener,100)