您的位置:首页 > 运维架构

CoppeliaSim 脚本(3)Customization scripts and Callback function

2020-03-06 16:20 966 查看

本文为官方文档翻译,仅供个人参考,如有侵权,联系删除

3.Customization scripts

自定义脚本是嵌入式脚本,可在很大程度上用于自定义模拟场景。 它们被附加到场景对象(或与场景对象相关联),并且可以通过场景层次结构中的黑色脚本图标轻松识别它们:

以下是自定义脚本的主要属性:
他们是非线程脚本。
它们始终在同一场景中执行:在运行模拟时以及在不运行模拟时。
它们附加到场景对象(或与场景对象关联)(即它们是关联的脚本)。关联脚本构成了CoppeliaSim分布式控制体系结构的基础,并且共享了方便的属性,如果关联对象被复制,该属性将被自动复制。
以上属性允许自定义脚本共享附加组件和子脚本的某些最佳功能。自定义脚本允许创建可自定义的模型,例如:想象一下一个模型,该模型已放入场景中,并且即使没有运行模拟也能够自行配置或调整。这可能是一个机器人,用户可以在其中通过单个滑块重新定位来调整各种链接长度。
自定义脚本包含阻塞型函数。这意味着每次调用它们时,它们都应执行一些任务,然后返回控制权。如果未返回控制,则整个应用程序将暂停。定制脚本函数经常被系统调用,但主脚本也会遵循精确的执行顺序进行调用。定制脚本还支持回调功能。
自定义脚本通常分为以下几个函数:

-- This is a customization script. It is intended to be used to customize a scene in
-- various ways, mainly when simulation is not running. When simulation is running,
-- do not use customization scripts, but rather child scripts if possible

function sysCall_init()
-- do some initialization here
end

function sysCall_nonSimulation()
-- is executed when simulation is not running
end

function sysCall_cleanup()
-- do some clean-up here
end

-- You can define additional system calls here:
function sysCall_beforeSimulation()
end

function sysCall_actuation()
end

function sysCall_sensing()
end

function sysCall_suspend()
end

function sysCall_suspended()
end

function sysCall_resume()
end

function sysCall_afterSimulation()
end

function sysCall_beforeInstanceSwitch()
end

function sysCall_afterInstanceSwitch()
end

function sysCall_userConfig()
end

function sysCall_dynCallback(inData)
-- See the dynamics callback function section in the user manual for details about the input argument
end

function sysCall_jointCallback(inData)
-- See the joint callback function section in the user manual for details about input/output arguments
return outData
end

function sysCall_contactCallback(inData)
-- See the contact callback function section in the user manual for details about input/output arguments
return outData
end

function sysCall_beforeCopy(inData)
for key,value in pairs(inData.objectHandles) do
print("Object with handle "..key.." will be copied")
end
end

function sysCall_afterCopy(inData)
for key,value in pairs(inData.objectHandles) do
print("Object with handle "..key.." was copied")
end
end

function sysCall_beforeDelete(inData)
for key,value in pairs(inData.objectHandles) do
print("Object with handle "..key.." will be deleted")
end
-- inData.allObjects indicates if all objects in the scene will be deleted
end

function sysCall_afterDelete(inData)
for key,value in pairs(inData.objectHandles) do
print("Object with handle "..key.." was deleted")
end
-- inData.allObjects indicates if all objects in the scene were deleted
end

function sysCall_beforeMainScript()
-- Can be used to step a simulation in a custom manner.
local outData={doNotRunMainScript=false} -- when true, then the main script won't be executed
return outData
end

function sysCall_afterCreate(inData)
for i=1,#inData.objectHandles,1 do
print("Object with handle "..inData.objectHandles[i].." was created")
end
end

4.Callback function

回调函数是特殊的脚本函数,可以由CoppeliaSim在模拟步骤的特定状态下调用:

  1. 在每个动力学模拟步骤之前和之后,物理引擎都会调用动力学回调函数。
  2. 物理引擎为每个接触对调用接触回调函数。
  3. 物理引擎为关节控制调用关节回调函数
  4. 每当获取或应用新图像时,系统都会调用视觉回调函数。

