Typically: "How do I... ", "How can I... " questions
napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03

Hi,

I recently upgraded to the latest version of CoppeliaSim and since then simSwitchThread from a plugin does not seem to be working in the same way. When I run the following threaded LUA-script I see the robot moving. Removing sim.switchThread() I no longer see the robot moving. Removing sim.setThreadAutomaticSwitch(false) I again see the robot moving, from automatic thread switching.

Code: Select all

    local joint = sim.getObjectHandle("joint")
local cylic, limits = sim.getJointInterval(joint)

jointValue = limits[1]
for i= 1,1000 do
sim.setJointPosition(joint, jointValue)
jointValue = jointValue + limits[2]/100
if jointValue > limits[1] + limits[2] then
jointValue = limits[1]
end
end

When I run the plugin code below I do not see the robot moving. This is also true regardless of whether sim.setThreadAutomaticSwitch(false) is there or not.

Code: Select all

	auto joint = simGetObjectHandle("joint");
simBool cyclic;
simFloat limits[2];
simGetJointInterval(joint, &cyclic, limits);

auto jointValue = limits[0];

for (int i = 0; i < 1000; ++i) {
simSetJointPosition(joint, jointValue);
jointValue = jointValue + limits[1] / 100.f;
if (jointValue > limits[0] + limits[1])
jointValue = limits[0];
}

This is just an example program but in a plugin that I'm writing and using I use simSwitchThread() when debugging to visualize planning as it happens. Am I making some mistake or should I use some other way in order to visualize what is happening?

napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03

Some more information. I downgraded to CoppeliaSim 4.0.0 and still couldn't see my robot moving the way I used to. Looking at the script, I found that the entry point was no longer sysCall_threadmain but rather I had the code below. Moving my script to a new threaded child script, a call to sysCall_threadmain was generated, and things worked. I don't understand where the code below is coming from but it showed up after updating. Next step I'll try updating again and see if calling sysCall_threadmain helps. Can't do that today though.

Code: Select all

function sysCall_init()
corout=coroutine.create(coroutineMain)
end

function sysCall_actuation()
local ok,errorMsg=coroutine.resume(corout)
if errorMsg then
error(debug.traceback(corout,errorMsg),2)
end
end
end

function coroutineMain()


napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03

Looking again, I see that my child script was converted from Threaded to Non-threaded as I upgraded..

napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03

So I did upgrade again and it seems there is a new handling of child scripts? If I create a threaded child script in the newest version of CoppeliaSim it generates the code that doesn't work with simSwitchThread().

coppelia
Posts: 8881
Joined: 14 Dec 2012, 00:25

Hello,

yes, there has been a switch in how threads are handled: prior to CoppeliaSim V4.2.0, there were two type of scripts: threaded and non-threaded. Since CoppeliaSim V4.2.0, there is only one type of script, which however can accommodate a threaded or non-threaded behaviour through Lua coroutines. This change simplifies script handling, writing code, and will eventually allow to offer also other scripted languages.

Now, from within a threaded script in CoppeliaSim V4.2.0, all functions should still work the same, and most scripts are automatically converted to a coroutine model. This is also what happened to your scripts probably. From within your converted scripts using coroutines, sim.setThreadAutomaticSwitch, sim.switchThread, etc. should work normally. From a plugin however, you are not able to switch threads anymore.

So, this is where your problem comes from. You are probably lifting heavy stuff from within the message function of your plugin, probably in a instance pass event. This is not the right approach, and lacks a lot of flexibility. Much better is to always use a plugin in conjunction with a script. For instance, if you need to execute threaded code during simulation, then you could use for instance a threaded add-on that looks like:

Code: Select all

function sysCall_info()
return {autoStart=true}
end

function sysCall_init()

end

function sysCall_cleanup()

end

return {cmd='cleanup'}
end

function sysCall_beforeSimulation()
corout=coroutine.create(coroutineMain)
end

function sysCall_actuation()
local ok,errorMsg=coroutine.resume(corout)
if errorMsg then
error(debug.traceback(corout,errorMsg),2)
end
end
end

