Pololu Maestro indepedant button press issue

Hi, i am having trouble independantly operating 2 buttons to 3 servos attached to a 6 pin maestro. 2 servos are assigned to button 1 and one other servo to button 2. i have two examples i have tried… shown below. my first example works but in most cases the servos dont activate on the first push of the button it requires 3-4 button pushes before the servo moves. the second example using wait_for_button_press, only one button works and ignores the other button completley. example 3 i have tried to merge the two but still no luck only as this time it onyl works as a sequence not by frame. my ideal goal is for button 1 to operate 2 servos together in sync frame by by frame(with each button press) not as a sequence… .and button 2 to operate the third servo indepedantly.
button 1 = channel 0
button 2 = channel 1
servo 1 = channel 2
servo 2 = channel 3
servo 3 = channel 4

example 1

# When the script is not doing anything else,
# this loop will listen for button presses.  When a button
# is pressed it runs the corresponding sequence.
begin
  button_a if sequence_a endif
    button_a if sequence_aa endif
  button_b if sequence_b endif
    button_a if sequence_bb endif
repeat

# These subroutines each return 1 if the corresponding
# button is pressed, and return 0 otherwise.
# Currently button_a is assigned to channel 0, 
# button_b is assigned to channel 1, and
# button_c is assigned to channel 2.
# These channels must be configured as Inputs in the
# Channel Settings tab.
sub button_a
  0 get_position 500 less_than
  return
 
sub button_b
  1 get_position 500 less_than
  return

# These subroutines each perform an arbitrary sequence
# of servo movements.  You should change these to fit
# your application.
sub sequence_a
  4000 2 servo 500 delay
  9000 3 servo 500 delay
  return
  
sub sequence_aa
  9000 2 servo 500 delay
  9000 3 servo 500 delay
  return
   
sub sequence_b
  4000 4 servo 500 delay
  return
 
sub sequence_bb
  9000 4 servo 500 delay
  return

Example 2

  goto main_loop    # Run the main loop when the script starts (see below).
 
# This subroutine returns 1 if the button is pressed, 0 otherwise.
# To convert the input value (0-1023) to a digital value (0 or 1) representing
# the state of the button, we make a comparison to an arbitrary threshold (500).
# This subroutine puts a logical value of 1 or a 0 on the stack, depending
# on whether the button is pressed or not.
sub button
  0 get_position 500 less_than
  return
 
# This subroutine uses the BUTTON subroutine above to wait for a button press,
# including a small delay to eliminate noise or bounces on the input.
sub wait_for_button_press
  wait_for_button_open_10ms
  wait_for_button_closed_10ms
  return
 
# Wait for the button to be NOT pressed for at least 10 ms.
sub wait_for_button_open_10ms
  get_ms # put the current time on the stack
  begin
    # reset the time on the stack if it is pressed
    button
    if
      drop get_ms
    else
      get_ms over minus 10 greater_than
      if drop return endif
    endif
  repeat
 
# Wait for the button to be pressed for at least 10 ms.
sub wait_for_button_closed_10ms
  get_ms
  begin
    # reset the time on the stack if it is not pressed
    button
    if
      get_ms over minus 10 greater_than
      if drop return endif
    else
      drop get_ms
    endif
  repeat
 
 
 sub button1
  1 get_position 500 less_than
  return
 
# This subroutine uses the BUTTON subroutine above to wait for a button press,
# including a small delay to eliminate noise or bounces on the input.
sub wait_for_button1_press
  wait_for_button1_open_10ms
  wait_for_button1_closed_10ms
  return
 
# Wait for the button to be NOT pressed for at least 10 ms.
sub wait_for_button1_open_10ms
  get_ms # put the current time on the stack
  begin
    # reset the time on the stack if it is pressed
    button
    if
      drop get_ms
    else
      get_ms over minus 10 greater_than
      if drop return endif
    endif
  repeat
 
# Wait for the button to be pressed for at least 10 ms.
sub wait_for_button1_closed_10ms
  get_ms
  begin
    # reset the time on the stack if it is not pressed
    button
    if
      get_ms over minus 10 greater_than
      if drop return endif
    else
      drop get_ms
    endif
  repeat
# An example of how to use wait_for_button1_press is shown below:
 
# Uses WAIT_FOR_BUTTON_PRESS to allow a user to step through
# a sequence of positions on servo 1.
main_loop:
begin
  4000  4000 frame 
  5000  5000 frame 
  6000  6000 frame 
  7000  7000 frame 
  8000  8000 frame 
repeat
 
sub frame
  wait_for_button_press
  2 servo
  3 servo
  return
  
begin
 4000 frame 
 5000 frame 
 6000 frame 
 7000 frame 
 8000 frame 
repeat
 
sub frame
  wait_for_button1_press
  4 servo
  return

example 3

# When the script is not doing anything else,
# this loop will listen for button presses.  When a button
# is pressed it runs the corresponding sequence.
begin
  button_a if sequence_a endif
    button_a if sequence_aa endif
  button_b if sequence_b endif
    button_a if sequence_bb endif