4.1 Dynamics callback functions

非线程子脚本或自定义脚本可以包含动力学回调函数。 如果存在,则物理引擎将在每个动力学模拟步骤之前和之后使用适当的参数调用回调函数。 动态回调函数可能经常被调用,通常每个模拟步骤调用10 * 2次(请记住,默认情况下,物理引擎时间步骤比模拟时间步骤小10倍)。 因此,脚本尽可能简单,以避免减慢仿真速度。
以下是一个简单的动态回调函数:

function sysCall_dynCallback(inData)
-- This function gets called often, so it might slow down the simulation
--     (this is called twice at each dynamic simulation step, by default 20x more often than a child script)
-- We have:
-- inData.passCnt : the current dynamics calculation pass. 1-10 by default. See next item for details.
-- inData.totalPasses : the number of dynamics calculation passes for each "regular" simulation pass.
--                      10 by default (i.e. 10*5ms=50ms which is the default simulation time step)
-- inData.dynStepSize : the step size used for the dynamics calculations (by default 5ms)
-- inData.afterStep : false when called before, and true after a dynamics step was computed.

local txt=string.format(" the %ith dynamics calculation step (out of %i steps)",inData.passCnt,inData.totalPasses)
if inData.afterStep then
txt="After"..txt
else
txt="Before"..txt
end
print(txt)
end

4.Joint callback functions

非线程子脚本或自定义脚本可以包含关节回调函数。 当存在给定关节(必须动态启用并且还必须启用其控制循环)时,物理引擎将使用适当的参数调用回调函数,从而允许用户自定义相关关节的控制环以进行编写 低级控制算法。 可能会经常调用联合回调函数,对于给定的联合,通常每个模拟步骤调用10次(请记住,默认情况下,物理引擎时间步骤比模拟时间步骤小10倍)。 因此,脚本尽可能简单,以避免减慢仿真速度。
以下是一个简单的PID联合回调函数:

function sysCall_jointCallback(inData)
-- This function gets called often, so it might slow down the simulation
--     (this is called at each dynamic simulation step, by default 10x more often than a child script)
-- We have:
-- inData.first : whether this is the first call from the physics engine, since the joint
--                was initialized (or re-initialized) in it.
-- inData.revolute : whether the joint associated with this script is revolute or prismatic
-- inData.cyclic : whether the joint associated with this script is cyclic or not
-- inData.handle : the handle of the joint associated with this script
-- inData.lowLimit : the lower limit of the joint associated with this script (if the joint is not cyclic)
-- inData.highLimit : the higher limit of the joint associated with this script (if the joint is not cyclic)
-- inData.passCnt : the current dynamics calculation pass. 1-10 by default. See next item for details.
-- inData.totalPasses : the number of dynamics calculation passes for each "regular" simulation pass.
--                      10 by default (i.e. 10*5ms=50ms which is the default simulation time step)
-- inData.currentPos : the current position of the joint
-- inData.targetPos : the desired position of the joint
-- inData.errorValue : targetPos-currentPos (with revolute cyclic joints we take the shortest cyclic distance)
-- inData.effort : the last force or torque that acted on this joint along/around its axis. With Bullet,
--                 torques from joint limits are not taken into account
-- inData.dynStepSize : the step size used for the dynamics calculations (by default 5ms)
-- inData.targetVel : the joint target velocity (as set in the user interface)
-- inData.maxForce : the joint maximum force/torque (as set in the user interface)
-- inData.velUpperLimit : the joint velocity upper limit (as set in the user interface)
--
-- Make sure that the joint is dynamically enabled, is in force/torque mode, motor enabled and
-- control loop enabled, otherwise this function won't be called

if inData.first then
PID_P=0.1
PID_I=0
PID_D=0
pidCumulativeErrorForIntegralParam=0
end

-- The control happens here:
-- 1. Proportional part:
local ctrl=inData.errorValue*PID_P