function coroutineMain()
for i=1,1000,1 do
local positions=simMyPlugin.computeJointValues(...)
for j=1,#jointHandles,1 do
sim.setJointPosition(jointHandles[j],positions[j])
end
end
end
From above code you can see that best is to use the plugin for its strength only (e.g. calculation speed, connectivity with the outside world or some hardware, specific library functions, etc.), and keep all the rest within a script. This will also greatly speed-up development times, since you do not constantly need to recompile your plugin.

Cheers

napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03

I don't think I can massage my use case into the model you are suggesting in any simple way. Maybe I should provide a bit more background and see if there is a way that I'm not finding myself.

I am working on an application where I have robots in a gantry structure and I am using CAD data as input in order to plan trajectories. The method you suggest works well for visualizing the final trajectories. I am, however, also interested in what is happening as I sample robot configurations (I have 9DOF per gantry-robot system so there is a lot of freedom) and interpolate. This visual information is used for two things. One is coming up with ways to improve the program and the other is for debugging, where visual information and connecting from Visual Studio has made this project possible. Crucially, I need the visual information as it is happening, not when the script is finished. Even sending back the selected configuration sample is not enough.

Maybe my use case fits in with using an Addon but I don't see how at the moment. Let me know if you have any suggestions as to how to proceed. For now I am back to using 4.1.0.

coppelia
Posts: 8881
Joined: 14 Dec 2012, 00:25

I still don't completely understand what you are doing ;)

• how is your plugin code called exactly? it seems that it originates from some threaded script (using old threads). And that script will eventually call a plugin function which will take a few seconds to execute, then return to the script? like scriptFlow --> pluginFlow --> scriptFlow ?
• Does your plugin run also other threads? Does your plugin communicate with the outside world on its own?
Cheers

napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03

I'd love to show you code, but I'm not allowed to so I'll give explaining another go :) The project that I'm working on is described in http://www.es.mdh.se/pdf_publications/5704.pdf, although we have since improved many things. Essentially we are using a gantry-robot system to place rebars for building a rebar cage. The gantry-robot system consists of three robots on a gantry where each robot base can be moved in x, y and z.

The purpose of the plugin that I'm working on is to compute paths for placing and tying rebars into a rebar cage. A rebar can be held by one or two robots which are moving the rebars linearly in Euclidean space, and planning is sometimes performed in a difficult environment. This, and perhaps the way we are doing things, means that planning can take a lot of time which is not much of a problem since everything happens offline. We then move to our real world station and test which is a lot of fun!

Going back to how I interact with CoppeliaSim, my script is called from a threaded child script. First there is some setup code, which is irrelevant for this discussion I think, and then there is a call asking the plugin to compute a path for placing a rebar. At the moment I simply wait until finished and then go for the next rebar.

The plugin does not use any threads and the only outside world communication is to read information about the rebar cage from file, as well as some config files.

Switching threads comes into the picture when for example sampling for a configuration to be used by a robot when placing a rebar. The way I do this is to sample the gantry position around the grip point of the robot and finding the last six DOF by IK. Visualizing this process helps me validate that I am sampling the gantry position in a reasonable way. There are also numerous other situations where this visualization has helped me.

I hope this attempted explanation is better, let me know if I am still not clear enough :)

Thanks again for the quick replies!

coppelia
Posts: 8881
Joined: 14 Dec 2012, 00:25

Ok, it becomes a bit more clear. But in the end, it is just a matter of visualization, correct?

• script calls plugin
• plugin computes something
• plugin switches threads a few times to make the computed data visible
• plugin returns to the script
why don't you do:
• script calls plugin
• plugin computes something
• plugin returns data to the script
• the script visualizes the data (e.g. via movement, via transparent shapes, via drawing objects, etc.)
And by the way, you can still use old-type threads in V4.2.0, by setting keepOldThreadedScripts=true in system/usrset.txt. Then start CoppeliaSim V4.2.0, load your V4.1.0 scene, save it in the V4.2.0 format. Then you can reverse the keepOldThreadedScripts to false again. But this should be temporary, and it would be best to try to find a correct workaround.

Cheers

napoleon
Posts: 19
Joined: 12 Dec 2019, 11:03