C Example

 

The following example is a simple implementation of TCP/IP socket communication with the Meca500 robot in TCP/IP on Windows system


socket_comm.h/.c contains all the socket/TCP-IP/Communication part of this example


socket_comm.h

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>

// For now keep only socket inside, but could add more stuff
// when the program will require more functionnality.
typedef struct{
    SOCKET socket_;
}tcpip_connection;

/// Connect a TCP socket. Handles the windows init socket
/// Return 0 for success, -1 for failure.
int tcpip_connect(const char *address, const char *port, tcpip_connection * connection);

/// Disconnect a connection
void tcpip_disconnect(tcpip_connection *connection);

/// Send data to the buffer
/// Return 0 for success, -1 for failure, or the size that was actually sent
/// if the entire data did not fit in the TCP buffer. In that case, you should 
/// send the remaining. 
int tcpip_send(const char* buffer, int len, tcpip_connection *connection);

/// Try to recveive len byte of data.
/// Return 0 for CLOSED CONNECTION, -1 for failure, or the nb of data received. 
int tcpip_receive(char* buffer, int len, tcpip_connection *connection);


socket_comm.c

#include <stdio.h>
#include <stdlib.h>
#include "socket_comm.h"

#define DEBUG 0

// Keep count of the user to init/close the library.
static int socket_system_user_count = 0;
// the WSData required by windows sockets.
static WSADATA wsaData;

/// Utility to exit the function if the socket system is not initialized.
#define EXIT_ON_SYSTEM_NOT_INITED() if(socket_system_user_count == 0) {return -1;}

/// Initialise the socket library if needed.
int init_socket_system()
{
    if (socket_system_user_count == 0)
    {
        printf("Init WSA\r\n");
        int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (result != 0)
        {
            printf("WSAStartup failed with error: %d\r\n", result);
            return -1;
        }
    }
    socket_system_user_count++;
    return 0;
}

/// Close the socket library if no more user on it.
void cleanup_socket_system()
{
    socket_system_user_count--;
    if (socket_system_user_count == 0)
    {
        printf("Closing WSA\r\n");
        WSACleanup();
    }
}

//=============================================================================
//
int tcpip_connect(const char *address, const char *port, tcpip_connection *connection)
{
    int result = 0;
    result = init_socket_system();
    if (result != 0)
    {
        return -1;
    }

    struct addrinfo hints, *addr_result;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    // Get the address information for the connection
    result = getaddrinfo(address, port, &hints, &addr_result);

    if (result != 0)
    {
        printf("getaddrinfo failed with error: %d\r\n", result);
        cleanup_socket_system();
        return -1;
    }

    // Create a SOCKET for connecting to server
    connection->socket_ = socket(addr_result->ai_family,
                                 addr_result->ai_socktype,
                                 addr_result->ai_protocol);
    if (connection->socket_ == INVALID_SOCKET)
    {
        printf("socket failed with error: %ld\r\n", WSAGetLastError());
        cleanup_socket_system();
        return -1;
    }

    // Connect to server.
    result = connect(connection->socket_,
                     addr_result->ai_addr,
                     (int)addr_result->ai_addrlen);
    if (result == SOCKET_ERROR)
    {
        closesocket(connection->socket_);
        cleanup_socket_system();
        connection->socket_ = INVALID_SOCKET;
        return -1;
    }

    // Done with socket creation.
    freeaddrinfo(addr_result);

    return 0;
}

//=============================================================================
//
void tcpip_disconnect(tcpip_connection *connection)
{
    if (socket_system_user_count == 0)
    {
        return;
    }
    closesocket(connection->socket_);
    cleanup_socket_system();
}

//=============================================================================
//
int tcpip_send(const char *buffer, int len, tcpip_connection *connection)
{
    EXIT_ON_SYSTEM_NOT_INITED();
// Send an initial buffer
#ifdef DEBUG
    printf("Sending: %s\r\n", buffer);
#endif

    int send_result = send(connection->socket_, buffer, len, 0);
    if (send_result == SOCKET_ERROR)
    {
        printf("send failed with error: %d\r\n", WSAGetLastError());
        closesocket(connection->socket_);
        cleanup_socket_system();
        return -1;
    }

    // Did not send everything, return the amount of data that was sent.
    if (send_result != len)
    {
        return send_result;
    }

    // everything was sent and
    return 0;
}

//=============================================================================
//
int tcpip_receive(char *buffer, int len, tcpip_connection *connection)
{
    EXIT_ON_SYSTEM_NOT_INITED();

    int recv_result = recv(connection->socket_, buffer, len, 0);
    if (recv_result == 0) // Closing connection case
    {
        printf("Connection closed\r\n");
        closesocket(connection->socket_);
        cleanup_socket_system();
        return 0;
    }
    else if (recv_result < 0) // Error case
    {
        printf("recv failed with error: %d\r\n", WSAGetLastError());
        return -1;
    }
#ifdef DEBUG
    printf("Receiving: %s\r\n", buffer);
#endif

    // contains the amout of data received.
    return recv_result;
}