-- 2. Integral part:
if PID_I~=0 then
pidCumulativeErrorForIntegralParam=pidCumulativeErrorForIntegralParam+inData.errorValue*inData.dynStepSize
else
pidCumulativeErrorForIntegralParam=0
end
ctrl=ctrl+pidCumulativeErrorForIntegralParam*PID_I

-- 3. Derivative part:
if not inData.first then
ctrl=ctrl+(inData.errorValue-pidLastErrorForDerivativeParam)*PID_D/inData.dynStepSize
end
pidLastErrorForDerivativeParam=inData.errorValue

-- 4. Calculate the velocity needed to reach the position in one dynamic time step:
local maxVelocity=ctrl/inData.dynStepSize -- max. velocity allowed.
if (maxVelocity>inData.velUpperLimit) then
maxVelocity=inData.velUpperLimit
end
if (maxVelocity<-inData.velUpperLimit) then
maxVelocity=-inData.velUpperLimit
end
local forceOrTorqueToApply=inData.maxForce -- the maximum force/torque that the joint will be able to exert

-- 5. Following data must be returned to CoppeliaSim:
firstPass=false
local outData={}
outData.velocity=maxVelocity
outData.force=forceOrTorqueToApply
return outData
end

4.3The contact callback function

687/5000
非线程子脚本或自定义脚本可以包含接触回调函数。 如果存在,并且物理引擎检测到两个可响应形状之间发生接触,则将使用适当的参数调用接触回调函数,从而允许用户自定义接触的处理方式。接触回调函数可能经常被调用,有时每个仿真步骤被调用数百次(还请记住,默认情况下,对于一个仿真步骤,物理引擎将被调用10次)。 因此,请保持简单,以避免减慢仿真速度。
以下是典型的接触回调函数:

function sysCall_contactCallback(inData)
-- Will objects with inData.handle1 and inData.handle2 respond to dynamic collision?
local retData={}
retData.ignoreContact=false -- handle contact here
retData.collisionResponse=true -- shapes will collide

if inData.engine==sim.physics_bullet then
retData.bullet={}
retData.bullet.friction=0
retData.bullet.restitution=0
end

if inData.engine==sim.physics_ode then
retData.ode={}
retData.ode.maxContacts=16
retData.ode.mu=0
retData.ode.mu2=0
retData.ode.bounce=0
retData.ode.bounceVel=0
retData.ode.softCfm=0
retData.ode.softErp=0
retData.ode.motion1=0
retData.ode.motion2=0
retData.ode.motionN=0
retData.ode.slip1=0
retData.ode.slip2=0
retData.ode.fDir1={0,0,0}
local mode=1 -- bit-coded. See below
-- 1=dContactMu2
-- 2=dContactFDir1
-- 4=dContactBounce
-- 8=dContactSoftERP
-- 16=dContactSoftCFM
-- 32=dContactMotion1
-- 64=dContactMotion2
-- 128=dContactSlip1
-- 256=dContactSlip2
-- 512=dContactApprox1_1
-- 1024=dContactApprox1_2
-- 2048=dContactApprox1
retData.ode.contactMode=mode
end

if inData.engine==sim.physics_vortex then
end

if inData.engine==sim.physics_newton then
retData.newton={}
retData.newton.staticFriction=0
retData.newton.kineticFriction=0
retData.newton.restitution=0
end

return(retData)
end

4.4Vision callback functions

当与视觉传感器相关联时,子脚本或自定义脚本可以包括视觉回调功能。当存在给定视觉传感器时,则系统将在每次获取或应用新图像时调用回调函数,从而允许用户执行图像处理。以下API函数就是这种情况:sim.handleVisionSensor,sim.checkVisionSensor,sim.checkVisionSensorEx,sim.setVisionSensorImage和sim.setVisionSensorCharImage。
视觉回调函数的位置适用一些条件:通常,它应位于自定义脚本或非线程子脚本中。但是,如果从线程子脚本中调用触发API函数(例如sim.handleVisionSensor),则视觉回调函数也应位于线程子脚本中。如果在非线程子脚本和自定义脚本中都存在视觉回调函数,并且两者都附加到视觉传感器,则将首先调用该子脚本,然后再调用自定义脚本。
以下表示一个空的视觉回调函数:

function sysCall_vision(inData)
-- We have:
-- inData.handle : the handle of the vision sensor.
-- inData.resolution : the x/y resolution of the vision sensor
-- inData.clippingPlanes : the near and far clipping planes of the vision sensor
-- inData.viewAngle : the view angle of the vision sensor (if in persp. proj. mode)
-- inData.orthoSize : the ortho size of the vision sensor (if in orth. proj. mode)
-- inData.perspectiveOperation : true if the sensor is in persp. proj. mode

local outData={}
outData.trigger=false -- true if the sensor should trigger
outData.packedPackets={} -- a table of packed packets. Can be accessed via e.g. sim.readVisionSensor
return outData
end

可以通过使用各种API函数来执行图像处理。 视觉插件导出了一些非常简单的图像处理功能。 通过图像插件(OpenCV包装器)支持更多图像处理功能。
以下是一个简单的边缘检测视觉回调函数,该函数触发并返回一个数据包(基于视觉插件功能):

function sysCall_vision(inData)
simVision.sensorImgToWorkImg(inData.handle)
simVision.edgeDetectionOnWorkImg(inData.handle,0.1)
simVision.workImgToSensorImg(inData.handle)

local outData={}
outData.trigger=true
local packetData={1.0,42.123,129.3}
outData.packedPackets={sim.packFloatTable(packetData)}
return outData
end

以下是视觉回调函数,该函数在获取的图像上绘制一个圆圈(基于图像插件函数):

function sysCall_vision(inData)
local imgHandle=simIM.readFromVisionSensor(inData.handle)
local center={inData.resolution[1]/2,inData.resolution[2]/2}
local radius=(inData.resolution[1]+inData.resolution[2])/8
simIM.circle(imgHandle,center,radius,{255,0,255},4)
simIM.writeToVisionSensor(imgHandle,inData.handle)
simIM.destroy(imgHandle)
end

4.5Trigger callback functions

力/扭矩传感器相关联时,子脚本或自定义脚本可以包括触发器回调函数。
某些条件适用于触发器回调函数的位置:通常,它应位于自定义脚本或非线程子脚本中。 但是,如果从线程子脚本中调用了触发API函数(例如sim.handleVisionSensor或sim.handleProximitySensor),则触发器回调函数也应位于线程子脚本中。 如果在非线程子脚本以及自定义脚本中都存在触发器回调函数,这两个都附加在对象触发上,那么将首先调用子脚本,然后再调用自定义脚本。
视觉传感器可以在视觉回调函数内部生成触发信号。 然后按以下示例调用触发器回调(如果存在)

function sysCall_trigger(inData)
-- We have:
-- inData.handle : the handle of the vision sensor.
-- inData.packedPackets : an array of data packets, packed (use sim.unpackFloatTable to unpack)
--    the first data packet always contains 15 auxiliary values about the acquired image:
--    - minimum of {intensity, red, green blue and depth value}
--    - maximum of {intensity, red, green blue and depth value}
--    - average of {intensity, red, green blue and depth value}

local outData={}
outData.trigger=true
return outData
end

当检测到物体时,接近传感器会生成触发信号。 然后按以下示例调用触发器回调(如果存在):

function sysCall_trigger(inData)
-- We have:
-- inData.handle : the handle of the proximity sensor.
-- inData.detectedObjectHandle : handle of detected object
-- inData.detectedPoint : detected point, relative to sensor frame
-- inData.normalVector : normal vector at detected point, relative to sensor frame

local outData={}
outData.trigger=true
return outData
end

以下是力/转矩传感器触发回调函数的示例,其中力/转矩传感器已损坏:

function sysCall_trigger(inData)
-- We have:
-- inData.handle : the handle of the force/torque sensor.
-- inData.force : current force
-- inData.torque : current torque
-- inData.filteredForce : current filtered force
-- inData.filteredTorque : current filtered torque
sim.breakForceSensor(inData.handle)
end
  • 点赞
  • 收藏
  • 分享
  • 文章举报
qq_29696095 发布了5 篇原创文章 · 获赞 0 · 访问量 538 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: