How to call a script function via Python (ZMQ API) using sim.callScriptFunction

Typically: "How do I... ", "How can I... " questions
Post Reply
wang1201
Posts: 2
Joined: 17 Nov 2025, 04:29

How to call a script function via Python (ZMQ API) using sim.callScriptFunction

Post by wang1201 »

Hi everyone,

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
Below is my full script for reference:

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
The script handle is correct (e.g., 1010074), and the function name matches.


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?
Any help or suggestions would be greatly appreciated. Thank you!
coppelia
Site Admin
Posts: 10804
Joined: 14 Dec 2012, 00:25

Re: How to call a script function via Python (ZMQ API) using sim.callScriptFunction

Post by coppelia »

Hello,

you are calling sim.callScriptFunction in an old fashion. Please try following:

In an empty scene add a non-threaded lua script, rename it to scriptAlias, and add following function to it:

Code: Select all

function test(a, b, c)
    print(a, b, c)
    return {1, 2, 3}
end


The from your Python ZeroMQ remote API client, ass following code:

Code: Select all

script = sim.getObject('/scriptAlias')
print(script)
reply = sim.callScriptFunction('test', script, 'Hello', 'Paul', 21)
print(reply)
Let me know if that works.

Cheers
wang1201
Posts: 2
Joined: 17 Nov 2025, 04:29

Re: How to call a script function via Python (ZMQ API) using sim.callScriptFunction

Post by wang1201 »

Thank you very much for the help!
I tested the code above using Add → Script → Simulation script → Non-threaded → Lua to add a new script named scriptAlias, and the Python call worked correctly (I received “1, 2, 3”).

However, when I apply the same method to /PioneerP3DX/fastHokuyo/Script, the return value of getMeasuredData() is still None.

Code: Select all

59
None
Here is my code:

Code: Select all

from coppeliasim_zmqremoteapi_client import RemoteAPIClient

client = RemoteAPIClient()
sim = client.getObject('sim')

try:
    script = sim.getObject('/PioneerP3DX/fastHokuyo/Script')
    print(script)
    reply = sim.callScriptFunction('getMeasuredData', script)
    print(reply)

except Exception as e:
    print(f"Error: {e}")
    raise SystemExit(1)
My question is:
Is this because the fastHokuyo's default script is not a “Non-threaded simulation script”, so it cannot be called this way?
The manual seems outdated—so in version 4.10, how should sim.callScriptFunction be used correctly?
Is it enough to replace just the second parameter int scriptHandle with sim.getObject()?(I previously used sim.getScript())
coppelia
Site Admin
Posts: 10804
Joined: 14 Dec 2012, 00:25

Re: How to call a script function via Python (ZMQ API) using sim.callScriptFunction

Post by coppelia »

In your sysCall_sensing function, your measuredData is a local variable: logically it will be nil in function getMeasuredData.

Cheers
Post Reply