Difference between revisions of "4. AHAS Buttons and BHand Library Motions"
(→ALLEGROHAND1_ACTUAL.lua) |
|||
Line 1: | Line 1: | ||
− | In the last few tutorials, we | + | In the last few tutorials, we created a control algorithm project and verified our setup by performing a simple user-defined motion on both the virtual and actual Allegro Hands. We did all this ignoring the features of Allegro Hand Application Studio (AHAS) as a robust GUI interface for controlling the hand and visualizing certain data. |
In this tutorial, we will take advantage of '''buttons''' in AHAS and use them to invoke our own algorithms and those supplied along with AHAS in the BHand Library. | In this tutorial, we will take advantage of '''buttons''' in AHAS and use them to invoke our own algorithms and those supplied along with AHAS in the BHand Library. | ||
Line 5: | Line 5: | ||
==AHAS Buttons== | ==AHAS Buttons== | ||
− | + | Let's open up ''myAHController.lua'' and take a look.<br> | |
− | + | This is the file that we made in Tutorial 1 which links to out new controller.<br> | |
− | The function ''OnGUI()'' is the area of interest. This function contains the buttons | + | The function ''OnGUI()'' is the area of interest. This function contains the buttons we seen on the AHAS GUI.<br> |
+ | To create a button and link its press to a command is as simple as follows: | ||
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
... | ... | ||
− | + | -- ROW 1 | |
− | + | row = 1 | |
− | + | col = 1 | |
− | if ( | + | button_image = Image.new("buttonImages/home_off.png") |
− | + | if (isHome) then | |
− | + | button_image = Image.new("buttonImages/home_on.png") | |
− | + | end | |
− | + | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | |
− | + | controller:command(RCMD_GO_HOME, VK_H) | |
− | + | print("Home button pressed") | |
− | + | allMotionsFalse() | |
− | + | if (isConnected) then isHome = true end | |
− | + | end | |
... | ... | ||
</syntaxhighlight > | </syntaxhighlight > | ||
− | This button, when pressed, will cause the hand to assume its ''Home'' position. As mentioned in the comments, the arguments of '' | + | This button, when pressed, will cause the hand to assume its ''Home'' position. As mentioned in the comments, the arguments of ''GUI.Button()'' specify the button's Rect and the image displayed on the button. |
− | '' | + | The function ''controller:command()'' is used to forward a command to the hand controller, the DLL plug-in, ''myAHController.dll''. |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | Notice that all of the button code to command the Allegro Hand library motion is already available within the original LUA file, yet, if clicked, these buttons do nothing. We must develop the ''command()'' function in '' | + | Notice that all of the button code to command the Allegro Hand library motion is already available within the original LUA file, yet, if clicked, these buttons do nothing. We must develop the ''command()'' function in ''myAHController.cpp'' to handle the incoming commands. |
<br> | <br> | ||
Line 48: | Line 40: | ||
Since the buttons are already set up in AHAS, it is very easy to set up the function that will handle the commands in the control plug-in. But first, we must define the commands as integers for easy recognition. | Since the buttons are already set up in AHAS, it is very easy to set up the function that will handle the commands in the control plug-in. But first, we must define the commands as integers for easy recognition. | ||
− | === | + | ===myAHControllerCmd.h=== |
In the following header file, the command BH_HOME, used to call the home position for the Allegro Hand, is defined as RCMD_GO_HOME. This represents an integer value predefined in ''rCmdManipulator.h''. | In the following header file, the command BH_HOME, used to call the home position for the Allegro Hand, is defined as RCMD_GO_HOME. This represents an integer value predefined in ''rCmdManipulator.h''. | ||
Line 56: | Line 48: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | #ifndef | + | #ifndef __MY_AH_CONTROLLER_CMD_H__ |
− | #define | + | #define __MY_AH_CONTROLLER_CMD_H__ |
#include "rCommand/rCmdManipulator.h" | #include "rCommand/rCmdManipulator.h" | ||
Line 74: | Line 66: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | ===myAHController.cpp=== |
Now that the 'home' command, BH_HOME has been defined, we can write the command handler into our controller. In the function ''command()'', we will create a switch statement with the integer valued command as input. This method will allow us to easily expand out list off executable commands in the future. | Now that the 'home' command, BH_HOME has been defined, we can write the command handler into our controller. In the function ''command()'', we will create a switch statement with the integer valued command as input. This method will allow us to easily expand out list off executable commands in the future. | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | int | + | int myAHController::command(const short& cmd, const int& arg) |
{ | { | ||
// Handles user-defined commands according to cmd. | // Handles user-defined commands according to cmd. | ||
Line 111: | Line 103: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | void | + | void myAHController::_compute(const double& t) |
{ | { | ||
if (_hand) | if (_hand) | ||
Line 133: | Line 125: | ||
==More Buttons, More Motions== | ==More Buttons, More Motions== | ||
− | As you can see in the '' | + | As you can see in the ''myAHController.lua'' code, all of the motion buttons already have a command in the form ''RCMD_USER + #''. We will reference these commands to update our header file, ''myAHControllerCmd.h''. |
− | === | + | ===myAHController.lua=== |
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
... | ... | ||
− | + | BH_READY = RCMD_USER + 2 | |
− | + | BH_GRASP_3 = RCMD_USER + 3 | |
− | + | BH_GRASP_4 = RCMD_USER + 4 | |
− | + | BH_PINCH_IT = RCMD_USER + 5 | |
− | + | BH_PINCH_MT = RCMD_USER + 6 | |
− | + | BH_ENVELOP = RCMD_USER + 8 | |
+ | BH_SHOWOFF = RCMD_USER + 50 | ||
+ | BH_GRAVITY_COMP = RCMD_USER + 9 | ||
+ | BH_TEST = RCMD_USER + 100 | ||
+ | |||
+ | CAN_CMD_RESET_ENC = 4 | ||
− | GUI = | + | function OnGUI() |
+ | |||
+ | |||
+ | topPadding_percent = 02/100 | ||
+ | topPadding = Screen.height*topPadding_percent | ||
+ | leftPadding = topPadding | ||
+ | buttonSize_plusPadding = (Screen.height-topPadding*3)/rowsTotal | ||
+ | |||
+ | button_percent = 93/100 | ||
+ | buttonHeight = buttonSize_plusPadding*button_percent | ||
+ | buttonWidth = buttonHeight | ||
+ | verticalPadding = buttonSize_plusPadding - buttonHeight | ||
+ | horizontalPadding = verticalPadding | ||
+ | |||
+ | |||
+ | if (buttonHeight > maxButtonSize) then | ||
+ | buttonHeight = maxButtonSize | ||
+ | buttonWidth = buttonHeight | ||
+ | verticalPadding = 10 | ||
+ | horizontalPadding = 10 | ||
+ | leftPadding = 10 | ||
+ | topPadding = 10 | ||
+ | end | ||
+ | |||
+ | AllegroLogoWidth_max = 512 | ||
+ | AllegroLogoHeight_max = AllegroLogoWidth_max/8 | ||
+ | |||
+ | |||
+ | AllegroLogoHeight = AllegroLogoHeight_max | ||
+ | AllegroLogoWidth = AllegroLogoWidth_max | ||
+ | |||
+ | |||
+ | if (Screen.width > 0.8*AllegroLogoWidth_max) then | ||
+ | x = Screen.width - AllegroLogoWidth - leftPadding | ||
+ | y = topPadding | ||
+ | GUI.DrawTexture(Rect.new(x, y, AllegroLogoWidth, AllegroLogoHeight), Image.new("buttonImages/AllegroHandLogo.png"), 0.0) | ||
+ | end | ||
+ | |||
+ | -- ROW 1 | ||
+ | --[[ | ||
+ | row = 1 | ||
+ | col = 1 | ||
+ | button_image = Image.new("buttonImages/on.png") | ||
+ | if (isConnected) then | ||
+ | button_image = Image.new("buttonImages/off.png") | ||
+ | end | ||
+ | --if (GUI.Button(Rect.new(hLocation(col), vLocation(row), buttonWidth, buttonHeight), Image.new(button_image))) then | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | if (isConnected) then | ||
+ | comm:off() | ||
+ | controller:command(RESERVED_CMD_SERVO_OFF) | ||
+ | isConnected = false | ||
+ | allMotionsFalse() | ||
+ | else | ||
+ | controller:command(RCMD_USER + 0) | ||
+ | comm:on() | ||
+ | controller:command(RESERVED_CMD_SERVO_ON) | ||
+ | isConnected = true | ||
+ | allMotionsFalse() | ||
+ | end | ||
+ | end | ||
+ | ]]-- | ||
+ | |||
+ | -- ROW 1 | ||
+ | row = 1 | ||
+ | col = 1 | ||
+ | button_image = Image.new("buttonImages/home_off.png") | ||
+ | if (isHome) then | ||
+ | button_image = Image.new("buttonImages/home_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(RCMD_GO_HOME, VK_H) | ||
+ | print("Home button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isHome = true end | ||
+ | end | ||
+ | |||
+ | col = 2 | ||
+ | button_image = Image.new("buttonImages/ready_off.png") | ||
+ | if (isReady) then | ||
+ | button_image = Image.new("buttonImages/ready_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_READY, VK_R) | ||
+ | print("Ready button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isReady = true end | ||
+ | end | ||
+ | |||
+ | -- ROW 3 | ||
+ | row = 2 | ||
+ | col = 1 | ||
+ | button_image = Image.new("buttonImages/grasp3fingers_off.png") | ||
+ | if (isGrasp3) then | ||
+ | button_image = Image.new("buttonImages/grasp3fingers_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_GRASP_3) | ||
+ | print("Grasp 3 button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isGrasp3 = true end | ||
+ | end | ||
+ | |||
+ | col = 2 | ||
+ | button_image = Image.new("buttonImages/grasp4fingers_off.png") | ||
+ | if (isGrasp4) then | ||
+ | button_image = Image.new("buttonImages/grasp4fingers_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_GRASP_4) | ||
+ | print("Grasp 4 button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isGrasp4 = true end | ||
+ | end | ||
+ | |||
+ | -- ROW 4 | ||
+ | row = 3 | ||
+ | col = 1 | ||
+ | button_image = Image.new("buttonImages/pinchIndex_off.png") | ||
+ | if (isPinchIT) then | ||
+ | button_image = Image.new("buttonImages/pinchIndex_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_PINCH_IT) | ||
+ | print("Pinch (IT) button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isPinchIT = true end | ||
+ | end | ||
+ | |||
+ | col = 2 | ||
+ | button_image = Image.new("buttonImages/pinchMiddle_off.png") | ||
+ | if (isPinchMT) then | ||
+ | button_image = Image.new("buttonImages/pinchMiddle_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_PINCH_MT) | ||
+ | print("Pinch (MT) button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isPinchMT = true end | ||
+ | end | ||
+ | |||
+ | |||
+ | -- ROW 5 | ||
+ | row = 4 | ||
+ | col = 1 | ||
+ | button_image = Image.new("buttonImages/envelop_off.png") | ||
+ | if (isEnvelop) then | ||
+ | button_image = Image.new("buttonImages/envelop_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_ENVELOP) | ||
+ | print("Envelop button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isEnvelop = true end | ||
+ | end | ||
+ | |||
+ | --[[ | ||
+ | col = 2 | ||
+ | button_image = Image.new("buttonImages/gravityCompensation_off.png") | ||
+ | if (isGravity) then | ||
+ | button_image = Image.new("buttonImages/gravityCompensation_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_GRAVITY_COMP) | ||
+ | print("Gravity Compensation button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isGravity = true end | ||
+ | end | ||
− | + | -- ROW 6 | |
− | + | row = 5 | |
− | + | col = 2 | |
− | + | button_image = Image.new("buttonImages/showOff_off.png") | |
− | + | if (isShowOff) then | |
− | + | button_image = Image.new("buttonImages/showOff_on.png") | |
− | + | end | |
− | + | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | |
− | + | controller:command(BH_SHOWOFF) | |
− | + | print("Showoff button pressed") | |
− | + | allMotionsFalse() | |
− | + | if (isConnected) then isShowOff = true end | |
− | + | end | |
− | + | ]]-- | |
− | + | ||
− | + | -- ROW 8 | |
− | + | --[[ | |
− | + | row = rowsTotal | |
− | + | col = 1 | |
+ | button_image = Image.new("buttonImages/encoderOffsets_off.png") | ||
+ | if (GUI.Button(Rect.new(Screen.width - button(row,col)[1]-buttonWidth, button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | |||
+ | for i=1,16 do | ||
+ | encName = "enc"..i | ||
+ | |||
+ | if i == 1 then | ||
+ | print(" ") | ||
+ | print("Finger 1") | ||
+ | end | ||
+ | |||
+ | if i == 5 then | ||
+ | print(" ") | ||
+ | print("Finger 2") | ||
+ | end | ||
+ | |||
+ | if i == 9 then | ||
+ | print(" ") | ||
+ | print("Finger 3") | ||
+ | end | ||
+ | |||
+ | if i == 13 then | ||
+ | print(" ") | ||
+ | print("Finger 4") | ||
+ | end | ||
+ | |||
+ | enc = hand:findDevice(encName) | ||
+ | enc:command(CAN_CMD_RESET_ENC) | ||
+ | --print("Test Encoders") | ||
+ | end | ||
+ | io.read() | ||
+ | end | ||
+ | |||
+ | row = rowsTotal - 1 | ||
+ | col = 1 | ||
+ | button_image = Image.new("buttonImages/motorDirections_off.png") | ||
+ | if (GUI.Button(Rect.new(Screen.width - button(row,col)[1]-buttonWidth, button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_TEST) | ||
+ | print("Test Motor Positive Direction") | ||
+ | end | ||
+ | |||
+ | ]]-- | ||
+ | |||
+ | end | ||
+ | |||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Please note that the command, BH_READY, is defined above as RCMD_USER + 2. This is the same as feeding RCMD_USER + 2 directly into '' | + | Please note that the command, BH_READY, is defined above as RCMD_USER + 2.<br> |
+ | This is the same as feeding RCMD_USER + 2 directly into ''controller:command()''. Feel free to define these wherever you want. | ||
− | According to the definitions in the AHAS LUA file, we will add these | + | According to the definitions in the AHAS LUA file, we will add these six(6) new commands to the ''myAHControllerCmd.h'' header file definitions. We will then add the code to be executed with each button to ''myAHController.cpp'''s ''command()'' function. |
− | === | + | ===myAHControllerCmd.h:=== |
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
... | ... | ||
Line 183: | Line 393: | ||
#define BH_READY (RCMD_USER + 2) | #define BH_READY (RCMD_USER + 2) | ||
#define BH_GRASP_3 (RCMD_USER + 3) | #define BH_GRASP_3 (RCMD_USER + 3) | ||
+ | #define BH_GRASP_4 (RCMD_USER + 4) | ||
#define BH_PINCH_IT (RCMD_USER + 5) | #define BH_PINCH_IT (RCMD_USER + 5) | ||
+ | #define BH_PINCH_MT (RCMD_USER + 6) | ||
+ | #define BH_ENVELOP (RCMD_USER + 8) | ||
//#define BH_MORE (RCMD_USER + 99) | //#define BH_MORE (RCMD_USER + 99) | ||
Line 190: | Line 403: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | ===myAHConroller.cpp=== |
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | int | + | int myAHConroller::command(const short& cmd, const int& arg) |
{ | { | ||
// Handles user-defined commands according to cmd. | // Handles user-defined commands according to cmd. | ||
Line 221: | Line 434: | ||
if (_hand) | if (_hand) | ||
_hand->SetMotionType(eMotionType_GRASP_3); | _hand->SetMotionType(eMotionType_GRASP_3); | ||
+ | } | ||
+ | break; | ||
+ | case BH_GRASP_4: // This grasping algorithm is a torque-controlled, four-fingered grip. | ||
+ | { | ||
+ | _demo_mode = 0; | ||
+ | if (_hand) | ||
+ | _hand->SetMotionType(eMotionType_GRASP_4); | ||
} | } | ||
break; | break; | ||
Line 228: | Line 448: | ||
if (_hand) | if (_hand) | ||
_hand->SetMotionType(eMotionType_PINCH_IT); | _hand->SetMotionType(eMotionType_PINCH_IT); | ||
+ | } | ||
+ | break; | ||
+ | case BH_PINCH_MT: // This grasping algorithm is a torque-controlled, two-fingered pinch. | ||
+ | { | ||
+ | _demo_mode = 0; | ||
+ | if (_hand) | ||
+ | _hand->SetMotionType(eMotionType_PINCH_MT); | ||
+ | } | ||
+ | break; | ||
+ | case BH_ENVELOP: // This grasping algorithm is a torque-controlled, two-fingered pinch. | ||
+ | { | ||
+ | _demo_mode = 0; | ||
+ | if (_hand) | ||
+ | _hand->SetMotionType(eMotionType_ENVELOP); | ||
} | } | ||
break; | break; | ||
Line 245: | Line 479: | ||
==A Button Just For Us== | ==A Button Just For Us== | ||
− | In your AHAS ''bin/controls'' directory, locate the file '' | + | In your AHAS ''bin/controls'' directory, locate the file ''myAHController.lua''. Copy this file to your ''Desktop''. |
'''''Note: '''Once again, we must copy this file to the desktop for editing then move it back to the controls folder when we are finished to avoid opening with admin privileges.'' | '''''Note: '''Once again, we must copy this file to the desktop for editing then move it back to the controls folder when we are finished to avoid opening with admin privileges.'' | ||
− | From the ''Desktop'', let's open up '' | + | From the ''Desktop'', let's open up ''myAHController.lua'' and take a look. |
To make our own button we need only to copy the code from a stock button and change three things: the location, the name and the command sent to the controller. | To make our own button we need only to copy the code from a stock button and change three things: the location, the name and the command sent to the controller. | ||
− | First, select any of the stock button and copy the ''if statement'' and anything inside. Paste it below the last stock button ('' | + | First, select any of the stock button and copy the ''if statement'' and anything inside. Paste it below the last stock button (''ENVELOP''). |
Now we will change a few things to make this button our own. | Now we will change a few things to make this button our own. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
The following button code produces a button called ''"Demo Mode 1"'' just below the ''"PINCHING"'' button. The command sent to the controller is ''RCMD_USER + 50''. Remember, we will have to define this in the controller header for use in the controller command function. | The following button code produces a button called ''"Demo Mode 1"'' just below the ''"PINCHING"'' button. The command sent to the controller is ''RCMD_USER + 50''. Remember, we will have to define this in the controller header for use in the controller command function. | ||
− | === | + | ===myAHController.lua=== |
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
... | ... | ||
+ | |||
+ | -- ROW 5 | ||
+ | row = 4 | ||
+ | col = 2 | ||
+ | button_image = Image.new("buttonImages/envelop_off.png") | ||
+ | if (isEnvelop) then | ||
+ | button_image = Image.new("buttonImages/envelop_on.png") | ||
+ | end | ||
+ | if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then | ||
+ | controller:command(BH_ENVELOP) | ||
+ | print("Envelop button pressed") | ||
+ | allMotionsFalse() | ||
+ | if (isConnected) then isEnvelop = true end | ||
+ | end | ||
if (GUI.Button(5, 95, 120, 25, "PINCHING")) then | if (GUI.Button(5, 95, 120, 25, "PINCHING")) then | ||
Line 288: | Line 526: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === | + | ===myAHControllerCmd.h=== |
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
... | ... | ||
− | #define | + | #define BH_ENVELOP (RCMD_USER + 8) |
#define BH_DEMO1 (RCMD_USER + 50) | #define BH_DEMO1 (RCMD_USER + 50) | ||
Line 299: | Line 537: | ||
− | === | + | ===myAHController.cpp=== |
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | int | + | int myAHController::command(const short& cmd, const int& arg) |
... | ... | ||
− | case | + | case BH_ENVELOP: |
{ | { | ||
_demo_mode = 0; | _demo_mode = 0; | ||
if (_hand) | if (_hand) | ||
− | _hand->SetMotionType( | + | _hand->SetMotionType(eMotionType_ENVELOP); |
} | } | ||
break; | break; | ||
Line 333: | Line 571: | ||
The controller's ''command()'' function calls the BHand library functions and the command values used are based on the original LUA file. This means that the BHand library function like Grasp and Pinch should automatically work with the buttons in AHAS for the actual hand. These buttons send the same commands and will therefore execute the same motions without any changes to the LUA file. | The controller's ''command()'' function calls the BHand library functions and the command values used are based on the original LUA file. This means that the BHand library function like Grasp and Pinch should automatically work with the buttons in AHAS for the actual hand. These buttons send the same commands and will therefore execute the same motions without any changes to the LUA file. | ||
− | If you would like to demonstrate your demo mode controller on the actual hand, you need only add your new button to '' | + | If you would like to demonstrate your demo mode controller on the actual hand, you need only add your new button to ''myAHController_ACTUAL.lua''. |
− | '''''Note: '''The first argument of | + | '''''Note: '''The first argument of controller:command() is '''"RTController"''', not '''"HandController"''' as in the virtual hand LUA file.'' |
− | === | + | ===myAHController_ACTUAL.lua=== |
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
... | ... |
Revision as of 15:12, 29 April 2015
In the last few tutorials, we created a control algorithm project and verified our setup by performing a simple user-defined motion on both the virtual and actual Allegro Hands. We did all this ignoring the features of Allegro Hand Application Studio (AHAS) as a robust GUI interface for controlling the hand and visualizing certain data.
In this tutorial, we will take advantage of buttons in AHAS and use them to invoke our own algorithms and those supplied along with AHAS in the BHand Library.
Contents |
AHAS Buttons
Let's open up myAHController.lua and take a look.
This is the file that we made in Tutorial 1 which links to out new controller.
The function OnGUI() is the area of interest. This function contains the buttons we seen on the AHAS GUI.
To create a button and link its press to a command is as simple as follows:
... -- ROW 1 row = 1 col = 1 button_image = Image.new("buttonImages/home_off.png") if (isHome) then button_image = Image.new("buttonImages/home_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(RCMD_GO_HOME, VK_H) print("Home button pressed") allMotionsFalse() if (isConnected) then isHome = true end end ...
This button, when pressed, will cause the hand to assume its Home position. As mentioned in the comments, the arguments of GUI.Button() specify the button's Rect and the image displayed on the button.
The function controller:command() is used to forward a command to the hand controller, the DLL plug-in, myAHController.dll.
Notice that all of the button code to command the Allegro Hand library motion is already available within the original LUA file, yet, if clicked, these buttons do nothing. We must develop the command() function in myAHController.cpp to handle the incoming commands.
Plug-in Command Handling
Since the buttons are already set up in AHAS, it is very easy to set up the function that will handle the commands in the control plug-in. But first, we must define the commands as integers for easy recognition.
myAHControllerCmd.h
In the following header file, the command BH_HOME, used to call the home position for the Allegro Hand, is defined as RCMD_GO_HOME. This represents an integer value predefined in rCmdManipulator.h.
The command BH_NONE is defined as RCMD_USER, another integer value predefined in rCmdDefine.h. We will use RCMD_USER plus some integer to define all of our further commands from both the BHand library and our user-written algorithms (see BH_ONE).
#ifndef __MY_AH_CONTROLLER_CMD_H__ #define __MY_AH_CONTROLLER_CMD_H__ #include "rCommand/rCmdManipulator.h" // These commands will be fed into command() // and can be used to envoke certain actions // by the robot. Allegro Application Studio // will use these to interface with the // cotroller plug-in. #define BH_NONE (RCMD_USER + 0) #define BH_HOME (RCMD_GO_HOME) // #define BH_ONE (RCMD_USER + 1) #endif
myAHController.cpp
Now that the 'home' command, BH_HOME has been defined, we can write the command handler into our controller. In the function command(), we will create a switch statement with the integer valued command as input. This method will allow us to easily expand out list off executable commands in the future.
int myAHController::command(const short& cmd, const int& arg) { // Handles user-defined commands according to cmd. // Further information can be retrieved from the second argument. // The variable cmd will be received from Allegro Application Studio // and will be used to envoke hand actions switch (cmd) { case BH_HOME: { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_HOME); } break; default: break; } return 0; }
As you can see, when it is time to the home position, we must turn off demo mode, which, as you remember, is the sinusoidal joint position controller we implementer in the last two tutorials. But setting _demo_mode to zero will not do the trick. We must revisit the demo mode algorithm and edit the if statement around it.
Currently, the if statement controlling the execution of the demo mode algorithm is evaluated as always true. Replace the true with the variable _demo_mode so that we can once again control it. This will also prevent the algorithm from running immediately when AHAS starts up.
void myAHController::_compute(const double& t) { if (_hand) { _hand->SetJointPosition(_q.array); // joint positions set via torque PID // DEMO MODE NOW ONLY RUNS IF WE SET _demo_mode TO 1 if (_demo_mode) { _hand->SetMotionType(eMotionType_JOINT_PD); // PID gains and motion control set ...
Compile then open up AHAS from the shortcut on your desktop.
Note: Make sure you are opening the shortcut that will run the virtual hand, not the actual hand.
The hand should be fully flat when AHAS starts. Click "Home" to send the home position command. That should assume the home position. Unfortunately, we now have no way to access our demo mode. We will fix that, but first, lets get all of the other buttons working.
More Buttons, More Motions
As you can see in the myAHController.lua code, all of the motion buttons already have a command in the form RCMD_USER + #. We will reference these commands to update our header file, myAHControllerCmd.h.
myAHController.lua
... BH_READY = RCMD_USER + 2 BH_GRASP_3 = RCMD_USER + 3 BH_GRASP_4 = RCMD_USER + 4 BH_PINCH_IT = RCMD_USER + 5 BH_PINCH_MT = RCMD_USER + 6 BH_ENVELOP = RCMD_USER + 8 BH_SHOWOFF = RCMD_USER + 50 BH_GRAVITY_COMP = RCMD_USER + 9 BH_TEST = RCMD_USER + 100 CAN_CMD_RESET_ENC = 4 function OnGUI() topPadding_percent = 02/100 topPadding = Screen.height*topPadding_percent leftPadding = topPadding buttonSize_plusPadding = (Screen.height-topPadding*3)/rowsTotal button_percent = 93/100 buttonHeight = buttonSize_plusPadding*button_percent buttonWidth = buttonHeight verticalPadding = buttonSize_plusPadding - buttonHeight horizontalPadding = verticalPadding if (buttonHeight > maxButtonSize) then buttonHeight = maxButtonSize buttonWidth = buttonHeight verticalPadding = 10 horizontalPadding = 10 leftPadding = 10 topPadding = 10 end AllegroLogoWidth_max = 512 AllegroLogoHeight_max = AllegroLogoWidth_max/8 AllegroLogoHeight = AllegroLogoHeight_max AllegroLogoWidth = AllegroLogoWidth_max if (Screen.width > 0.8*AllegroLogoWidth_max) then x = Screen.width - AllegroLogoWidth - leftPadding y = topPadding GUI.DrawTexture(Rect.new(x, y, AllegroLogoWidth, AllegroLogoHeight), Image.new("buttonImages/AllegroHandLogo.png"), 0.0) end -- ROW 1 --[[ row = 1 col = 1 button_image = Image.new("buttonImages/on.png") if (isConnected) then button_image = Image.new("buttonImages/off.png") end --if (GUI.Button(Rect.new(hLocation(col), vLocation(row), buttonWidth, buttonHeight), Image.new(button_image))) then if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then if (isConnected) then comm:off() controller:command(RESERVED_CMD_SERVO_OFF) isConnected = false allMotionsFalse() else controller:command(RCMD_USER + 0) comm:on() controller:command(RESERVED_CMD_SERVO_ON) isConnected = true allMotionsFalse() end end ]]-- -- ROW 1 row = 1 col = 1 button_image = Image.new("buttonImages/home_off.png") if (isHome) then button_image = Image.new("buttonImages/home_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(RCMD_GO_HOME, VK_H) print("Home button pressed") allMotionsFalse() if (isConnected) then isHome = true end end col = 2 button_image = Image.new("buttonImages/ready_off.png") if (isReady) then button_image = Image.new("buttonImages/ready_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_READY, VK_R) print("Ready button pressed") allMotionsFalse() if (isConnected) then isReady = true end end -- ROW 3 row = 2 col = 1 button_image = Image.new("buttonImages/grasp3fingers_off.png") if (isGrasp3) then button_image = Image.new("buttonImages/grasp3fingers_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_GRASP_3) print("Grasp 3 button pressed") allMotionsFalse() if (isConnected) then isGrasp3 = true end end col = 2 button_image = Image.new("buttonImages/grasp4fingers_off.png") if (isGrasp4) then button_image = Image.new("buttonImages/grasp4fingers_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_GRASP_4) print("Grasp 4 button pressed") allMotionsFalse() if (isConnected) then isGrasp4 = true end end -- ROW 4 row = 3 col = 1 button_image = Image.new("buttonImages/pinchIndex_off.png") if (isPinchIT) then button_image = Image.new("buttonImages/pinchIndex_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_PINCH_IT) print("Pinch (IT) button pressed") allMotionsFalse() if (isConnected) then isPinchIT = true end end col = 2 button_image = Image.new("buttonImages/pinchMiddle_off.png") if (isPinchMT) then button_image = Image.new("buttonImages/pinchMiddle_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_PINCH_MT) print("Pinch (MT) button pressed") allMotionsFalse() if (isConnected) then isPinchMT = true end end -- ROW 5 row = 4 col = 1 button_image = Image.new("buttonImages/envelop_off.png") if (isEnvelop) then button_image = Image.new("buttonImages/envelop_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_ENVELOP) print("Envelop button pressed") allMotionsFalse() if (isConnected) then isEnvelop = true end end --[[ col = 2 button_image = Image.new("buttonImages/gravityCompensation_off.png") if (isGravity) then button_image = Image.new("buttonImages/gravityCompensation_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_GRAVITY_COMP) print("Gravity Compensation button pressed") allMotionsFalse() if (isConnected) then isGravity = true end end -- ROW 6 row = 5 col = 2 button_image = Image.new("buttonImages/showOff_off.png") if (isShowOff) then button_image = Image.new("buttonImages/showOff_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_SHOWOFF) print("Showoff button pressed") allMotionsFalse() if (isConnected) then isShowOff = true end end ]]-- -- ROW 8 --[[ row = rowsTotal col = 1 button_image = Image.new("buttonImages/encoderOffsets_off.png") if (GUI.Button(Rect.new(Screen.width - button(row,col)[1]-buttonWidth, button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then for i=1,16 do encName = "enc"..i if i == 1 then print(" ") print("Finger 1") end if i == 5 then print(" ") print("Finger 2") end if i == 9 then print(" ") print("Finger 3") end if i == 13 then print(" ") print("Finger 4") end enc = hand:findDevice(encName) enc:command(CAN_CMD_RESET_ENC) --print("Test Encoders") end io.read() end row = rowsTotal - 1 col = 1 button_image = Image.new("buttonImages/motorDirections_off.png") if (GUI.Button(Rect.new(Screen.width - button(row,col)[1]-buttonWidth, button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_TEST) print("Test Motor Positive Direction") end ]]-- end
Please note that the command, BH_READY, is defined above as RCMD_USER + 2.
This is the same as feeding RCMD_USER + 2 directly into controller:command(). Feel free to define these wherever you want.
According to the definitions in the AHAS LUA file, we will add these six(6) new commands to the myAHControllerCmd.h header file definitions. We will then add the code to be executed with each button to myAHController.cpp's command() function.
myAHControllerCmd.h:
... #define BH_NONE (RCMD_USER + 0) #define BH_HOME (RCMD_GO_HOME) #define BH_READY (RCMD_USER + 2) #define BH_GRASP_3 (RCMD_USER + 3) #define BH_GRASP_4 (RCMD_USER + 4) #define BH_PINCH_IT (RCMD_USER + 5) #define BH_PINCH_MT (RCMD_USER + 6) #define BH_ENVELOP (RCMD_USER + 8) //#define BH_MORE (RCMD_USER + 99) ...
myAHConroller.cpp
int myAHConroller::command(const short& cmd, const int& arg) { // Handles user-defined commands according to cmd. // Further information can be retrieved from the second argument. // The variable cmd will be received from Allegro Application Studio // and will be used to envoke hand actions switch (cmd) { case BH_HOME: // The position ensures that all joints are oriented properly for executing a grasp. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_HOME); } break; case BH_READY: // Click the buttons entitled Ready to prepare for each type of grasping motion. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_READY); } break; case BH_GRASP_3: // This grasping algorithm is a torque-controlled, three-fingered grip. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_GRASP_3); } break; case BH_GRASP_4: // This grasping algorithm is a torque-controlled, four-fingered grip. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_GRASP_4); } break; case BH_PINCH_IT: // This grasping algorithm is a torque-controlled, two-fingered pinch. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_PINCH_IT); } break; case BH_PINCH_MT: // This grasping algorithm is a torque-controlled, two-fingered pinch. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_PINCH_MT); } break; case BH_ENVELOP: // This grasping algorithm is a torque-controlled, two-fingered pinch. { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_ENVELOP); } break; default: break; } return 0; }
As you can see in every case, we are ensuring that _demo_mode is set to zero. The value of the _demo_mode flag is checked every iteration. If _demo_mode == 1, then the demo code we wrote earlier will override the latest command.
Now compile, reload AHAS and play with your buttons!!
A Button Just For Us
In your AHAS bin/controls directory, locate the file myAHController.lua. Copy this file to your Desktop.
Note: Once again, we must copy this file to the desktop for editing then move it back to the controls folder when we are finished to avoid opening with admin privileges.
From the Desktop, let's open up myAHController.lua and take a look.
To make our own button we need only to copy the code from a stock button and change three things: the location, the name and the command sent to the controller.
First, select any of the stock button and copy the if statement and anything inside. Paste it below the last stock button (ENVELOP).
Now we will change a few things to make this button our own.
The following button code produces a button called "Demo Mode 1" just below the "PINCHING" button. The command sent to the controller is RCMD_USER + 50. Remember, we will have to define this in the controller header for use in the controller command function.
myAHController.lua
... -- ROW 5 row = 4 col = 2 button_image = Image.new("buttonImages/envelop_off.png") if (isEnvelop) then button_image = Image.new("buttonImages/envelop_on.png") end if (GUI.Button(Rect.new(button(row,col)[1], button(row,col)[2], button(row,col)[3], button(row,col)[4]), button_image)) then controller:command(BH_ENVELOP) print("Envelop button pressed") allMotionsFalse() if (isConnected) then isEnvelop = true end end if (GUI.Button(5, 95, 120, 25, "PINCHING")) then sendCommand("HandController", RCMD_USER + 5) print("Pinching button pressed") end if (GUI.Button(5, 155, 240 25, "PINCHING")) then sendCommand("HandController", RCMD_USER + 50) print("Pinching button pressed") end ...
myAHControllerCmd.h
... #define BH_ENVELOP (RCMD_USER + 8) #define BH_DEMO1 (RCMD_USER + 50) #endif
myAHController.cpp
int myAHController::command(const short& cmd, const int& arg) ... case BH_ENVELOP: { _demo_mode = 0; if (_hand) _hand->SetMotionType(eMotionType_ENVELOP); } break; case BH_DEMO1: { _demo_mode = 1; } break; default: break; } return 0; }
As simple as that!
With what you learned in this tutorial, you can add as many buttons and respective control algorithms as you want. Please feel free to share your results with us!
Actual Allegro Hand
The controller's command() function calls the BHand library functions and the command values used are based on the original LUA file. This means that the BHand library function like Grasp and Pinch should automatically work with the buttons in AHAS for the actual hand. These buttons send the same commands and will therefore execute the same motions without any changes to the LUA file.
If you would like to demonstrate your demo mode controller on the actual hand, you need only add your new button to myAHController_ACTUAL.lua.
Note: The first argument of controller:command() is "RTController", not "HandController" as in the virtual hand LUA file.
myAHController_ACTUAL.lua
... if (GUI.Button(5, 95, 120, 25, "PINCHING")) then sendCommand("HandController", RCMD_USER + 5) print("Pinching button pressed") end if (GUI.Button(5, 155, 240 25, "PINCHING")) then sendCommand("HandController", RCMD_USER + 50) print("Pinching button pressed") end ...
Whos here now: Members 0 Guests 0 Bots & Crawlers 1 |