大多数远程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);
//等电机转完,远程端再来下一步,太慢了
如果希望在同一模拟步骤中执行多个命令,如三关节机器人的所有关节都转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)
一下子对一个关节发出了很多命令,机器人来不及动的
服务器可以预测客户端需要的数据类型。要实现这一点,客户端必须使用“流”或“连续”操作模式标志向服务器发出此提示(即函数存储在服务器端,定期执行和发送,不需要客户机发出请求)。这可以看作是从客户机到服务器的命令/消息订阅,服务器将在其中向客户机流数据。这种流操作请求和流数据的读取在客户端可能是这样的:(要结合代码看)
// 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.