lua/buffer.lua:44: attempt to yield across a C-call boundary

Report crashes, strange behaviour, or apparent bugs
Post Reply
JichaoYang
Posts: 5
Joined: 15 Jan 2025, 10:18

lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by JichaoYang »

Code: Select all

function zmq_REQ_send_and_recv(dataSend)

    ---- SEND
    printf('[requester] Sending "%s"...', dataSend)
    dataSend=sim.packFloatTable(dataSend)
    
    print(dataSend)
    simZMQ.send(requester, dataSend, 0)
    
    ---- RECEIVE
    local rc, returnData = simZMQ.recv(requester, 0)
    
    if rc~=-1 then
        dataRecv = sim.unpackFloatTable(returnData)
        printf('[requester] Received "%s"', dataRecv)
    end
    return(dataRecv)
end
Part of the log:

Code: Select all

currentPosition: 1.3811
[requester] Sending "{-1, 1.381072}"...
[buffer (8 bytes)]
[requester] Received "{-0.629}"
currentPosition: 0.9107
[requester] Sending "{-1, 0.910686}"...
[buffer (8 bytes)]
[requester] Received "{-1.885}"
currentPosition: 0.1175
[requester] Sending "{-1, 0.117526}"...
...ram Files/CoppeliaRobotics/CoppeliaSimEdu/lua/buffer.lua:44: attempt to yield across a C-call boundary
[sandboxScript:info] Simulation stopping...
[sandboxScript:info] Simulation stopped.
My code is used to exchange information frequently between coppeliasim and external python scripts. After running for a while, it very randomly throws the above error then causes the termination of the external python script, which causes the task to be unsustainable.

I think this may be a problem caused internally by sim.packFloatTable, because as the logs show, dataSend was successfully printed in the previous step and this is no different from when it succeeded.

Would appreciate a solution, thanks.

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

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by coppelia »

Hello,

can you create a minimalistic, self-contained scene that illustrates the problem, so that we can easily reproduce that behaviour?

What is calling zmq_REQ_send_and_recv? Is that code threaded or non-threaded?

Cheers

JichaoYang
Posts: 5
Joined: 15 Jan 2025, 10:18

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by JichaoYang »

Thank you for your reply.

The function snippet that calls it is as follows:

Code: Select all

function sysCall_thread()
    while true do
        
        -- Get the current joint position
        currentPosition = sim.getJointPosition(jointHandle)
        
        print(string.format("currentPosition: %.4f", currentPosition))
        
        -- Compute error
        if useZMQ then
            msg1[1] = targetPosition
            msg1[2] = currentPosition
            msg2 = zmq_REQ_send_and_recv(msg1)
            err = msg2[1]
        else 
            err = targetPosition - currentPosition
        end
        
        if -0.1<err and err<0.1 then
            sim.setJointTargetVelocity(jointHandle, 0)
            print('Reached.')
            
            -- Change direction for demonstration.
            targetPosition = -targetPosition
            
        end
        
        -- Compute integral term
        integralError = integralError + err * sim.getSimulationTimeStep()
        
        -- Compute derivative term (only used in PID mode)
        derivativeError = (err - previousError) / sim.getSimulationTimeStep()
        
        -- Compute control output
        if usePID then
            velocityCommand = Kp * err + Ki * integralError + Kd * derivativeError
        else
            velocityCommand = Kp * err + Ki * integralError  -- PI control only
        end
        
        -- Apply velocity command to joint
        sim.setJointTargetVelocity(jointHandle, velocityCommand)
        
        -- Update previous error
        previousError = err
    end
end
It seems that the scope of the problem occurs within this section. The problem is not accidental: in every run of the scenario, this reported error always ends up being triggered at some point in the communication.

For some scientific reasons, it is not convenient to show more details of the scenario and the external algorithm python code. We apologise for any inconvenience.

JichaoYang
Posts: 5
Joined: 15 Jan 2025, 10:18

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by JichaoYang »

coppelia wrote: 19 Mar 2025, 10:46 Hello,

can you create a minimalistic, self-contained scene that illustrates the problem, so that we can easily reproduce that behaviour?

What is calling zmq_REQ_send_and_recv? Is that code threaded or non-threaded?

Cheers
I will post the lua code for the entire script below to help you reproduce the problem. This ur5 robot arm is the only thing in the scene.

Basically, our task is to calculate the error of the control in real time with the help of an external python script. Unfortunately, the current external algorithm is not perfect. In particular, it is very slow, which means that this calculation can take several seconds. But it will eventually return the result, so this shouldn't cause problems in a thread callback function, right?

I'm a bit confused by the error message, as it seems to be triggering some c-code issue directly, without any higher level hints?

Code: Select all

sim=require'sim'
simZMQ = require('simZMQ')

print('ZMQ connected. UR5 requester ready to receive control orders...')
context = simZMQ.ctx_new()
requester = simZMQ.socket(context, simZMQ.REQ)
simZMQ.setsockopt(requester,simZMQ.RCVTIMEO,sim.packInt32Table{2000})
simZMQ.setsockopt(requester,simZMQ.LINGER,sim.packInt32Table{500})
simZMQ.connect(requester, 'tcp://127.0.0.1:5557')

-- Choose use zmq or not
useZMQ = true
msg1={0,0}

jointHandle = sim.getObject('../joint',{index=1})
--jointHandle = sim.getObject('../../damn')

-- Control Parameters
Kp = 0.1  -- Proportional gain
Ki = 0.05  -- Integral gain
Kd = 0.01  -- Derivative gain

-- Target position (modify as needed)
targetPosition = 1  -- Target in radians

-- Choose control mode: true for PID, false for PI
usePID = true 
--usePID = false

