North (formerly Thalmic Labs), the creator of the Myo armband, was acquired by Google in June 2020. Myo sales ended in October 2018 and Myo software, hardware and SDKs are no longer available or supported. Learn more.
#MyoCraft: Function Binding for magic powers

Note: We discuss a more advanced version of this approach here.
Hey folks! We’re back with this week’s edition of #MyoCraft. If you need a refresher on what we’re doing, check out this post here. Today, we’re featuring our connector for Saint’s Row IV. It demonstrates a very useful technique you will see in a lot of Myo Scripts: Function binding.
Here’s the script:
scriptId = 'com.thalmic.saintsrow4'
minMyoConnectVersion = '0.7.0'
scriptDetailsUrl = 'https://market.myo.com/app/5474d22be4b081c4011c77ba'
scriptTitle = 'Saints Row IV Connector'
description = [[
A third-person shooter that consistently chooses fun over physics and laughter over common decency.
Play through the intro until you get to the Steelport simulation, then enable cheats and try dem
superpowers. Telekin dat car into dem people, or vice versa. And be sure to serve plenty o fireballs
to those hungry customers.
Suggestions/notes:
- adjust the mouse sensitivity
- cheats can be enable from the in-game menu (hit tab) under extras > cheats
]]
link = [[http://store.steampowered.com/app/314580/]]
controls = [[
This script assumes default control mappings.
Use your arm to aim and make a Fist to start shooting, release it to stop.
Use FingersSpread to activate your current super power.
Holding waveOut allows you to move your arm without moving the mouse,
which can become necessary if you arm ends up in an uncomfortable position.
Release to resume control of the mouse.
Standard keyboard controls are used for everything else.
- movement (wasd), reload (r), melee (f), etc.
- Number keys for selecting/changing guns
- F1,F2,F3,F4 to change your current superpower, or change element of current power
]]
knownIssues = [[
- Aiming is sensitive to the Myo armband's position on your arm. To workaround this
position the armband such that the main module does not tilt when making/releasing poses.
- OS's mouse is still active while playing, if it clicks the Dock you will jump out of the game.
]]
----------------------------
-- Useful for disabling debug output (by commenting the implementation)
function debug(msg)
-- myo.debug(msg)
end
----------------------------
-- Shooting
function startShooting()
debug("start shooting")
myo.mouse("left","down")
end
function stopShooting()
debug("stop shooting")
myo.mouse("left","up")
end
----------------------------
-- Superpowers
function activateSuperpower()
debug("activate superpower")
myo.mouse("center","click")
end
----------------------------
-- Mouse control
function mouseOn()
debug("mouse on")
myo.controlMouse(true)
end
function mouseOff()
debug("mouse off")
myo.controlMouse(false)
end
----------------------------
-- Map poses to functions
local BINDINGS = {
fist_on = startShooting,
fist_off = stopShooting,
fingersSpread_on = activateSuperpower,
waveOut_on = mouseOff,
waveOut_off = mouseOn,
}
-- Set how the Myo Armband handles locking
myo.setLockingPolicy("none")
function onPoseEdge(pose, edge)
fn = BINDINGS[pose .. "_" .. edge]
if fn then
fn()
end
end
----------------------------
function activeAppName()
return "Saints Row IV"
end
function onActiveChange(isActive)
if isActive then
myo.centerMousePosition()
myo.controlMouse(true)
end
end
function onForegroundWindowChange(app, title)
return platform == "Windows" and string.match(app, "^SaintsRowIV.exe$")
end
function onActiveChange(isActive)
-- Start with the mouse in a known position and enabled.
if isActive then
myo.centerMousePosition()
mouseOn()
end
end
There’s a lot of good stuff in there, but the thing I want to talk about today is the onPoseEdge implementation. In other scripts, especially when you’re just starting you may use a series of if statements (one for each pose). That’s OK, but it gets a bit big and messy, especially when you want to make something easy to modify or take pieces from later.
Luckily that’s not the only way to do it. The approach we use in the Saint’s Row IV connector relies on the fact that in Lua a function is a first class value. That means you can assign any variable to point to a function, and in fact this:
function myCoolFunction()
-- Some code
end
is just some nice syntactic sugar for this:
myCoolFunction = function ()
-- Some code
end
This means that you can do things like this:
function onPoseEdge(pose, edge)
fn = BINDINGS[pose .. "_" .. edge]
if fn then
fn()
end
end
Where bindings looks like this:
local BINDINGS = {
fist_on = startShooting,
fist_off = stopShooting,
fingersSpread_on = activateSuperpower,
waveOut_on = mouseOff,
waveOut_off = mouseOn,
}
So, when you start the fist pose, onPoseEdge
is called with pose == “fist”
and edge == “on”
. That means that the first line of onPoseEdge
turns into
fn = BINDINGS["fist" .. "_" .. "on"]`
which is, of course:
fn = BINDINGS["fist_on"]
which, when you look it up in the BINDINGS
table really points to startShooting
. So fn()
is really calling startShooting()
, and from there away you go.
The net effect is that you can have the EXACT same, very tight onPoseEdge
implementation for every single one of your scripts, and just replace the definitions with names of the functions of your choosing in the BINDINGS
declaration.
You can also use this to swap in different functions on the fly (to have multiple states in your script or to cover multiple similar applications, for example), and it cleanly handles gestures you don’t use.
It’s a neat trick, and you’ll probably see it in a lot of scripts, so it’s good to know how it works. If you have a neat trick of your own, or some other cool example or demo you want to show off in a future #MyoCraft, let me know on Twitter at @thalmicdev, or with an email to MyoCraft@thalmic.com.
Otherwise, see you next Saturday!