Parallel switch use?

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.