Back to basics - script observing over time

I am trying to build a lua script that will do an action if a parameter is true for X time period… say 10 seconds.

I had attempted this with a while loop counting down but it gives me timeout errors. Is there a “normal” way to make an observation over time?

I expected this script to make “counter” count down from 10 to 0 and then play a tune. It works but almost instantly. I don’t seem to be able to make it slow down. I get LUA exceeded error messages.


function update() -- this is the loop which periodically runs
 
 -----------CONFIG--------------------------------------------
 local thresh = 2 -- threshold at which the loop triggers
 local counter = 10 

 --------END-----------------------------------------------------------------------
 
   
  while( thresh > 1 )
  do
  
		if (counter < 0 )
			then
				notify:play_tune ( 'MFT180MLL8O2CEMNGT118O3C.O2L16G.L4MLO3C' )
			else
				counter = counter-1
				gcs:send_text(0, string.format("counter %.1f",  counter))
				
		end
		
		
		
	 	--return update, 2000 -- reschedules the loop
  
 
	end
  
  
  
  
  
  return update, 1000 -- reschedules the loop
end

return update() -- run immediately before starting to reschedule

ArduPilot Lua scripts are given small execution time slices on the CPU. Running long while loops is ill advised because you will potentially exceed the given time slice (as you’re seeing).

Here’s a short script that alternates between two methods of determining timeout states without running blocking code like while loops.

local RUN_INTERVAL_MS   = 500
local TIMEOUT_S         =  10
local MAV_SEVERITY_INFO =   6

local first_method_count = 0
local second_method_start_ms = uint32_t(0)

function first_method()
    first_method_count = first_method_count + 1
    if first_method_count * RUN_INTERVAL_MS >= TIMEOUT_S * 1000 then
        gcs:send_text(MAV_SEVERITY_INFO, 'First method timed out')
        second_method_start_ms = millis()
        return second_method, RUN_INTERVAL_MS
    end
    return first_method, RUN_INTERVAL_MS
end

function second_method()
    if millis() - second_method_start_ms >= TIMEOUT_S * 1000 then
        gcs:send_text(MAV_SEVERITY_INFO, 'Second method timed out')
        first_method_count = 0
        return first_method, RUN_INTERVAL_MS
    end
    return second_method, RUN_INTERVAL_MS
end

return first_method, RUN_INTERVAL_MS

Additionally, Lua supports decrementing for loops, so your original code, while flawed, can be simplified with a loop that looks a bit like this one:

for x = 10, 1, -1 do
    if x == 10 then
        gcs:send_text(0, 'first iteration')
    end

    if x == 1 then
        gcs:send_text(0, 'last iteration')
    end
end
1 Like

Thank you - mind blown…

I think I understand the gist of your two method example. How would you use that to observe the state of some variable X ?
e.g. if X ==1 for 10 seconds then “do something” else keep watching.

Reset the timer or counter if x changes.