robot_interface.h/.c contains the code that handles sending the robot the correct command

and parsing the return messages

robot_interface.h

#include "socket_comm.h"

// Contain the information about a robot's connection.
// Members should not be access individually
typedef struct 
{
    tcpip_connection robot_connection_;
    int connected_;
}Meca500;

/// Connect to a meca500 to the control port
int connect_robot(char* address, Meca500 *robot);

/// Disconnect a meca500
int disconnect_robot(Meca500 *robot);

/// Wait for a specified return code.
/// Return 0 if code was received.
/// Return 1 if an error code ( between 1000 and 2000) was received
/// Return -1 if there was a network error.
int wait_for_return_code(int code, Meca500 *robot);

/// Wait for End of Block flag.
/// Return 0 if code was received.
/// Return 1 if an error code ( between 1000 and 2000) was received
/// Return -1 if there was a network error.
int wait_for_EOB(Meca500 *robot);

/// Send an ActivateRobot command and wait for it to be completed.
/// return 0 for success
/// return -1 for failure
int activate_robot(Meca500 *robot);

/// Send an DeactivateRobot command and wait for it to be completed.
/// return 0 for success
/// return -1 for failure
int deactivate_robot(Meca500 *robot);

/// Send an activatesim command and wait for it to be completed.
/// return 0 for success
/// return -1 for failure
int activate_sim(Meca500 *robot);

/// Send an deactivatesim command and wait for it to be completed.
/// return 0 for success
/// return -1 for failure
int deactivate_sim(Meca500 *robot);

/// Send an home command and wait for it to be completed.
/// return 0 for success
/// return -1 for failure
int home(Meca500 *robot);

/// Sends a MoveJoint command. Do not wait for completion.
/// return 0 for success
/// return -1 for failure
int movejoints(Meca500 *robot, float joints[6]);

/// Sends a MovePose command. Do not wait for completion.
/// return 0 for success
/// return -1 for failure
int movepose(Meca500 *robot, float euler[6]);

/// Sends a MoveJoint command to go to zero. Do not wait for completion.
/// return 0 for success
/// return -1 for failure
int movetozero(Meca500 *robot);

/// Sends a MoveJoint command for the shipping position. Do not wait for completion.
/// return 0 for success
/// return -1 for failure
int movetoshipping(Meca500 *robot);


robot_interface.c

#include "robot_interface.h"

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

/// The control port for the meca500
static const char *CONTROL_PORT = "10000";

/// Utility to exit the function if the robot is not connected
#define EXIT_ON_ROBOT_NOT_CONNECTED(connected_flag) \
    if (connected_flag == 0)                        \
    {                                               \
        printf("Robot not connected.\r\n");         \
        return -1;                                  \
    }

//=============================================================================
//
/// Extract the code ("[3000][..." -> 3000) from a message and return it as int.
/// if not found, return 0;
int extract_code(const char *message)
{
    int code = 0;
    char *first_bracket = NULL;
    char *second_bracket = NULL;
    do
    {
        first_bracket = strchr(message, '[');
        second_bracket = strchr(message, ']');
        if ((int)(second_bracket - first_bracket) == 5)
        {
            code = 1000 * (first_bracket[1]-'0') + 
            100 * (first_bracket[2]-'0') + 
            10 * (first_bracket[3]-'0') + 
            1 * (first_bracket[4]-'0');
        }
    } while (code == 0 || first_bracket == NULL || second_bracket == NULL);
    return code;
}

//=============================================================================
//
int wait_for_return_code(int code, Meca500 *robot)
{
    int found_error_code = 0;
    int found_requested_code = 0;
    char recv_buffer[512] = {0};
    int recv_result = 0;
    int code_received = 0;
    do
    {
        recv_result = tcpip_receive(recv_buffer, 512, &robot->robot_connection_);
        if (recv_result < 0)
        {
            return -1;
        }
        code_received = extract_code(recv_buffer);
        found_requested_code = (code_received == code);
        found_error_code = code_received >= 1000 && code_received < 2000;
    } while (!found_requested_code && !found_error_code);

    if (found_error_code)
    {
        return 1;
    }
    if (found_requested_code)
    {
        return 0;
    }

    // Should not come here...
    return -1;
}

//=============================================================================
//
int wait_for_EOB(Meca500 *robot)
{
    return wait_for_return_code(3012, robot);
}

