HAPTIX C API


Overview

Looking for the C-API documentation? Try http://gazebosim.org/haptix/api.

This tutorial will explain how to use the C HAPTIX client library haptix-comm for requesting a description of the hand, sending new joint commands, and receiving state updates.

We assume that you have already done the installation step.

Compile your controller

In this tutorial we include a very basic controller that applies a sinusoidal function to all the hand joints. First, you should compile your controller and link it to the haptix-comm library.

Windows

Open Visual Studio 2013 and create a new project for your hand controller. Click on File->New Project->Visual C++, and select Win32 Console Application from the right side window. Select an appropriate name for your project, for example MyBasicController. Click OK, and then, click on Finish.

Replace the source code from your current project with our basic controller. Copy the code from here and paste it in your current project.

Add the following line at the beginning of your source code:

#include "stdafx.h"

Configuration for 64-bit SDK

Note: Skip this section if you are using the 32-bit SDK.

Click on the dropdown menu with the Win32 option in the toolbar and select Configuration Manager.


After that, look for the Active solution platform dropdown menu and select <New...>. Click on Type or select the new platform and change ARM to x64 , and then, click the Close button.

Compile your code

Open the Property Manager view by clicking on View->Other Windows->Property Manager. This will allow you to use the property sheet provided by the HAPTIX library SDK. Move to the Property Manager tab and right click on your project. Then, select Add Existing Property Sheet.... A new popup window will appear. Browse to the folder where you downloaded the HAPTIX client library SDK and select the property sheet named haptix-comm. This will handle all the dependencies for your project.

Switch the target build type from Debug to Release using the upper toolbar. Then, click on BUILD->Build Solution to build your controller.

Linux

  1. Install the following packages required for downloading and compiling the example:

    sudo apt-get install wget cmake build-essential
    
  2. Create a new directory named haptix_controller for this tutorial:

    mkdir ~/haptix_controller
    cd ~/haptix_controller
    
  3. Download the source code and the cmake file for the controller:

    wget http://bitbucket.org/osrf/haptix-comm/raw/default/example/hx_controller.c
    wget http://bitbucket.org/osrf/gazebo_tutorials/raw/default/haptix_comm/files/CMakeLists.txt
    
  4. Create a build directory and compile the source code.

    mkdir build
    cd build
    cmake ..
    make
    

Running the simulation with your controller

On the Linux machine, double-click on the haptixStart desktop icon to start the simulation.

Windows

Your code should be ready to be executed using Visual Studio. Click on DEBUG-> Start Without Debugging... (alternatively you can press Ctrl+F5).

Note: if the Windows firewall is enabled, it will show a Window called "Windows security alert. Windows Firewall has blocked some features of this program" asking for permissions to run the recently compiled application. You could leave the default option ("Private networks, such as my home or work network.") and click on "Allow access".

Linux

  1. Go to the Linux machine where you want to run your controller code. Open a terminal and go to the build/ directory where you have your controller executable:

    cd ~/haptix_controller/build
    
  2. Start the controller:

    ./hx_controller
    

Controller visualization

While your controller is running, you should see your fingers following a smooth trajectory in Gazebo.

The code explained

int main(int argc, char **argv)
{
  int i;
  int counter = 0;
  hxRobotInfo robotInfo;
  hxCommand cmd;
  hxSensor sensor;

  // Capture SIGINT signal.
  if (signal(SIGINT, sigHandler) == SIG_ERR)
    printf("Error catching SIGINT\n");

  // Capture SIGTERM signal.
  if (signal(SIGTERM, sigHandler) == SIG_ERR)
    printf("Error catching SIGTERM\n");

  // Connect to the simulator / hardware
  if (hx_connect(NULL, 0) != hxOK)
  {
    printf("hx_connect(): Request error.\n");
    return -1;
  }

  // Requesting robot information.
  if (hx_robot_info(&robotInfo) != hxOK)
  {
    printf("hx_getrobotinfo(): Request error.\n");
    return -1;
  }

  // Print the robot information.
  printRobotInfo(&robotInfo);

  // Uncomment this block to start logging.
  // if (hxs_start_logging("/tmp/log/") != hxOK)
  //   printf("hxs_start_logging(): error.\n");

  int steps = 0;

  // Send commands at ~100Hz.
  while (steps < 3000)
  {
    // Create a new command based on a sinusoidal wave.
    for (i = 0; i < robotInfo.motor_count; ++i)
    {
      // Set the desired position of this motor
      cmd.ref_pos[i] = (float)(350 * 0.5 *
        sin(0.05 * 2.0 * M_PI * counter * 0.01));
      // We could set a desired maximum velocity
      // cmd.ref_vel[i] = 1.0;
      // cmd.ref_vel_max[i] = 1.0;
      // We could set a desired controller position gain
      // cmd.gain_pos[i] = 1.0;
      // We could set a desired controller velocity gain
      // cmd.gain_vel[i] = 1.0;
    }
    // Indicate that the positions we set should be used.
    cmd.ref_pos_enabled = 1;
    // We're not setting it, so indicate that ref_vel should be ignored.
    cmd.ref_vel_enabled = 0;
    // We're not setting it, so indicate that ref_vel_max should be ignored.
    cmd.ref_vel_max_enabled = 0;
    // We're not setting it, so indicate that gain_pos should be ignored.
    cmd.gain_pos_enabled = 0;
    // We're not setting it, so indicate that gain_vel should be ignored.
    cmd.gain_vel_enabled = 0;

    // Send the new joint command and receive the state update.
    if (hx_update(&cmd, &sensor) != hxOK)
    {
      printf("hx_update(): Request error.\n");
      continue;
    }

    // Debug output: Print the state.
    if (!(counter % 100))
      printState(&robotInfo, &sensor);

    if (++counter == 10000)
      counter = 0;

    ++steps;

    // Here is where you would do your other work, such as reading from EMG
    // sensors, decoding that data, computing your next control command,
    // etc.  In this example, we're just sleeping for 10ms.
    //
    // You might also want to sleep in your code, because there's a maximum
    // rate at which the limb can process new commands and produce new
    // sensor readings.  Depending on how long your computation takes, you
    // might want to wait here until it's time to send a new command.  Or
    // you might want to run as fast as possible, computing and sending new
    // commands constantly (but knowing that not all of them will be
    // executed by the limb).
    unsigned int sleeptime_us = 10000;
#ifdef _WIN32
    Sleep((DWORD)(sleeptime_us / 1e3));
#else
    usleep(sleeptime_us);
#endif
  }

  // Uncomment this block to stop logging.
  // if (hxs_stop_logging() != hxOK)
  //   printf("hxs_stop_logging(): error.\n");

  // Disconnect from the simulator / hardware
  if (hx_close() != hxOK)
  {
    printf("hx_close(): Request error.\n");
    return -1;
  }

  return 0;
}

