I’m trying to call a function inside my child script /PioneerP3DX/fastHokuyo/Script from Python using the ZeroMQ Remote API.
My child script is mostly the default Hokuyo script, and I only added this function:
Code: Select all
function getMeasuredData()
return measuredData
end
Code: Select all
sim=require'sim'
function sysCall_init()
maxScanDistance=5
showLines=true
generateData=true
rangeData=true -- if false, then X/Y/Z data rel to sensor base
discardMaxDistPts=true
self=sim.getObject('..')
visionSensors={sim.getObject("../sensor1"),sim.getObject("../sensor2")}
local collection=sim.createCollection(0)
sim.addItemToCollection(collection,sim.handle_all,-1,0)
sim.addItemToCollection(collection,sim.handle_tree,self,1)
sim.setObjectInt32Param(visionSensors[1],sim.visionintparam_entity_to_render,collection)
sim.setObjectInt32Param(visionSensors[2],sim.visionintparam_entity_to_render,collection)
sim.setObjectFloatParam(visionSensors[1],sim.visionfloatparam_far_clipping,maxScanDistance)
sim.setObjectFloatParam(visionSensors[2],sim.visionfloatparam_far_clipping,maxScanDistance)
red={1,0,0}
lines=sim.addDrawingObject(sim.drawing_lines,1,0,-1,10000,red)
end
function sysCall_cleanup()
sim.removeDrawingObject(lines)
end
function sysCall_sensing()
local measuredData={}
sim.addDrawingObjectItem(lines,nil)
for i=1,2,1 do
local r,t,u=sim.readVisionSensor(visionSensors[i])
if u then
local sensorM=sim.getObjectMatrix(visionSensors[i])
local relRefM=sim.getObjectMatrix(self)
relRefM=sim.getMatrixInverse(relRefM)
relRefM=sim.multiplyMatrices(relRefM,sensorM)
local p={0,0,0}
p=sim.multiplyVector(sensorM,p)
t={p[1],p[2],p[3],0,0,0}
for j=0,u[2]-1,1 do
for k=0,u[1]-1,1 do
local w=2+4*(j*u[1]+k)
local v={u[w+1],u[w+2],u[w+3],u[w+4]}
if generateData then
if rangeData then
table.insert(measuredData,v[4])
else
if v[4]<maxScanDistance*0.9999 or not discardMaxDistPts then
p=sim.multiplyVector(relRefM,v)
table.insert(measuredData,p[1])
table.insert(measuredData,p[2])
table.insert(measuredData,p[3])
end
end
end
if showLines then
p=sim.multiplyVector(sensorM,v)
t[4]=p[1]
t[5]=p[2]
t[6]=p[3]
sim.addDrawingObjectItem(lines,t)
end
end
end
end
end
print("Measured data:", #measuredData, "points")
-- print one example value
if #measuredData > 0 then
print("Example:", measuredData[1])
end
end
function getMeasuredData()
return measuredData
end
Python code:
Code: Select all
from coppeliasim_zmqremoteapi_client import RemoteAPIClient
import numpy as np
import matplotlib.pyplot as plt
client = RemoteAPIClient()
sim = client.getObject('sim')
# Call robot script getLaserPoints() or getMeasuredData()
# Obtain script handle (script attached to object /PioneerP3DX or /PioneerP3DX/fastHokuyo)
try:
# Directly use getScript to obtain script handle
script_handle = sim.getScript(sim.handle_self, '/PioneerP3DX/fastHokuyo/Script')
# script_handle = sim.getObjectHandle('/PioneerP3DX/fastHokuyo/Script')
print(f"✓ Script handle obtained: {script_handle}")
# Call getLaserPoints function in the script
points = sim.callScriptFunction(
'getMeasuredData@/PioneerP3DX/fastHokuyo/Script',
script_handle,
)
print(f"✓ Function call succeeded, return type: {type(points)}")
print(f"✓ Raw return data: {points}")
except Exception as e:
print(f"✗ Error: {e}")
raise SystemExit(1)
Problem:
Even though the script prints valid data in Coppeliasim during simulation, calling getMeasuredData() from Python always returns:
Code: Select all
✓ Script handle obtained: 1010074
✓ Function call succeeded, return type: <class 'NoneType'>
✓ Raw return data: None
My question:
What is required to make sim.callScriptFunction() calling a function from the child script and return some data?
Some specific doubts:
- Is my usage of sim.callScriptFunction() correct?
- Do I need to declare measuredData as a global variable explicitly?
- Should the function be outside sysCall_sensing() (as I did)?
- Does the Hokuyo script type related to this problem?