repeat
 
# These subroutines each return 1 if the corresponding
# button is pressed, and return 0 otherwise.
# Currently button_a is assigned to channel 0, 
# button_b is assigned to channel 1, and
# button_c is assigned to channel 2.
# These channels must be configured as Inputs in the
# Channel Settings tab.
sub button_a
  0 get_position 500 less_than
  return
  
  sub wait_for_button_press
  wait_for_button_open_10ms
  wait_for_button_closed_10ms
  return
 
# Wait for the button to be NOT pressed for at least 10 ms.
sub wait_for_button_open_10ms
  get_ms # put the current time on the stack
  begin
    # reset the time on the stack if it is pressed
    button
    if
      drop get_ms
    else
      get_ms over minus 10 greater_than
      if drop return endif
    endif
  repeat
 
# Wait for the button to be pressed for at least 10 ms.
sub wait_for_button_closed_10ms
  get_ms
  begin
    # reset the time on the stack if it is not pressed
    button
    if
      get_ms over minus 10 greater_than
      if drop return endif
    else
      drop get_ms
    endif
  repeat
 
sub button_b
  1 get_position 500 less_than
  return
 
 sub wait_for_button_b_press
  wait_for_button_b_open_10ms
  wait_for_button_b_closed_10ms
  return
 
# Wait for the button to be NOT pressed for at least 10 ms.
sub wait_for_button_b_open_10ms
  get_ms # put the current time on the stack
  begin
    # reset the time on the stack if it is pressed
    button
    if
      drop get_ms
    else
      get_ms over minus 10 greater_than
      if drop return endif
    endif
  repeat
 
# Wait for the button to be pressed for at least 10 ms.
sub wait_for_button_b_closed_10ms
  get_ms
  begin
    # reset the time on the stack if it is not pressed
    button
    if
      get_ms over minus 10 greater_than
      if drop return endif
    else
      drop get_ms
    endif
  repeat

 
# These subroutines each perform an arbitrary sequence
# of servo movements.  You should change these to fit
# your application.
sub sequence_a
  4000 frame
  5000 frame
  6000 frame
  7000 frame
  8000 frame
repeat
 
sub frame
  wait_for_button_press
  2 servo
  3 servo
  return
  
sub sequence_aa
  4000 frame
  5000 frame
  6000 frame
  7000 frame
  8000 frame
repeat
 
sub frame
  wait_for_button_press
  2 servo
  3 servo
  return
   
sub sequence_b
  4000 frame
  5000 frame
  6000 frame
  7000 frame
  8000 frame
repeat
 
sub frame
  wait_for_button_press
  4 servo
  
  return
 
sub sequence_bb
  4000 frame
  5000 frame
  6000 frame
  7000 frame
  8000 frame
repeat
 
sub frame
  wait_for_button_press
  4 servo
  return

Hello.

Thank you for posting the scripts you have tried so far and clear descriptions of what they do.

Since your first script is the simplest and seems to be working close to how you want, I recommend starting there. I noticed two things that are potentially causing the problem. The first is that all your sequences have delays in them. This might not be a problem depending on how responsive you want the system, but keep in mind that these delays are blocking, so while the Maestro is commanded to delay, it will not be running any other code in your script. For example, if you press the button and sequence_a runs, it will not respond to another button press for at least 1 second (since there are two half second delays in that sequence).

The second thing I noticed was that your script is using the button subroutines in multiple different places in the loop with different results. The way your code is right now, when no button is being pressed, the script will continuously run through the button_a and button_b subroutines to see if either of them are pressed. Because this same subroutine is being used in multiple IF statements throughout the loop, the sequence that gets called when a button is pressed will be whichever one happens to be in the IF statement currently being processed. This means that if you press button_a and it runs sequence_a, there is a good chance that the next time you press button_a, it will run sequence_a again, instead of sequence_aa.

If you want pressing the same button multiple times to have different outcomes (e.g. switching a servo from position one to position two on the first press, and back to position one on the second press) you will need to have additional logic. One way to do this is using a state variable. You can find an example and explanation for using a state variable in my posts in this thread. Another option is to use the current position of the servo to decide which sequence to call. For example:

button_a if    		#if button_a is pressed
  2 get_position   	#check the position of servo 2
  9000 equals if   	#if it equals 9000 
    sequence_a		#run sequence_a
  else			#if it does not equal 9000
    sequence_aa		#run sequence_aa
  endif
endif

By the way, it looks like you might have a typo in your first script. It looks like you probably want button_b to switch between calling sequence_b and sequence_bb, but your last if statement uses button_a again.

Brandon

Hello Brandon, thank you very much for your response. sorry about the typo at the end of script one, yes you are correct. i shall test out what you have suggested by adding the logic and will get back to you, thank you very much for your input.

Kay.

implemented perfectly… Thank you Brandon

1 Like