The HAPTIX C API is composed of five C function calls: hx_connect(), hx_robot_info(), hx_update(), hx_read_sensors(), and hx_close(). hx_connect() and hx_close() are optional for the Gazebo simulator, but are included for compatibility with MuJoCo.

hx_robot_info() requests information from a given device. In this tutorial, our device is a hand simulated in Gazebo. Note that this call blocks until the response is received.

The parameter to hx_robot_info() is a hxRobotInfo struct that contains the number of motors, joints, contact sensors, IMUs and joint limits for the requested device. It also includes the update rate, which is how frequently the device updates. If we have a valid response, the returned value is hxOK.

We have included in our example a helper function printRobotInfo() that will print all the received fields for debugging purposes.

Once we confirm the robot information we can start sending commands for controlling the hand. The function hx_update() is in charge of sending a new command and receiving the current state of the hand.

First of all, we need to fill a hxCommand struct that contains the positions, velocities, and gains for each joint. Check the haptix-comm API for a detailed view of the hxCommand struct. In our case, we are modifying the position of all the joints according to a sinusoidal function.

The first parameter to hx_update(), cmd, is the command that we want to send to the device, which we already filled in. The second output command sensor is passed to the function; it will contain the state of the hand after applying the command.

We have included a helper function printState() that shows all the state information for debugging purposes. Similar to hx_robot_info(), the function hx_update() returns hxOK when the command was successfully sent and the state has been received.

Troubleshooting

I can not connect the Windows client with Gazebo Linux Server

Usually you will receive a message from the command line launched by Visual Studio with an error message hx_robot_info() Service call timed out. This means that the communication to the Gazebo Linux server failed.

First check: Are both machines in the same network and can reach each other? Simply using the ping command from both (windows command line and Linux shell), should be enough to check connectivity. If it is not working, there is a problem in network configuration, be sure that both are connected to the same network.

Second check: Is the communication layer using the right network interface? Double check that you have set the IGN_IP properly in both Gazebo Linux server and Windows. In Windows this can be done from the Windows command line echo %IGN_IP%. To be completely sure, logout from your user session, login again and open Visual Studio.

Third check: Is the Windows firewall affecting the communication? It can be disabled from the Windows Control Panel (remember that there are different profiles in the Windows firewall, be sure of disable them all) and try to launch the Visual Studio application again.

Fourth check: Is the router cutting the communication? Several solutions: Login into the router, disable any kind of firewall. If you can not do that, connect both machines using an ethernet cable directly. You will need to manually setup both in the same subnet (192.168.X.Y/255.255.255.0 and 192.168.X.Y+1/255.255.255.0).

'Error setting socket option '

Probably you have an incorrect IP adress set in the IGN_IP variable.

The handsim simulator displays: 'NodeShared: no route to host'

The error means that there is no connection from the Linux simulator back to the Windows system. It is probably because of the Windows Firewall.

The hand is moving in the simulator, but erratically, not smoothly

If you are using a Wireless connection, it could happen that latency is making the interaction fail. Please try using a wired connection.

In the Windows Firewall question, I clicked the wrong option (cancel)

If by an error you pressed the wrong button, you can access to the Windows Firewall advanced security from the Windows control panel, go to Inbound rules and remove the ones with the name ConsoleApplication (or the name that you gave to the application).

Another option is to modify your application name, in the Project Properties name (not the solution name) that appears in the Solution Explorer window. Clean, rebuild and run again.