Developing the Internet of Things: Myo-ity Report
In todays post we will dive a little deeper into the exploration of gesture control as an emerging form of input. Learn how the Myo Gesture Control Armband from Thalmic Labs can be used with Appmethod to create new user experiences with traditional UI/UX components. Specifically, we will take a look at FireFlow, a photo gallery scroller that ships as a demo with Appmethod.
FireFlow, a Demo Photo Gallery
FireFlow is a sample demo that illustrates how to create a photo gallery with FireMonkey. FireFlow is bundled with the Appmethod download as a demo app. For more details on FireFlow please reference the Appmethod Docwiki article.
FireFlow + Thalmic Labs Myo Gesture Control Armband = Myo-ity Report!
Today we all take one step closer to living out the Minority Report gesture-based user interface scene from 2002.
The Myo-ity Report demo app is an example of extending existing UI/UX controls to create new user experiences with gesture input.
Lets dive right in and examine how it works.
Appmethod and the Myo SDK
The first step is to load the Myo SDK into Appmethod.
If you have not yet integrated the Myo SDK with Appmethod, please refer to my previous post fore more deatils. The first half of following video will step you through integrating the SDK with Appmethod.
Building Myo-ity Report
First, make a copy of the FileFlow demo project from the following location:
Start | Programs | Appmethod 1.15 | Samples -> CPP\FireMonkey Desktop\FireFlow
or download directly from sourceforge.
New Class Properties
The following properties have been added to the datacollector class. scroll_left and scroll_right are flags which track the direction to scroll the photos. The set of const static ints determine the offsets from the calculated relative center position that represents the upper and lower bounds (left and right movement) for the Myo's positional location. The SCROLL_AMOUNT_* refers to how fast the animation timer fires which controls how quickly the photo gallery will scroll.
yaw_w_ref represents the inital angle the Myo Armband starts at. yaw_w_rel is the calculated offset from that refrenced position.
1
2
3
4
5
6
7
8
9
|
int roll_w, pitch_w, yaw_w, yaw_w_ref, yaw_w_rel; bool onArm, scroll_left, scroll_right; const static int SCROLL_LEFT_FAST = -4, SCROLL_LEFT_SLOW = -2, SCROLL_RIGHT_FAST = 3, SCROLL_RIGHT_SLOW = 2, SCROLL_AMOUNT_FAST = 250, SCROLL_AMOUNT_SLOW = 750; |
The DataCollector initialization list has been updated too:
1
2
3
4
5
|
DataCollector() : onArm( false ), roll_w(0), pitch_w(0), yaw_w(0), currentPose(), scroll_left( false ), scroll_right( false ), yaw_w_ref( -1 ) { } |
Processing Gesture Input
Within the datacollector class (please reference my previous Myo post for more detail) I have added a new method for the DataCollector class, read().
Firstly, It calculates the relative orientation of the Myo in regards to its start position. If the thumbToPinky or fingerSpread fists are detected then a new refrence orientation point is calculated against the current arm position in space. Doing this allows the wearer of the Myo to stand at pretty much any angle with respect to the Bluetooth USB dongle.
If the clenched fist is detected then the currently selected photo gets scaled out by a factor of 2 on X and Y and no further input is processed. This allows the person to 'grab' onto the current item and keep it selected regardless of any arm movements that may occur. This is an example of having to define new solutions for UX/UI experiences that are specific to gesture input.
Lastly, the relative yaw positional data is checked against upper and lower bounds which results in scrolling the images to the left and right.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
void read() { TLayer3D *Cover = (TLayer3D *)FrmMain->Coverflow->Children->Items[ Round(FrmMain->TrackBar1->Value) ]; if ( onArm ) { //- clear scrolling flags scroll_left = false ; scroll_right = false ; //- check for current fist std::string poseString = currentPose.toString(); //- recalibrate if ( poseString == "thumbToPinky" || poseString == "fingerSpread" ) { yaw_w_ref = yaw_w; } //- zoom selection on fist if ( poseString == "fist" ) { Cover->Scale->X = 2; Cover->Scale->Y = 2; //- the fist is being made, dont proccess movement return ; } else { Cover->Scale->X = 1; Cover->Scale->Y = 1; } //- set refrence point if ( yaw_w_ref == -1 ) { yaw_w_ref = yaw_w; } //- set relative position of myo armband yaw_w_rel = yaw_w_ref - yaw_w; if ( yaw_w_rel <= SCROLL_LEFT_SLOW ) scroll_right = true ; else if ( yaw_w_rel >= SCROLL_RIGHT_SLOW ) scroll_left = true ; if ( yaw_w_rel <= SCROLL_LEFT_FAST ) FrmMain->Timer2->Interval = SCROLL_AMOUNT_FAST; else if ( yaw_w_rel <= SCROLL_LEFT_SLOW ) FrmMain->Timer2->Interval = SCROLL_AMOUNT_SLOW; else if ( yaw_w_rel >= SCROLL_RIGHT_FAST ) FrmMain->Timer2->Interval = SCROLL_AMOUNT_FAST; else if ( yaw_w_rel >= SCROLL_RIGHT_SLOW ) FrmMain->Timer2->Interval = SCROLL_AMOUNT_SLOW; } } |
Adding Time
From the Tool Palette add two TTimer and a TMemo to the Form Designer
The first timer is set to a fast interval of 10ms. This timer is responsible for polling the Myo device for new data and outputting debug info to the Memo.
The second timer is responsible for animating the photo gallery.
Add the following code to their Timer Event handlers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
void __fastcall TFrmMain::Timer1Timer(TObject *Sender) { hub.run( 1000/50 ); collector.read(); Memo1->Lines->Clear(); Memo1->Lines->Add( String(). sprintf ( L "scroll_left: %d" ,collector.scroll_left ) ); Memo1->Lines->Add( String(). sprintf ( L "scroll_right: %d" ,collector.scroll_right ) ); Memo1->Lines->Add( String(). sprintf ( L "yaw_w: %d" , collector.yaw_w_ref - collector.yaw_w ) ); Memo1->Lines->Add( String(). sprintf ( L "timer speed: %d" , Timer2->Interval ) ); std::string poseString = collector.currentPose.toString(); Memo1->Lines->Add( poseString.c_str() ); } //--------------------------------------------------------------------------- void __fastcall TFrmMain::Timer2Timer(TObject *Sender) { if ( collector.scroll_left) { FrmMain->TrackBar1->Value--; } if ( collector.scroll_right ) { FrmMain->TrackBar1->Value++; } } |


Comments
-
Please login first in order for you to submit comments