Part Five: Shake It

And we’re back with the penultimate post in our tutorial series on Getting Started With Myo Scripts (Parts one, two, three and four here)! Last time I asked you to implement and use a conditionallySwapWave function. Did you get it?

This is what I did:

  
  




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

and here is what onPoseEdge now looks like:

  
  



function onPoseEdge(pose, edge)  
        myo.debug("onPoseEdge: " .. pose .. ": " .. edge)

        pose = conditionallySwapWave(pose)

        if (edge == "on") then
            if (pose == "waveOut") then
                onWaveOut()     
            elseif (pose == "waveIn") then
                onWaveIn()
            elseif (pose == "fist") then
                onFist()
            elseif (pose == "fingersSpread") then
                onFingersSpread()           
            end
        end
    end

This is a pretty standard technique, so you will probably see that exact function in many example scripts. Keep it in your back pocket for your own use in the future.

Vibration

Watching the debug output isn’t always easy when you are trying to build a script. A useful technique is to give yourself a little vibration feedback whenever a gesture is detected. The best way to do that is with myo.notifyUserAction(). You can make the Myo armband vibrate with the myo.vibrate(vibrationType) function, where vibrationType can be one of short, medium or long. Try putting in different combinations of vibration in each of the pose functions we created.

Once you’ve played around with it a bit, check out what I did:

  
  



function onWaveOut()  
        myo.debug("Next")
        myo.vibrate("short")
        myo.keyboard("tab", "press")
    end

    function onWaveIn()  
        myo.debug("Previous")
        myo.vibrate("short")
        myo.vibrate("short")
        myo.keyboard("tab","press","shift")
    end

    function onFist()  
        myo.debug("Enter")  
        myo.notifyUserAction()
        myo.keyboard("return","press")
    end

    function onFingersSpread()  
        myo.debug("Escape")
        myo.vibrate("long")
        myo.keyboard("escape", "press")
    end

In a real script, you probably don’t want to vibrate so much. Generally, a gesture a user performs will have an immediately visible result on screen. If that’s the case, think about whether you really need to vibrate or not.

Locking and Unlocking

By default, until a user does the unlock gesture with an application running that can accept Myo input, none of the other poses are detected or let through. This is the standard unlock policy, and it’s pretty handy. If that flow doesn’t work for your script (for example, if you are controlling a game where the Myo should be active at all times), you can disable this behaviour by setting the lock policy:

  
  



myo.setLockingPolicy("none")

You can turn it back on with

  
  



myo.setLockingPolicy("standard")

We’re not going to do that though. In fact, the standard unlock policy on it’s own is perfectly good for this little script, and we could stop here if we wanted. The standard policy is designed to easily let the user input a command before the armband locks again, and that’s all we’re doing. Sometimes though, you may want to let them hold a single gesture (like to adjust the volume) or enter a series of commands.

This is pretty straightforward to accomplish with the myo.unlock(unlockType) function. This will let you programmatically unlock (or keep unlocked) a Myo armband. You can send either timed or hold. timed will reset the clock and keep the armband unlocked for a few more seconds, and hold will keep it unlocked until you manually lock it (or set it back to timed and wait).

Let’s tweak our script a bit so that the user can hold any of our key presses as long as they hold the pose that triggers them. To do that, we’re going to modify onPoseEdge and our pose handlers (onWaveOut, etc) so that we use the edge value of onPoseEdge to control the edge value of the key press.

The first problem is that onPoseEdge gives you either on or off, while myo.keyboard() needs either down or up. What we need to do is write some code that converts the one into the other and saves it in a local variable. Give that a try now.

This is a reasonable solution you could have come up with:

  
  



local keyEdge
        if (edge == "on") then
            keyEdge = "down"
        else
            keyEdge = "up"
        end

“Local” means that the variable only exists in the current “scope” (ie, in the current execution of the function or code block we’re in. After that it’s gone forever and you can reuse the name). All the arguments to a function like pose and edge are local automatically. Every other variable is available anywhere in your script, which can get a bit confusing. It’s best to keep things local if you can.

If you came up with a “convertEdge” function similar to conditionallySwapWave that would also be a perfectly reasonable idea.

There are actually a bunch of ways you could reasonably do this. But I’m going to show you one line crazy that means the same thing:

  
  



local keyEdge = edge == "off" and "up" or "down"

Yeah, just trust me. It relies on some quirks of how Lua handles logical operators and order of operations. You can think of it as a one line if/else statement of the form

  
  




 myVariable =  and  or 

I tell you because you’ll probably see this in other scripts since it’s a really concise way to convert our pose edge to what we need for myo.keyboard(). Feel free to use it or not, but now you should at least recognize it in the future.

Anyway, our updated onPoseEdge and pose functions now looks like this:

  
  




function onPoseEdge(pose, edge)  
        myo.debug("onPoseEdge: " .. pose .. ": " .. edge)

        pose = conditionallySwapWave(pose)

        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

If you try and use that, you’ll notice the armband locking in the middle of holding a pose, and you can still only do one or two of them.

To keep the Myo armband unlocked while it’s still in use, every time a valid pose is detected we want to call myo.unlock(unlockType). Unlock type will be either hold if the user is holding a pose, or timed if they’ve released it.

Homework time! See if you can figure out how to do that. Join me tomorrow for the answer, in the final part of our Getting Started with Myo Scripts tutorial!

Newsletter

Enter your email address and get all latest content delivered to your inbox every now and then.