An Android library to interact with your Thalmic Myo, written in Kotlin and using RxJava2.
This repo contains also a sample app that showcases the usage of the library: Myo EMG Visualizer. With this app you can stream EMG Raw data from your device and save it as a CSV. The app is also available on the play store:
DISCLAIMER: If you don't know what a Myo is, please go here: support.getmyo.com. Please note that you need a Myo in order to use this library/app.
Myonnaise is distributed through JCenter. To use it you need to add the following Gradle dependency to your android app gradle file (NOT the root file).
dependencies {
implementation("com.ncorti:myonnaise:1.0.0")
}
After setting up the Gradle dependency, you will be able to access two main classes: Myonnaise
and Myo
.
-
Myonnaise
is the entry point where you can trigger a bluetooth scan to search for nearby devices. A scan will return you one or modeBluetoothDevice
(from the android framework). If you don't know your Myo's address a priori, you need to show those devices to the user and allow him to pick one. -
Myo
is the class that will allow you to connect to your device, send commands and start the streaming. You need aBluetoothDevice
in order to create aMyo
.
First, you need to find a Myo with a bluetooth scan.
**
To start a bluetooth scan, you can use the startScan()
method:
Myonnaise(context).startScan()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
// Do something with the found device
println(it.address)
})
This method will return a Flowable
that will publish all the BluetoothDevice
that are discovered nearby. Please note that the scan will stop only when you cancel the Flowable.
Alternatively, you can also provide a timeout and the scan will stop after the timeout:
Myonnaise(context).startScan(5, TimeUnit.MINUTES)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
// Do something with the found device
println(it.address)
})
Once you found a BluetoothDevice
that is a Myo, you can get a Myo
instance from it.
val myMyo = Myonnaise.getMyo(foundDevice)
Connecting or disconnecting to a Myo is really easy:
// To Connect
myMyo.connect(getContext())
// To Disconnect
myMyo.disconnect()
Connecting and disconnecting are not syncronous operations. You have to wait that the device is successfully connected before start sending commands.
You can get notified of status updates using the RxJava statusObservable
.
myMyo.statusObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
when (it) {
MyoStatus.CONNECTED -> { /* ... */ }
MyoStatus.CONNECTING -> { /* ... */ }
MyoStatus.READY -> { /* ... */ }
else -> { /* ... */ } // DISCONNECTED
}
}
In order to send command to your Myo
, your Myo
should be in the READY state. If the Myo
is not ready, commands will be ignored.
To send a command you can use the sendCommand()
method. For example, you can let your device vibrate with:
myMyo.sendCommand(CommandList.vibration1())
Commands will be processed by the library and sent to the device (the library has a queue to process all the commands).
List of all available commands is in the CommandList.kt
file.
You can start/stop the streaming using again the sendCommand
method:
// Start Streaming
myMyo.sendCommand(CommandList.emgUnfilteredOnly())
// Stop Streaming
myMyo.sendCommand(CommandList.stopStreaming())
You will start receiving the streaming of data as a Flowable<FloatArray>
through the dataFlowable()
method. To collect the data, just subscribe to the flowable:
myMyo.dataFlowable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
println(it) // it is an array of 8 floats.
}
You can change the streaming frequency to receive less data. By default data is streamed at 200Hz (the max supported by the device). You can subsample the data if you set the frequency property:
myMyo.frequency = 50 // Streaming at 50Hz
Allowed values are from 0 (reset to default) to 200.
The Myo will go to sleep if he receives no intereaction within some seconds. For this reason we are sending a CommandList.unSleep()
every 10 seconds, in order to keep the connection always on.
If you don't want this behavior, just turn off the keep alive:
myMyo.keepAlive = false
- 100% Kotlin (but you don't need Kotlin to use it)!
- Uses RxJava. You don't need to poll for status update, the library will call you.
- Unleash the full Myo power, Raw Data Streaming at 200Hz! 💪
- Small footprint: The AAR is just 36Kb
- API >= 21 compatible (due to BluetoothLE limitations).
- Easy to integrate (just a gradle
implementation
line).
You can find the test app (Myo Emg Visualizer) inside the app
module.
This app allows you to:
- Scan for a Myo
- Connect to a Myo, control the frequency and send vibration.
- See a graph of the EMG data.
- Export the EMG data as a CSV file
Some technical features are:
- The app is 100% Kotlin.
- Architecture pattern used: MVP.
- Dagger Android to inject the views.
- Use AndroidX.
- Use the Material Design Components library.
Searching for a Myo
Starting the Streaming
Exporting to CSV
This projects is built with GitHub Actions. The CI environment takes care of building the library .AAR, the example app and to run the JUnit tests. Test and lint reports are exposes in the artifacts section at the end of every build.
Circle CI is responsible of uploading Jacoco reports to Codecov. When opening a Pull Request, Codecov will post a report of the diff of the test coverage.
Please don't ignore it! PR with new features and without are likely to be discarded 😕
Then just clone the repo locally and build the .AAR with the following command:
git clone [email protected]:cortinico/myonnaise.git
cd myonnaise/
./gradlew build
The assembled .AAR (library) will be inside the myonnaise/build/outputs/aar folder. The assembled .APK (application) will be inside the app/build/outputs/apk/debug folder.
Once you're able to build successfully, you can run JUnit tests locally with the following command.
./gradlew test
Please note that there are tests inside the myonnaise
and the app
module. The app
module contains test for the presenters. The myonnaise
module contains tests for the library.
Make sure your tests are all green ✅ locally before submitting PRs.
Looking for contributors! Don't be shy. 😁 Feel free to open issues/pull requests to help me improve this project.
- When reporting a new Issue, make sure to attach Screenshots of the problem you are reporting.
- Debugging
- When submitting a new PR, make sure tests are all green. Write new tests if necessary (would be great if the code coverage doesn't decrease).
This project is licensed under the MIT License - see the License file for details