//=============================================================================
//
int connect_robot(char *address, Meca500 *robot)
{
    int result = 0;
    // Connect with the good port
    result = tcpip_connect(address, CONTROL_PORT, &robot->robot_connection_);

    if (result == -1)
    {
        printf("Robot connection failed on network error.\r\n");
        return -1;
    }

    // Wait for the robot to return data.

    char recv_buffer[512] = {0};

    result = tcpip_receive(recv_buffer, 512, &robot->robot_connection_);
    if (result == -1)
    {
        printf("Robot connection failed on network error (recv).\r\n");
        return -1;
    }
    else if (result == 0)
    {
        printf("Robot connection failed because robot closed the connection.\r\n");
        return -1;
    }

    // Check for the connection acknowledged from the robot.
    char *search_result = strstr(recv_buffer, "[3000]");
    if (search_result == NULL)
    {
        printf("Robot connection failed because robot did not accept the control.\r\n");
        printf("%s\r\n", recv_buffer);
        return -1;
    }
    robot->connected_ = 1;
    printf("Connected to the Meca500 at addresss %s\r\n", address);
    return 0;
}

//=============================================================================
//
int disconnect_robot(Meca500 *robot)
{
    tcpip_disconnect(&robot->robot_connection_);
    robot->connected_ = 0;
}

//=============================================================================
//
int activate_robot(Meca500 *robot)
{
    EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char *msg = "ActivateRobot\0";
    tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    int result = wait_for_return_code(2000, robot);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int deactivate_robot(Meca500 *robot)
{
    EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char *msg = "DeactivateRobot\0";
    tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    int result = wait_for_return_code(2004, robot);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int activate_sim(Meca500 *robot)
{
    //EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char *msg = "ActivateSim\0";
    int result = tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    if (result != 0)
    {
        return -1;
    }
    result = wait_for_return_code(2045, robot);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int deactivate_sim(Meca500 *robot)
{
    EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char *msg = "DeactivateSim\0";
    int result = tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    if (result != 0)
    {
        return -1;
    }
    result = wait_for_return_code(2046, robot);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int home(Meca500 *robot)
{
    EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char *msg = "Home\0";
    int result = tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    if (result != 0)
    {
        return -1;
    }
    result = wait_for_return_code(2002, robot);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int movejoints(Meca500 *robot, float joints[6])
{
    EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char msg[100] = {0};
    sprintf(msg, "MoveJoints(%10.4f, %10.4f, %10.4f, %10.4f, %10.4f, %10.4f)\0", joints[0], joints[1], joints[2], joints[3], joints[4], joints[5]);
    int result = tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int movepose(Meca500 *robot, float euler[6])
{
    EXIT_ON_ROBOT_NOT_CONNECTED(robot->connected_);
    char msg[100] = {0};
    sprintf(msg, "MovePose(%10.4f, %10.4f, %10.4f, %10.4f, %10.4f, %10.4f)\0", euler[0], euler[1], euler[2], euler[3], euler[4], euler[5]);
    int result = tcpip_send(msg, strlen(msg) + 1, &robot->robot_connection_);
    if (result != 0)
    {
        return -1;
    }
    return 0;
}

//=============================================================================
//
int movetozero(Meca500 *robot)
{
    float joints[6] = {0};
    return movejoints(robot, joints);
}

//=============================================================================
//
int movetoshipping(Meca500 *robot)
{
    float joints[6] = {0, -60, 60, 0, 0, 0};
    return movejoints(robot, joints);
}


main.c is the main program that calls the function from the robot's interface.


main.c

#define WIN32_LEAN_AND_MEAN

#include <stdlib.h>
#include <stdio.h>
#include "robot_interface.h"

// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")


/// Little example to show usage of the Meca500 in C
/// This example Connect to the robot, activate the simulation,
/// Activate/home the robot and do some movement.
/// Then, it deactivate the robot and the simulation and disconnect.
int main(int argc, char **argv) 
{
    Meca500 robot;
    // Connect
    int result = connect_robot("192.168.0.100", &robot);
    if( result != 0)
    {
        return -1;
    }
    /// For visual clarity, will no check for the return value of the function.
    activate_sim(&robot);
    activate_robot(&robot);
    home(&robot);

    float pose_1 [6] = {250,0,250,0,90,0};
    float pose_2 [6] = {150,0,150,180,00,180};
    movepose(&robot, pose_1);
    movepose(&robot, pose_2);
    movetozero(&robot);
    movetoshipping(&robot);
    /// Movement function to not wait for completion before returning from their call
    /// So we wait eob here.
    wait_for_EOB(&robot);
    
    deactivate_robot(&robot);
    deactivate_sim(&robot);
    disconnect_robot(&robot);

    return 0;
}