V-REP教程(八) 详解远程API运作方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DanielDingshengli/article/details/86492344

远程API函数和常规API函数区别

大多数远程API函数有返回码,需要操作模式(op_mode)和客户端ID(clientID)。
VREP作为服务器端通过套接字与客户端(matlab、python等)通信,最简单的方法是客户端发送请求,等待服务器处理请求、回复,和计算机当中等待标注I/O输入输出类似。这会花费很多时间,滞后的回复也将影响客户端应用程序。在VREP中远程API允许用户通过四种操作模式来执行函数调用或控制进度:

阻塞函数调用

适用于我们不得不等待服务器回复的情况
如:

// Following function (blocking mode) will retrieve an object handle:
if (simxGetObjectHandle(clientID,"myJoint",&jointHandle,simx_opmode_blocking)==simx_return_ok) 
{
    // here we have the joint handle in variable jointHandle!    
}

下图演示了一个阻塞函数调用:
在这里插入图片描述

非阻塞函数调用

非阻塞函数调用适用于只想将数据发送给V-REP,而不需要回复

// Following function (non-blocking mode) will set the position of a joint:
simxSetJointPosition(clientID,jointHandle,jointPosition,simx_opmode_oneshot); 
//等电机转完,远程端再来下一步,太慢了

在这里插入图片描述

simulation time

在这里插入图片描述

理解

如果希望在同一模拟步骤中执行多个命令,如三关节机器人的所有关节都转60度。在这种情况下,用户可以暂时停止通信线程,以达到这个目的。
在这里插入图片描述

        # 控制命令需要同时方式,故暂停通信,用于存储所有控制命令一起发送
        vrep.simxPauseCommunication(clientID, True)
        for i in range(jointNum):
            vrep.simxSetJointTargetPosition(clientID, jointHandle[i], 120/RAD2DEG, vrep.simx_opmode_oneshot)
        vrep.simxPauseCommunication(clientID, False)

错误的运用。谨以此鄙视下我的烂代码:

    vrep.simxPauseCommunication(clientID, True)
    for i in range(1,10):
        vrep.simxSetJointTargetPosition(clientID, joint1, i*5*math.pi/180 ,vrep.simx_opmode_oneshot)
        _, tip_j2 = vrep.simxGetObjectPosition(clientID, tip, joint2,vrep.simx_opmode_oneshot)
        _, target_j2 = vrep.simxGetObjectPosition(clientID, target, joint2,vrep.simx_opmode_oneshot)
        time.sleep(0.5)
    print('tip_j2:',tip_j2)
    print('tar_j2:',target_j2)
    vrep.simxPauseCommunication(clientID, False)

一下子对一个关节发出了很多命令,机器人来不及动的

数据流 Data streaming

