Hello,
My name is Ruslan and this is my first post on this forum. I’m trying to implement a script using the Micro Maestro Board. I need to implement a timeout in my script, like this:
goto start
sub TIMEOUT
dup
get_ms
minus
15000 greater_than # 15 sec
if
drop
2 1 greater_than #puts "true" on stack
else
1 2 greater_than #puts "false" on stack
endif
return
#program starts here
start:
get_ms
begin
GENERATE_PWM
TIMEOUT
if
goto some_place
endif
repeat
The code will generate a PWM pulse for a 15 seconds and then jumps to another place.
Is this the right way to implement the script? Do I need check if a get_ms timer overflows?
In the Maestro scripting language, “true” and “false” just mean 1 and 0, so you can simplify your TIMEOUT subroutine to the following:
sub TIMEOUT
dup
get_ms
minus
15000 greater_than # 15 sec
if
drop
1
else
0
endif
return
It make me nervous to see a subroutine that has a different effect on the stack level depending on what code path it travels down. That’s what you get because you have a “drop” in one code path but no “drop” in the other. That kind of subroutine is just asking for a stack overflow or underflow error. In my opinion, you should simplify the function to just be:
sub TIMEOUT
dup
get_ms
minus
15000 greater_than # 15 sec
return
You still need to drop that timer value somewhere, so you could add a “drop” command right before “goto some_place”.
In general you do have to worry about get_ms timer overflowing, but if you use the function above it will handle the overflow correctly. Here’s an example of how that works: Suppose the timer value on the stack is 30000, but get_ms returns -30000. Then the “minus” operation will be -30000 - (30000), so that operation will overflow and yield a result of -30000 - (30000) + 2^16 = 5536, which is what you would want.
Thank you David for a quick reply. Thank you for the suggestion about better programming practice, I will keep them in mind and rewrite the function. During the day I tried different ways of implementation and I run into this problem. I wrote a small script to blink the red LED (3 sec ON, 3 sec OFF) using a timeout function I posted later. This is the script (I will rewrite the script tomorrow as you suggested):
goto start
sub TIMEOUT
dup
get_ms
minus
3000 greater_than
if
drop
2 1 greater_than #true
else
1 2 greater_than #false
endif
return
#program starts here
start:
get_ms
begin
TIMEOUT
if
LED_ON
goto timer
endif
repeat
timer:
get_ms
begin
TIMEOUT
if
LED_OFF
goto start
endif
repeat
Time-out is the same routine, but now the delay is 3sec. When the code runs, surprise, the LED blinks every 30sec (aprox) - 30 sec. ON, 30 sec. OFF. I’ve reviewed the code again and again, I was banding my head against the wall without understand what’s going on? Later, I’ve modificate the timeout routine this way:
sub TIMEOUT
dup
get_ms
minus
negate
3000 greater_than
if
drop
2 1 greater_than #true
else
1 2 greater_than #false
endif
return
AND IT WORKS! And works good. I suspect why, but I’m not sure. I think the right way was the original version, I don’t understand why the old version does not work?
Can you help me please? Someone may think “OK, it works”, but I really need to understand what’s going on.
You needed to add that negate command because you are trying to compute elapsedTime = (now - startTime) and the minus command computes X - Y where Y is the value on top of the stack and X is just below it. If you have trouble understanding this, I recommend carefully reading the documentation of the mathematical script commands in the Maestro user’s guide and also using the “Step Script” button to step through your script and see what happens at every step.
So you will probably need to add a negate command in the subroutine I gave you above, or add a swap command just before minus.