Call sim.Step from add-on script.

Typically: "How do I... ", "How can I... " questions
Post Reply
DrRiften
Posts: 7
Joined: 06 Jun 2024, 13:36

Call sim.Step from add-on script.

Post by DrRiften »

I have following questions when writing threading code in script.
  • Can I call sim.step outside sysCall_thread?
  • Can I call sim.step in other script's function outside sysCall_thread through sim.callScriptFunction? Even if the caller is within sysCall_thread?
My situation is that I have a simple path tracking function in my add on script

Code: Select all

function executePath(joints, path)
    -- path is a list of configurations

    local need_stop = false
    disableDynamic(idx)
    if sim.getSimulationStopping() then
        need_stop = true
        sim.startSimulation()
    end

    local sw=sim.setStepping(true)
    for i, conf in ipairs(path) do
        for j, joint in ipairs(joints) do
            sim.setJointPosition(joint, conf[j])
        end
        sim.step()
    end
    sim.setStepping(sw)

    if need_stop then
        sim.stopSimulation()
    end
end
And call it from a customization script's sysCall_thread

Code: Select all

function sysCall_thread()
	sim.callScriptFunction('executePath', script_handle, joints, path)
end
It seems that the sim.step does not work here. All steps would be executed in an instant.

coppelia
Site Admin
Posts: 10467
Joined: 14 Dec 2012, 00:25

Re: Call sim.Step from add-on script.

Post by coppelia »

Hello,

yes, this is correct: sim.step does not work across a C-boundary, or when not in a sysCall_thread section.

You should rather proceed in a manner similar to what follows:

Code: Select all

--Script1:
sim.callScriptFunction('triggerPathExecution', script_handle, args)

Code: Select all

--script2:
function triggerPathExecution(args)
    allCommands[#allCommands + 1] = {cmd = 'executePath', args = args}
end

function sysCall_thread()
    allCommands = {}
    while not sim.getSimulationStopping() do
        if #allCommands > 0 then
            local cmd = allCommands[1]
            table.remove(allCommands, 1)
            if cmd.cmd == 'executePath' then
                -- handle the command here. sim.step is allowed.
            end
        else
            sim.step()
        end
    end 
end
Cheers

DrRiften
Posts: 7
Joined: 06 Jun 2024, 13:36

Re: Call sim.Step from add-on script.

Post by DrRiften »

Thank you. I'm still confused about coppeliaSim thread.
Based on my current understanding, coppeliaSim implements multi-threading through Lua coroutine, which is non-preemptive. CoppeliaSim provides preemptive-like experience by calling coroutine.yield and coroutine.resume periodically (2ms) to switch between simulation and user defined thread. Is my understanding correct?
And here are some more questions.
  1. What would happen if there are multiple scripts calling sim.step? How many times would the main thread be yielded?
  2. How to distinguish thread and non-thread script? Is there any coroutine if I have no sysCall_thread in any script?

coppelia
Site Admin
Posts: 10467
Joined: 14 Dec 2012, 00:25

Re: Call sim.Step from add-on script.

Post by coppelia »

about your questions:

1. sim.step acts only on the current script. So each time you call it (from within a thread (or coroutine)), the function immediately after it will be called only once the simulation time has increased to t+dt. Calling sim.step twice from within a thread will bring you to t+2*dt. Try this:

Code: Select all

function sysCall_init()
    sim = require('sim')
end

function sysCall_thread()
    while not sim.getSimulationStopping() do
        print(sim.getSimulationTime())
    end
end
vs ths:

Code: Select all

function sysCall_init()
    sim = require('sim')
end

function sysCall_thread()
    sim.setStepping(true)
    while not sim.getSimulationStopping() do
        print(sim.getSimulationTime())
    end
end
vs that:

Code: Select all

function sysCall_init()
    sim = require('sim')
end

function sysCall_thread()
    sim.setStepping(true)
    while not sim.getSimulationStopping() do
        print(sim.getSimulationTime())
        sim.step()
    end
end
But technically, sysCall_thread is handled via hidden coroutine code.

2. You can check if you run a coroutine via following code:

Code: Select all

local thread, yieldForbidden = coroutine.running()
if not yieldForbidden then
    -- is a coroutine and can yield (or sim.step())
end 
Cheers

Post Reply