Return callback time being ignored... or how to avoid the use of global variables


I am trying to wrap my head around Ardupilot and LUA scripts in general, so if I am missing something obvious my apologies in advance.

I am seeing unexpected behaviour when trying to schedule a callback by passing parameters to the function in an attempt to avoid using a global variables. When scheduling the callback via return and passing parameter(s) to the callback function the specified time is being ignored resulting it in the callback being called immediately. If I avoid passing parameters to the callback function and use global variables instead the callback is called according to the specified schedule. However, I prefer to avoid the use of global variables whenever possible

for example, return update(1), 1000 does not work as expected; the function is called with the correct parameter but the time is being ignored and the function is called immediately instead of in 1000ms

the following script demonstrates the issue:

-- dummy script to test callback timing...

local knMaxIterations = 9
local knFrequency = 1000

function dosomething( nIteration )
	gcs:send_text( 6, "dummy::dosomething #" .. tostring(nIteration) )

function update( nIteration )
	gcs:send_text( 6, "dummy::update #" .. tostring(nIteration) )

    if not arming:is_armed() then
        dosomething( nIteration )    

	nIteration = nIteration + 1

	if nIteration > knMaxIterations then
		nIteration = 1

	return update(nIteration),knFrequency

return update(1),knFrequency

hopefully this is just an issue of incorrect syntax and not a shortcoming of the implementation.

any assistance will be greatly appreciated


You cannot pass arguments in a callback. Unfortunately, global variables are a necessary evil.

You can think of the callback as a function pointer, which has the same limitation in a language like C++.

It’s sometimes useful to use multiple functions rather than using persistent state variables, like so:

local RUN_INTERVAL_MS   = 500

function update()
    -- return to standby on disarmed/unhealthy
    if not (ahrs:healthy() and arming:is_armed()) then
        gcs:send_text(MAV_SEVERITY_INFO, 'Returning to standby')
        return standby, RUN_INTERVAL_MS
    -- execution logic goes here
    return update, RUN_INTERVAL_MS

function standby()
    -- wait until armed with healthy ahrs
    if ahrs:healthy() and arming:is_armed() then
        gcs:send_text(MAV_SEVERITY_INFO, 'Entering update function')
        return update, RUN_INTERVAL_MS
    return standby, RUN_INTERVAL_MS

return standby()  -- execute immediately

Thank you for the clarification… and the suggestion