Part Five: Mouse Control Enabled

We’re nearing the finish line on this tutorial. In part five (parts one, two, three and four here) we’re going to talk about mouse control.

But first, this is what my script looks like at this stage:

  
 


 
 scriptId = 'com.thalmic.examples.racethesun'  
    scriptTitle = "Race The Sun"  
    scriptDetailsUrl = ""

    centreYaw = 0  
    centreRoll = 0

    deltaRoll = 0

    YAW_DEADZONE = .1

    TWOPI = math.pi * 2

    flyingLeft = false  
    flyingRight = false

    printCount = 0

    function onForegroundWindowChange(app, title)  
        myo.debug("onForegroundWindowChange: " .. app .. ", " .. title)
        local titleMatch = string.match(title, "Race The Sun") ~= nil or string.match(title, "RaceTheSun") ~= nil
        myo.debug("Race the Sun: "  .. tostring(titleMatch))
        return titleMatch;
    end

    function onPoseEdge(pose, edge)  
        myo.debug("onPoseEdge: " .. pose .. ", " .. edge)
        if (edge == "on") then
            if (pose == "fist") then
                centre()
            elseif (pose == "fingersSpread") then
                escape()
            end
        end
    end

    function activeAppName()  
        return "Race The Sun"
    end

    function centre()  
        myo.debug("Centred")
        centreYaw = myo.getYaw()
        myo.vibrate("short")    
    end

    function escape()  
        myo.debug("Escape!")
        centreYaw = 0
        myo.keyboard("escape","press")
    end    

    function onPeriodic()  
        if (centreYaw == 0) then
            return
        end
        local currentYaw = myo.getYaw()
        local currentRoll = myo.getRoll()
        local deltaYaw = calculateDeltaRadians(currentYaw, centreYaw)
        deltaRoll = calculateDeltaRadians(currentRoll, centreRoll);
        printCount = printCount + 1
        if printCount >= 200 then
            myo.debug("deltaYaw = " .. deltaYaw .. ", centreYaw = " .. centreYaw .. ", currentYaw = " .. currentYaw)
            myo.debug("deltaRoll = " .. deltaRoll)
            printCount = 0
        end
        if (deltaYaw > YAW_DEADZONE) then
            flyLeft()
        elseif (deltaYaw < -YAW_DEADZONE) then
            flyRight()
        else
            flyNeutral()
        end
    end

    function flyLeft()  
        if (flyingRight) then
            myo.debug("Not flying right");
            myo.keyboard("right_arrow","up")
            flyingRight = false
        end
        if (not flyingLeft) then
            myo.debug("Flying left");
            myo.keyboard("left_arrow","down")
            flyingLeft = true;
        end
    end

    function flyRight()  
        if (flyingLeft) then
            myo.debug("Not flying left");
            myo.keyboard("left_arrow","up")
            flyingLeft = false
        end
        if (not flyingRight) then
            myo.debug("Flying right");
            myo.keyboard("right_arrow","down")
            flyingRight = true
        end
    end

    function flyNeutral()  
        if  (flyingLeft) then
            myo.debug("Not flying left");
            myo.keyboard("left_arrow","up")
            flyingLeft = false
        end
        if (flyingRight) then
            myo.debug("Not flying right");
            myo.keyboard("right_arrow","up")
            flyingRight = false
        end
    end

    function calculateDeltaRadians(currentYaw, centreYaw)  
        local deltaYaw = currentYaw - centreYaw

        if (deltaYaw > math.pi) then
            deltaYaw = deltaYaw - TWOPI
        elseif(deltaYaw < -math.pi) then
            deltaYaw = deltaYaw + TWOPI
        end
        return deltaYaw
    end  

Mouse Control

You know what sucks? Switching between using the Myo armband to play Race The Sun, and then back to the mouse to try and navigate menus or restart the game.

Wouldn’t it be nice to be able to use your Myo to control the mouse?

Yes, Myo Script has cursor control built right in. It’s trivial to enable, too: myo.controlMouse(enabled).

Set that to true in a script and you’ll immediately notice the cursor being moved around by your Myo armband. You will then notice immediately after that there is no way to “lift up” the mouse and center it again, so to move further and further left you will have to start spinning in your chair. The way you solve this is by letting the user turn off mouse control, move their arm, and then turn it back on again.

In other situations you might consider a “clutch” approach where when the user is holding a certain pose the mouse control is disabled, allowing them to recenter their arm. We actually only really want mouse control on in certain situations though, so we’re going to just enable and disable it with the wave out pose. Try that now. Also go ahead and make wave in fire a left click. It’s up to you if you want to switch these based on what arm the user is wearing their Myo on, but a wave in is usually much easier to do without jostling your arm (thereby moving the cursor), so I’m not going to. Remember it should still fire jump (only) on wave “up” or “down”.

You’ll probably find that works pretty well, but you may end up accidentally turning the mouse on while playing the game. Let’s turn this into a timed gesture (i.e. more than just a pose).

Instead, let’s try a hold. We’re going to ask the user to hold the wave out gesture for about 400 milliseconds before we toggle mouse control on or off. We’re nearing the end of our Myo Script tutorials, so see if you can work out how to do that without any more advice.

Need a hint? Try highlighting one of these if you get stuck:

  • You’ll need to capture the current time when the user starts double tap
  • You can get the current time in milliseconds with myo.getTimeMilliseconds()
  • If the user has started wave out, you need to periodically check if the current time is bigger than the double tap start time, plus 400 milliseconds.
  • “periodically” means in onPeriodic
  • Don’t forget to clear the start time once the mouse is toggled
  • What should happen if wave out’s edge is “off”?
  • It should also clear the start time

That’s the meat of this script. There are a few more bits of polish we should apply to make it really work well. When mouse control is enabled, the rudder should lose its centre so things don’t go crazy when it’s disabled. You should also make sure the left and right arrows are pressed “up”, or they will break the menus. Fist should disable mouse control in addition to centring the yaw and roll. Once everything is working, you can turn off all the debug output.

Try that now. Tomorrow, we’ll be back in our final part of this tutorial with the complete script and some thoughts on where to go next.

Newsletter

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