Part Six: The End, and the Beginning
Well, I hope you did your homework because it’s the last you’ll get in this series. We’ve talked about what Myo Scripts are, walked you through your first one, detected poses, done keyboard input, and handled vibration and locking. Today, we’ll finish off with (most of) the other callbacks, and give you the completed script.
But first, the solution from last time:
if (pose ~= "rest" and pose ~= "unknown") then
-- hold if edge is on, timed if edge is off
myo.unlock(edge == "off" and "timed" or "hold")
end
Recognize that? I hope so, it’s the technique I mentioned last time. On any pose except rest and unknown, if edge
is off call myo.unlock(“timed”)
, otherwise call myo.unlock(“hold”)
. Again you could have done it with an If block or a function, but this is the most concise.
Comments are the other thing to note. If you haven’t seen them before, you can comment a line in Lua with two dashes (–
). This means the line won’t get executed, so it’s good for leaving notes for yourself or temporarily disabling parts of your code you may want to re-enable later.
The Penultimate Callbacks
We’ll go into the last callback, onPeriodic
, in the next tutorial series, but before that let’s briefly discuss the other two we haven’t talked about yet: activeAppName
, onActiveChange(isActive)
, onLock
and onUnlock
. activeAppName
is called when Myo Connect wants to know what app your script is CURRENTLY controlling. All you really need to do for this is to store the app title you get from onForegroundWindowChange
when you detect an app you want to control, and return it in activeAppName()
. You can also return scriptTitle
if it’s the same name as the application and you only control one.
'onActiveChange
' is even easier. You probably don’t even need to implement it. The idea is it will get called with false
when your script is not longer active. If there is any cleanup you need to do at that point, this is where you put it. You probably won’t have any though. This function also gets called with true
when your script becomes active, but since you triggered that in onForegroundWindowChange
you can do whatever setup you need in there.
onLock and onUnlock are pretty straightforward as well. If you need to do something when the armband is locked or unlocked, do it in there. If you want to create a script where the armband is unlocked with double tap and then not locked again until the user double taps again (like for a mouse control script or something), you would implement onUnlock so it calls myo.unlock(“hold”)
(and turns on the mouse):
function onUnlock()
myo.unlock("hold")
myo.controlMouse(true)
end
We’ll talk about mouse control more in the next tutorial.
Try modifying onForegroundWindowChange
and implementing activeAppName
. We’re not going to use onActiveChange
or onLock/onUnlock
.
For our simple script that tries to control everything, mine looks like this:
appTitle = ""
function onForegroundWindowChange(app, title)
myo.debug("onForegroundWindowChange: " .. app .. ", " .. title)
appTitle = title
return true
end
function activeAppName()
return appTitle
end
The Completed Script
And that’s it. Your finished script should look something like this:
scriptId = 'com.thalmic.examples.myfirstscript'
scriptTitle = "My First Script"
scriptDetailsUrl = ""
locked = true
appTitle = ""
function onForegroundWindowChange(app, title)
myo.debug("onForegroundWindowChange: " .. app .. ", " .. title)
appTitle = title
return true
end
function activeAppName()
return appTitle
end
function onPoseEdge(pose, edge)
myo.debug("onPoseEdge: " .. pose .. ": " .. edge)
pose = conditionallySwapWave(pose)
if (pose ~= "rest" and pose ~= "unknown") then
-- hold if edge is on, timed if edge is off
myo.unlock(edge == "off" and "timed" or "hold")
end
local keyEdge = edge == "off" and "up" or "down"
if (pose == "waveOut") then
onWaveOut(keyEdge)
elseif (pose == "waveIn") then
onWaveIn(keyEdge)
elseif (pose == "fist") then
onFist(keyEdge)
elseif (pose == "fingersSpread") then
onFingersSpread(keyEdge)
end
end
function onWaveOut(keyEdge)
myo.debug("Next")
--myo.vibrate("short")
myo.keyboard("tab", keyEdge)
end
function onWaveIn(keyEdge)
myo.debug("Previous")
--myo.vibrate("short")
--myo.vibrate("short")
myo.keyboard("tab",keyEdge,"shift")
end
function onFist(keyEdge)
myo.debug("Enter")
--myo.vibrate("medium")
myo.keyboard("return",keyEdge)
end
function onFingersSpread(keyEdge)
myo.debug("Escape")
--myo.vibrate("long")
myo.keyboard("escape", keyEdge)
end
function conditionallySwapWave(pose)
if myo.getArm() == "left" then
if pose == "waveIn" then
pose = "waveOut"
elseif pose == "waveOut" then
pose = "waveIn"
end
end
return pose
end
It’s pretty basic, but shows you how to do key things like print to the debug console and press certain keys in response to specific poses. That’s all you need to Myo-enable a lot of interesting apps.
One thing to note is that, while these scripts are written in Lua, the final version should have a .myo extension. This will let users double click on them to have them automatically loaded into the Application Manager. The downside of this is if you try and edit a .myo file it won’t have any of that nice pretty syntax highlighting without a bit of work. In Notepad++, you can go to Settings -> Style Configurator and add .myo as a user filetype for Lua.
Our next tutorial is going to target a specific game (Race The Sun, if you’re curious) and show you how to use onPeriodic
and the IMU, which opens up even more possibilities. Until then, get scripting, and good luck! If you have any questions post them in the Developer Forums, or hit me up on Twitter at @thalmicdev!