服务器可以预测客户端需要的数据类型。要实现这一点,客户端必须使用“流”或“连续”操作模式标志向服务器发出此提示(即函数存储在服务器端,定期执行和发送,不需要客户机发出请求)。这可以看作是从客户机到服务器的命令/消息订阅,服务器将在其中向客户机流数据。这种流操作请求和流数据的读取在客户端可能是这样的:(要结合代码看

// Streaming operation request (subscription) (function returns immediately (non-blocking)):
simxGetJointPosition(clientID,jointHandle,&jointPosition,simx_opmode_streaming);//定期执行

// The control loop:
while (simxGetConnectionId(clientID)!=-1) // while we are connected to the server..
{ 
    // Fetch the newest joint value from the inbox (func. returns immediately (non-blocking)):
    //从收件箱中读取,和simx_opmode_buffer配合用
    if (simxGetJointPosition(clientID,jointHandle,&jointPosition,simx_opmode_buffer)==simx_return_ok) 
    { 
        // here we have the newest joint position in variable jointPosition!    
    }
    else
    {
        // once you have enabled data streaming, it will take a few ms until the first value has arrived. So if
        // we landed in this code section, this does not always mean we have an error!!!
        //一旦您启用了数据流,它将花费几毫秒直到第一个值到达。因此,如果我们在这个代码段登陆,这并不总是意味着我们有错误!!!
    }
}

// Streaming operation is enabled/disabled individually for each command and
// object(s) the command applies to. In above case, only the joint position of
// the joint with handle jointHandle will be streamed.
//读jointHandle的joint position时是流模式

在这里插入图片描述
所以开始的时候可能会读成0
simx_opmode_discontinue操作模式用于关闭流

同步操作

从上面的函数调用中,您可能已经注意到VREP仿真器的推进或进行不考虑远程API客户端的进度默认情况下,远程API函数调用将异步执行。但是,在某些情况下,远程API客户机需要通过控制来自远程API客户机端的模拟进度来与模拟进度同步。这可以通过使用远程API同步模式来实现。在这种情况下,远程API服务器服务需要预先启用同步操作(this can be achieved via the simRemoteApi.start function, or via the continuous remote API server service configuration file remoteApiConnections.txt

simxSynchronous(clientID,true); // Enable the synchronous mode (Blocking function call)
simxStartSimulation(clientID,simx_opmode_oneshot);

// The first simulation step waits for a trigger before being executed

simxSynchronousTrigger(clientID); // Trigger next simulation step (Blocking function call)

// The first simulation step is now being executed,仿真第一步从这开始

simxSynchronousTrigger(clientID); // Trigger next simulation step (Blocking function call)

// The second simulation step is now being executed

注意:The first simulation step is now being executed
在这里插入图片描述
当调用simxsynchronioustrigger时,下一个模拟步骤将开始计算。这并不意味着当函数调用返回时,下一个模拟步骤将完成计算。因此,您必须确保读取正确的数据。如果没有采取特殊措施,可以从之前的仿真步骤或当前仿真步骤读取数据,如下图所示:
在这里插入图片描述
你有几种可能来克服以上的问题。最简单的方法是在调用simxsynchronioustrigger后直接以阻塞方式调用函数:

simxSynchronous(clientID,true); // Enable the synchronous mode (Blocking function call)
simxStartSimulation(clientID,simx_opmode_oneshot);

// The first simulation step waits for a trigger before being executed

simxSynchronousTrigger(clientID); // Trigger next simulation step (Blocking function call)

// The first simulation step is now being executed

simxGetPingTime(clientID); // After this call, the first simulation step is finished (Blocking function call)

// Now we can safely read all streamed values

在这里插入图片描述

注意

当您有几个远程API客户端,每个客户端都需要发送它们的触发器来启动下一个模拟步骤时,您应该将以下代码放在场景中的非线程子脚本中

function sysCall_init()
   iteration=1
end

function sysCall_sensing()
   simSetIntegerSignal('iteration',iteration)
   iteration=iteration+1
end

function sysCall_cleanup()
   simClearIntegerSignal('iteration')
end

远程客户端需要的代码:

// enable the synchronous mode on the client:
simxSynchronous(clientID,1);

// start the simulation:
simxStartSimulation(clientID,simx_opmode_blocking);

// enable streaming of a value:
int anyValue;
simxGetIntegerSignal(clientID,"anyValue",&anyValue,simx_opmode_streaming);

// enable streaming of the iteration counter:
int iteration1;
simxGetIntegerSignal(clientID,"iteration",&iteration,simx_opmode_streaming);

// Now step a few times:
for (int i=0;i<30;i++)
{
    int res=simxGetIntegerSignal(clientID,"iteration",&iteration1,simx_opmode_buffer);
    if (res!=simx_return_ok)
        iteration1=-1;
    simxSynchronousTrigger(clientID);
    int iteration2=iteration1;
    while (iteration2==iteration1)
    { // wait until the iteration counter has changed
        res=simxGetIntegerSignal(clientID,"iteration",&iteration2,simx_opmode_buffer);
        if (res!=simx_return_ok)
            iteration2=-1;
    }

    // Now fetch other values:
    simxGetIntegerSignal(clientID,"anyValue",&anyValue,simx_opmode_buffer);
    printf("Streamed value: %i\n",anyValue) // this is the freshest value
}

在上面的代码中,只需确保您启用的最后一个流命令用于信号迭代,否则迭代将不是最后一个更新的值。

非常形象的一幅图

在这里插入图片描述

额外的细节

在客户端(即您的应用程序),至少将运行两个线程:主线程(您将从其中调用远程API函数的线程)和通信线程(将在幕后处理数据传输的线程)。在客户端可以有任意数量的通信线程(即通信线路):确保为每个通信线程调用simxStart。服务器端使用V-REP插件实现,其操作方式类似。下图展示了远程API的工作方式:
在这里插入图片描述
这部分看得似懂非懂,谁搞明

各种操作类型的描述

在这里插入图片描述
结合上图来看,有点晕,日后再补充

重点

simx_opmode_oneshot:This mode is often used with “set-functions” (e.g. simxSetJointPosition), where the user doesn’t care about the return value.
simx_opmode_blocking: This mode is often used with “get-functions” (e.g. simxGetObjectHandle), where the user requires a reply to the sent command.
simx_opmode_streaming: This mode is often used with “get-functions” (e.g. simxGetJointPosition), where the user requires a specific value constantly.
simx_opmode_oneshot_split:This mode is often used with “set-functions” associated with large amounts of data (e.g. simxSetVisionSensorImage), in order not to overload the communication network.
simx_opmode_streaming_split:This mode is often used with “get-functions” associated with large amounts of data (e.g. simxGetVisionSensorImage), where the user requires data constantly without overloading the communication network.
simx_opmode_discontinue:This mode is used to release some memory in (i) (similar to simx_opmode_remove), or to interrupt streaming commands (i.e. by removing them from (e)).
simx_opmode_buffer: This mode is often used in conjunction with the simx_opmode_streaming or simx_opmode_streaming_split operation mode: first, a constant command execution is started with a streaming command, then only command replies fetched.(此模式通常与simx_opmode_streaming或simx_opmode_streaming_split操作模式一起使用:首先,使用流命令启动常量命令执行,然后仅获取命令响应。)
simx_opmode_remove:This mode can be used to release some memory on the client side, but is rarely necessary.

猜你喜欢

转载自blog.csdn.net/DanielDingshengli/article/details/86492344
今日推荐