Hi there !
I want to use 6 buttons to trigger 6 servo sequences, it should be possible to trigger the sequence parallel. How can i write the script for that ? Has anybody done a project like this ?
Greetings =)
Hi there !
I want to use 6 buttons to trigger 6 servo sequences, it should be possible to trigger the sequence parallel. How can i write the script for that ? Has anybody done a project like this ?
Greetings =)
Hello.
Programming the Maestro to do multiple sequences concurrently is tricky because you have to avoid using the delay
command, and use variables on the stack to keep track of the progress of each sequence.
Below is some example code I made showing how you could do that. For each sequence, it stores a boolean variable (0 or 1) to record whether the sequence is active or not, and it stores the time when the sequence started executing. Right now it only supports 3 buttons and 3 sequences, but you could easily add more.
The syntax for writing frames in a sequence is:
200 nbframe if
7000 4 servo
return
endif
The number before nbframe
is the duration of the frame, in milliseconds. The code between if
and return
is the code to run while this frame is active; that code will be executed frequently while that frame is running. The code for the first frame in a sequence will be executed frequently even while the frame is not active, so you can use the first frame to set default positions for your servos.
The get_time
function, which returns how long a given sequence has been running, will wrap around after 32767 milliseconds, so you cannot make any sequences that are longer than that. If you rewrite the script, you could probably make the sequences be much longer by keeping track of what frame is active and the start time of that frame, instead of only keeping track of what time the sequence started.
Another limitation of this setup is that you cannot easily make reusable subroutines that contain frames of a sequence, because you need to return from the top-level sequence subroutine after executing the code for a frame. I think that could also be fixed with a rewrite.
This script uses peek
and poke
so you will need a Mini Maestro (not the 6-channel Micro Maestro).
Please let me know if you have any further questions.
–David
# This script shows how to have 3 buttons that control 3
# servo sequences that can run in parallel.
# Initialize variables at the bottom of the stack to
# keep track of the state of each sequence.
0 # Sequence 0 active: 0 if inactive, 1 if active
0 # Sequence 0 start time: the time from get_ms that it started
0 # Sequence 1 active
0 # Sequence 1 start time
0 # Sequence 2 active
0 # Sequence 2 start time
begin
0 0 start_sequence_if_button_pressed
1 1 start_sequence_if_button_pressed
2 2 start_sequence_if_button_pressed
sequence_0
sequence_1
sequence_2
repeat
# Starts/activates the specified sequence.
# Top argument: sequence number
sub start_sequence
2 times 1 swap poke
return
# Stops/deactivates the specified sequence.
# Top argument: Sequence number.
sub stop_sequence
2 times 0 swap poke
return
# Top argument: sequence number
# Returns: the value of the 'active' variable
sub get_active
2 times peek
return
# Sets the start time for the specified sequence to the current time.
# Top argument: sequence number
sub set_start_time
2 times 1 plus get_ms swap poke
return
# Top argument: sequence number
# Returns: The value of the 'start_time' variable
sub get_start_time
2 times 1 plus peek
return
# Top argument: sequence number
# Returns: time in milliseconds that the sequence has been
# running if active, 0 otherwise.
sub get_time
dup get_active
if
get_start_time get_ms swap minus
else
drop 0
endif
return
# Checks to see if the specified button is pressed and starts the specified
# sequence if so. This subroutine will restart the sequence if it is
# already running, but it could be modified to not do that.
#
# Top argument: the channel with the button
# Next argument: the number of the sequence
sub start_sequence_if_button_pressed
get_position 500 greater_than
if drop return endif
dup start_sequence
set_start_time
return
# Helper function for making non-blocking frames.
#
# Top argument: duration of this frame in milliseconds
# Bottom argument: time since this frame started
# (Both arguments get removed from the stack.)
#
# If this frame is still active, this routine pushes 1 to the stack.
# Otherwise, this routine places the amount of time since this frame
# ended on the stack (which can be used by the next call to
# nbframe) and also pushes 0 to the stack.
sub nbframe
dup 2 pick greater_than
if
# Frame is active
drop drop 1
else
minus 0
endif
return
# Sequence 0: A simple sequence that moves servo 3 to a few different locations.
sub sequence_0
0 get_time
100 nbframe if
4000 3 servo
return
endif
1000 nbframe if
6000 3 servo
return
endif
300 nbframe if
4500 3 servo
return
endif
300 nbframe if
5500 3 servo
return
endif
drop 0 stop_sequence
return
# Sequence 1: Wiggle servo 4 back and forth for 2 seconds.
sub sequence_1
1 get_time
200 nbframe if
5000 4 servo
return
endif
200 nbframe if
7000 4 servo
return
endif
200 nbframe if
5000 4 servo
return
endif
200 nbframe if
7000 4 servo
return
endif
200 nbframe if
5000 4 servo
return
endif
200 nbframe if
7000 4 servo
return
endif
200 nbframe if
5000 4 servo
return
endif
200 nbframe if
7000 4 servo
return
endif
200 nbframe if
5000 4 servo
return
endif
200 nbframe if
7000 4 servo
return
endif
drop 1 stop_sequence
return
# Sequence 2: A longer sequence that lasts 10 seconds.
# (Sequences longer than 32 seconds are not possible.)
sub sequence_2
2 get_time
100 nbframe if
4000 5 servo
return
endif
10000 nbframe if
8000 5 servo
return
endif
drop 2 stop_sequence
return
Hello David.
Thank you, that is perfect. Now i can change the sequences as i need them.