-- Initialize variables
previousError = 0
integralError = 0

function sysCall_thread()
    while true do
        
        -- Get the current joint position
        currentPosition = sim.getJointPosition(jointHandle)
        
        print(string.format("currentPosition: %.4f", currentPosition))
        
        -- Compute error
        if useZMQ then
            msg1[1] = targetPosition
            msg1[2] = currentPosition
            msg2 = zmq_REQ_send_and_recv(msg1)
            err = msg2[1]
        else 
            err = targetPosition - currentPosition
        end
        
        if -0.1<err and err<0.1 then
            sim.setJointTargetVelocity(jointHandle, 0)
            print('Reached.')
            
            -- Change direction for demonstration.
            targetPosition = -targetPosition
            
        end
        
        -- Compute integral term
        integralError = integralError + err * sim.getSimulationTimeStep()
        
        -- Compute derivative term (only used in PID mode)
        derivativeError = (err - previousError) / sim.getSimulationTimeStep()
        
        -- Compute control output
        if usePID then
            velocityCommand = Kp * err + Ki * integralError + Kd * derivativeError
        else
            velocityCommand = Kp * err + Ki * integralError  -- PI control only
        end
        
        -- Apply velocity command to joint
        sim.setJointTargetVelocity(jointHandle, velocityCommand)
        
        -- Update previous error
        previousError = err
    end
end

function sysCall_cleanup()
    simZMQ.close(requester)
    simZMQ.ctx_term(context)
end

function zmq_REQ_send_and_recv(dataSend)

    ---- SEND
    printf('[requester] Sending "%s"...', dataSend)
    dataSend=sim.packFloatTable(dataSend)
    
    print(dataSend)
    simZMQ.send(requester, dataSend, 0)
    
    ---- RECEIVE
    local rc, returnData = simZMQ.recv(requester, 0)
    
    if rc~=-1 then
        dataRecv = sim.unpackFloatTable(returnData)
        printf('[requester] Received "%s"', dataRecv)
    end
    return(dataRecv)
end

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

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by coppelia »

In your Lua script, make sure to put the initialization code inside of a sysCall_init function, like:

Code: Select all

sim=require'sim'
simZMQ = require('simZMQ')

function sysCall_init()
    print('ZMQ connected. UR5 requester ready to receive control orders...')
    context = simZMQ.ctx_new()
    requester = simZMQ.socket(context, simZMQ.REQ)
    simZMQ.setsockopt(requester,simZMQ.RCVTIMEO,sim.packInt32Table{2000})
    simZMQ.setsockopt(requester,simZMQ.LINGER,sim.packInt32Table{500})
    simZMQ.connect(requester, 'tcp://127.0.0.1:5557')

    -- Choose use zmq or not
    useZMQ = true
    msg1={0,0}

    jointHandle = sim.getObject('../joint',{index=1})
    --jointHandle = sim.getObject('../../damn')

    -- Control Parameters
    Kp = 0.1  -- Proportional gain
    Ki = 0.05  -- Integral gain
    Kd = 0.01  -- Derivative gain

    -- Target position (modify as needed)
    targetPosition = 1  -- Target in radians

    -- Choose control mode: true for PID, false for PI
    usePID = true 
    --usePID = false

    -- Initialize variables
    previousError = 0
    integralError = 0
end

function sysCall_thread()
    while true do
        
        -- Get the current joint position
        currentPosition = sim.getJointPosition(jointHandle)
        
        print(string.format("currentPosition: %.4f", currentPosition))
        
        -- Compute error
        if useZMQ then
            msg1[1] = targetPosition
            msg1[2] = currentPosition
            msg2 = zmq_REQ_send_and_recv(msg1)
            err = msg2[1]
        else 
            err = targetPosition - currentPosition
        end
        
        if -0.1<err and err<0.1 then
            sim.setJointTargetVelocity(jointHandle, 0)
            print('Reached.')
            
            -- Change direction for demonstration.
            targetPosition = -targetPosition
            
        end
        
        -- Compute integral term
        integralError = integralError + err * sim.getSimulationTimeStep()
        
        -- Compute derivative term (only used in PID mode)
        derivativeError = (err - previousError) / sim.getSimulationTimeStep()
        
        -- Compute control output
        if usePID then
            velocityCommand = Kp * err + Ki * integralError + Kd * derivativeError
        else
            velocityCommand = Kp * err + Ki * integralError  -- PI control only
        end
        
        -- Apply velocity command to joint
        sim.setJointTargetVelocity(jointHandle, velocityCommand)
        
        -- Update previous error
        previousError = err
    end
end

function sysCall_cleanup()
    simZMQ.close(requester)
    simZMQ.ctx_term(context)
end
Then, try to call sim.setStepping(true) as the last command in the initialization section.
In your code, you set a timeout of 2 seconds. Try to increase that and and see if that makes a difference.

Cheers

JichaoYang
Posts: 5
Joined: 15 Jan 2025, 10:18

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by JichaoYang »

Thanks, I tried it as you described.
It seems that sim.setStepping(true) solved the problem.

If possible, could you give some guidance on why this problem might be occurring and why this function might solve it?
This will help me gain experience for subsequent use of the platform.
Thanks again!

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

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by coppelia »

In a CoppeliaSim Lua script, by default there is preemptive threading (when running in a thread), which means that CoppeliaSim can/will automatically call sim.yield after some time (which will interrupt the script and yield command back). With sim.setStepping(true) this automatic yielding is prevented.

Cheers

JichaoYang
Posts: 5
Joined: 15 Jan 2025, 10:18

Re: lua/buffer.lua:44: attempt to yield across a C-call boundary

Post by JichaoYang »

Get it. Thank you for your reply.

Post Reply