V-rep 远程API模块使用方法

原文地址:http://www.coppeliarobotics.com/helpFiles/en/remoteApiModusOperandi.htm#synchronous

远程API或旧式远程API不应与基于BØ的远程API混合使用,后者是远程API的更新版本,它更灵活,更易于使用,最重要的是,更易于扩展。

远程API函数的调用方式与常规API函数类似,但是有两个主要区别:

  • 大多数远程API函数都返回相似的值:返回码。请始终记住,返回码是位编码的(因此,您必须测试各个位才能正确解释它)。
  • 大多数远程API函数都需要两个附加参数:操作模式和clientID(由simxStart函数返回的标识符)

远程API函数必须通过套接字通信传递到服务器(CoppeliaSim),执行任务,然后返回到调用方(客户端),因此需要一种操作模式和特定的返回码。一种稚嫩(或常规)的方法是让客户端发送请求,然后等待服务器处理该请求并进行回复:在大多数情况下,这将花费太多时间,并且滞后会影响客户端应用程序。相反,远程API通过提供四种执行函数调用或控制仿真进度的主要机制,让用户选择操作模式的类型和仿真进行的方式:

  • 阻塞函数调用 Blocking function calls
  • 非阻塞函数调用 Non-blocking function calls
  • 数据流 Data streaming
  • 同步运转 Synchronous operation

Blocking function calls 阻塞函数调用:阻塞函数调用是一种常规的方法,用于无法承受不等待服务器回复的情况,例如以下情况:

// 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!    
}

下图说明了阻塞函数调用:

在这里插入图片描述
非阻塞函数调用 Non-blocking function calls:非阻塞函数调用适用于以下情况:我们仅希望将数据发送到CoppeliaSim而不需要回复,例如以下情况:

// Following function (non-blocking mode) will set the position of a joint:
simxSetJointPosition(clientID,jointHandle,jointPosition,simx_opmode_oneshot); 

下图说明了非阻塞函数调用:
在这里插入图片描述
在某些情况下,重要的是能够在同一条消息中发送各种数据,以使该数据也同时应用于服务器端(例如,我们希望将机器人的3个关节应用于其上 CoppeliaSim模型在完全相同的时间,即在相同的模拟步骤中)。 在这种情况下,用户可以暂时停止通信线程以实现此目的,如以下示例所示:

simxPauseCommunication(clientID,1);
simxSetJointPosition(clientID,joint1Handle,joint1Value,simx_opmode_oneshot);
simxSetJointPosition(clientID,joint2Handle,joint2Value,simx_opmode_oneshot);
simxSetJointPosition(clientID,joint3Handle,joint3Value,simx_opmode_oneshot);
simxPauseCommunication(clientID,0);

// Above's 3 joints will be received and set on the CoppeliaSim side at the same time

下图说明了暂时停止通信线程的效果:
在这里插入图片描述
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)):
    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.

下图说明了数据流:
在这里插入图片描述
完成流数据传输后,远程API客户端应始终通知服务器(即CoppeliaSim)停止流传输该数据,否则服务器将继续流传输不必要的数据并最终降低速度。 为此,请使用simx_opmode_discontinue操作模式。
同步操作 Synchronous operation:从上面的函数调用中,您可能已经注意到,模拟将在不考虑远程API客户端进度的情况下进行或进行。 默认情况下,远程API函数调用将异步执行。 但是,在某些情况下,需要通过从远程API客户端一侧控制仿真进度来使远程API客户端与仿真进度同步。 这可以通过使用远程API同步模式来实现。 在这种情况下,需要预先启用远程API服务器服务以进行同步操作(这可以通过simRemoteApi.start函数或通过连续的远程API服务器服务配置文件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

...

下图说明了同步模式:
在这里插入图片描述
当调用simxSynchronousTrigger时,下一个模拟步骤将开始计算。 这并不意味着当函数调用返回时,下一个模拟步骤将完成计算。 因此,您必须确保读取正确的数据。 如果未采取特殊措施,则可能从上一个仿真步骤或当前仿真步骤读取数据,如下图所示:
在这里插入图片描述
您有几种可能性可以克服上述问题。 最简单的方法是在调用simxSynchronousTrigger之后立即以阻塞方式调用函数:

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

以及每个远程API客户端中的以下代码:

// 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
}

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

下图说明了如何在服务器端(即CoppeliaSim远程API插件端)处理传入的远程API命令:
在这里插入图片描述

额外细节

