“Hello Motions”

Hubo APIs

Controlling actuators using Rainbow is fairly simple since all of the definitions and simple APIs has been built and are very easy to implement or develop further. Take a look at the following code:

for (int i = RF1; i <= RF5; i++)
    Joint[i].RefVelCurrent = 30; MoveJMC(EJMC4);

When this code is executed by the program, the five right fingers will rotate (unfold in this case) with 30 velocity unit. So in short, to control a joint, simply set the properties for that joint (velocity for example) and call the function MoveJMC(_boardID) of the corresponding controller board. EJMC4 controls right hand.

For example:

Joint[RSP].RefVelCurrent = -40;
MoveJMC(EJMC8); // this will move the Right Shoulder Pitch

NOTE: When coming to actual programming, do not call the functions directly like above without other factors involved since the actuators keep rotating and they may break. So be careful!

So how do we implement these functions and actually control the hand? Take a look at the void main(void) in Core.cpp (Rainbow project) which is the main file of the project containing most of the functions, definitions, drivers, etc. The switch section looks like this:

switch(pSharedMemory->CommandFlag)
{
     unsigned int i;
     FILE* zmpinit_file;

     ...
     case GRIP_ON:
          for (i=RF1; i<=RF5; i++)
               Joint[i].RefVelCurrent = -pSharedMemory->CommandDataFloat[0];
          MoveJMC(EJMC4);
          // directionFlag = 0;
          pSharedMemory->CommandFlag = NO_ACT;
          break;
     ...
}
Before going right into the code, let's take a look at the structure of Rainbow program. There are two sides of the program: RTX side and user side. RTX side is where all of the commands, protocol communication, CAN messages sending/receiving are processed. User side (or GUI side) is where user input commands as well as monitoring status of the robot. The two communicate with each other through a shared memory. The following diagram summarizes the idea:  So, whenever the user send command to RTX, the pSharedMemory->CommandFlag will be set accordingly. The main() in RTX side will process this flag and execute the corresponding actions. The example code above show the GRIP_ON command flag. When this flag is set (i.e. the user click Grasp On button of the GUI), RTX will apply the velocity value (also set by user from the GUI) to the reference velocity of each actuators and then send CAN message to EJMC4 board and move the fingers. Finally, RTX will set the flag to NO_ACT, break out of the switch statement, and check for the next command. Let's try a simple example: "Fold the index finger and then wait ( with a total time of 2 seconds) before unfold the finger."
// add another command flag named RF1_CMD
case RF1_CMD:
    Joint[RF1].RefVelCurrent = -40;
    MoveJMC(EJMC4);
    Sleep(2000);

    Joint[RF1].RefVelCurrent = 40;
    MoveJMC(EJMC4);
    Sleep(2000);

    Joint[RF1].RefVelCurrent = 0;
    MoveJMC(EJMC4);
    pSharedMemory->CommandFlag = NO_ACT; // clear the command
    break;

Make sure to define the command flag RF1_CMD in the COMMAND_FLAG enum in CommonDefinition.h, which will help RTX recognize the command. Add control button or call pSharedMemory->CommandFlag = RF1_CMD; directly from the main().

~