在客户端(即您的应用程序)上,至少有两个线程正在运行:主线程(您将在其中调用远程API函数),以及通信线程(将在其后处理数据传输)。 场景)。 客户端上可以有任意数量的通信线程(即通信线路):请确保为每个线程调用simxStart。 通过CoppeliaSim插件实现的服务器端以类似的方式运行。 下图说明了远程API的操作方式:
在这里插入图片描述
下面介绍了各种受支持的操作模式:

  • simx_opmode_oneshot:非阻塞模式。将命令发送到服务器以执行(1)-(b)-(3)。如果可用(i)-(2),则从本地缓冲区返回对先前执行的同一命令的答复。该函数不等待服务器(7)-(i)的答复。在服务器端,命令被临时存储(4)-(d),执行一次(d)-(9)-(g),然后将答复发送回(g)-(6)。此模式通常与“设置功能”(例如simxSetJointPosition)一起使用,用户无需担心返回值。
  • simx_opmode_blocking:阻止模式。将命令发送到服务器以执行(1)-(b)-(3),并且该功能等待来自服务器(7)-(i)-(2)的答复。然后,接收到的回复将从收件箱缓冲区(i)中删除,而其他操作模式则不会发生这种情况。在服务器端,命令被临时存储(4)-(d),执行一次(d)-(9)-(g),然后将答复发送回(g)-(6)。此模式通常与“ get-functions”(例如simxGetObjectHandle)一起使用,在这种情况下,用户需要对发送的命令进行回复。
  • simx_opmode_streaming:非阻塞模式。将命令发送到服务器以执行(1)-(b)-(3)。如果可用(i)-(2),则从本地缓冲区返回对先前执行的同一命令的答复。该函数不等待服务器(7)-(i)的答复。与simx_opmode_oneshot相似,但区别在于命令将存储在服务器端(4)-(e),连续执行(e)-(9)-(g),然后连续发送回客户端(g) -(6)。此模式通常与“ get-functions”(例如simxGetJointPosition)一起使用,其中用户不断需要特定的值。
  • simx_opmode_oneshot_split(不推荐):非阻塞模式。将命令(以小的数据块形式)逐渐发送到服务器以执行(1)-(a)-(3)。如果可用(i)-(2),则从本地缓冲区返回对先前执行的同一命令的答复。该函数不等待服务器(7)-(h)-(i)的答复。完全发送命令后,将从(a)中删除该命令。在服务器端,命令块被临时存储(4)-(c),并且在完全接收到命令后,该命令将被执行一次(5)-(d)-(9)-(f)并回复逐渐发送回客户(f)-(6)。客户端以小块(7)-(h)接收答复,当答复完成时,它将存储在本地缓冲区(8)-(i)中。此模式通常与与大量数据关联的“设置功能”一起使用(例如simxSetVisionSensorImage),以免使通信网络过载。
  • simx_opmode_streaming_split(不推荐):非阻塞模式。将命令(以小的数据块形式)逐渐发送到服务器以执行(1)-(a)-(3)。如果可用(i)-(2),则从本地缓冲区返回对先前执行的同一命令的答复。该函数不等待服务器(7)-(h)-(i)的答复。完全发送命令后,将从(a)中删除该命令。在服务器端,命令块被临时存储(4)-(c),当命令被完全接收(5)-(e)时,命令将连续执行(e)-(9)-(f)并逐渐将答复发送回客户端(f)-(6)。客户端以小块(7)-(h)接收答复,当答复完成时,它将存储在本地缓冲区(8)-(i)中。此模式通常与与大量数据相关联的“获取功能”一起使用(例如simxGetVisionSensorImage),在这种情况下,用户不断需要数据而不会使通信网络过载。
    simx_opmode_discontinue:非阻塞模式。命令发送到服务器(1)-(b)-(3)。如果可用(i)-(2),则从本地缓冲区返回对先前执行的同一命令的答复。该函数不等待服务器(7)-(i)的答复。在服务器端,该命令仅清除(e)中的类似命令。将答复发送到客户端(6)-(7),该客户机还将清除位于(i)中的类似答复。此模式用于释放(i)中的某些内存(类似于simx_opmode_remove),或中断流命令(即通过从(e)中删除它们)。
  • simx_opmode_buffer:非阻塞模式。没有命令发送到服务器,而是仅从本地缓冲区(如果有)(i)-(2)返回对先前执行的同一命令的答复。该模式通常与simx_opmode_streaming或simx_opmode_streaming_split操作模式结合使用:首先,使用流命令开始执行恒定的命令,然后仅提取命令答复。
  • simx_opmode_remove:非阻塞模式。没有命令发送到服务器,而是仅从本地缓冲区(如果存在)中清除对先前执行的同一命令的答复(如果有的话)。该函数不返回任何值,除了返回码。此模式可用于释放客户端的一些内存,但很少需要。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值