Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

Maestro Mini 12 control 3 servos with 3 buttons

Hello,
I am new to this and can not seem to figure out how to get the script to work for my purpose.
I got it partialy working with one servo and one button and it does what I want.
Now I want to add 2 extra servo’s and buttons.
But the second one does not work.
It seems dat the end of the script is missing something to make it work.
I searched other threads, the example scripts and the manual.
Below my script that I used and are tweaking.
Any help would really help.

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_a
  6 get_position 500 less_than
  return

sub button_b
  7 get_position 500 less_than
  return

sub button_c
  8 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_a
  wait_for_button_open_10ms_a
  wait_for_button_closed_10ms_a
  return

sub wait_for_button_press_b
  wait_for_button_open_10ms_b
  wait_for_button_closed_10ms_b
  return
 
# Wait for the button to be NOT pressed for at least 10 ms.
sub wait_for_button_open_10ms_a
  get_ms # put the current time on the stack
  begin
# reset the time on the stack if it is pressed
    button_a
    if
      drop get_ms
    else
      get_ms over minus 10 greater_than
      if drop return endif
    endif
  repeat
 
# Wait for the button to be NOT pressed for at least 10 ms.
sub wait_for_button_open_10ms_b
  get_ms # put the current time on the stack
  begin
# reset the time on the stack if it is pressed
    button_b
    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_a
  get_ms
  begin
# reset the time on the stack if it is not pressed
    button_a
    if
      get_ms over minus 10 greater_than
      if drop return endif
    else
      drop get_ms
    endif
repeat

# Wait for the button to be pressed for at least 10 ms.
sub wait_for_button_closed_10ms_b
  get_ms
  begin
# reset the time on the stack if it is not pressed
    button_b
    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_button_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
			6000 frame_1
  		4000 frame_1
		repeat

		begin
  		6000 frame_2
  		4000 frame_2
		repeat
 
sub frame_1
  wait_for_button_press_a
  1 servo
  return

sub frame_2
  wait_for_button_press_b
  2 servo
  return

Hello.

There could be a couple problems with the way your script is written depending on how you want the system to behave. The biggest problem (and the reason why the second button doesn’t work) is that there are two completely isolated ‘BEGIN/REPEAT’ loops. Once the script enters the first one, it will never reach the second one:

main_loop:

begin                           #Start of loop
    6000 frame_1	      
    4000 frame_1        
repeat		      #Returns to start of loop

begin		      #This BEGIN/REPEAT loop will never be reached
    6000 frame_2
    4000 frame_2
repeat

One way to fix this is to put them all in a single BEGIN/REPEAT loop:

begin
    6000 frame_1	      
    4000 frame_1        

    6000 frame_2
    4000 frame_2
repeat	

However, please note that your ‘wait_for_button_press_a’ and ‘wait_for_button_press_b’ subroutines are blocking code, so the script will be stuck waiting for those buttons when it enters them. This means that your script will require the user to push the buttons in alternating orders to continue. If that is not how you want the system to work, you can post more details about what you are trying to do and I would be glad to give you suggestions.

Brandon

Hello Brandon,
I tried the second portion of the script you provided and does not give me the correct behavior.
That creates behavior that the button_b can only be used if button_a is used two times.
I need every button to behave the same and independent from each other.
Every button must go to the servo first position on one touch and the servo second position on the second touch, and back again to first position on the touch after that.
I want to use it to open/close three doors.

Addional it would be nice to light up a led if the servo is second position.

I hope I explained it clearly :slight_smile:

You will need to change how your code works to get that kind of behavior. As I mentioned before the wait_for_button_press subroutines are blocking, so you will not be able to use them as-is to have any of the buttons work at all times.

One way around this is to use the method shown in the “Using multiple buttons or switches to control servos” example found in the “Example Scripts” section of the Maestro user’s guide. However, note that this example dose not do any debouncing for the buttons, so it might trigger multiple times when you press the button once. A simple (but not very elegant) way to solve this is to add a small delay before returning from your subroutine. Also, since you want the same button to do different things each time it is pressed, you will need to add some separate logic for that. One way to do it would be to have your subroutine check what position the servo is in before deciding what the new position should be. For example, if you want a servo on channel 0 to swap between 1000us and 2000us, it might look like this:

sub moveServo0
  0 get_position      #get the position of the servo

  6000 less_than if   #if it is less than 6000 (1500us)
    8000 0 servo        #set the position to 8000 (2000us)
  else                          #otherwise,
    4000 0 servo        #set the position to 4000 (1000us)
  endif

 500 delay            #small delay to prevent debouncing problems
return

If you have enough Maestro channels still available, you could use them to control LEDs. You would need a separate channel for each of your 3 LEDs to be controlled independently. Instructions for connecting LEDs can be found in the “LED” section of the “Attaching Servos and Peripherals” section of the user’s guide. Once the channels are configured as outputs and the LEDs are connected, you can add commands to toggle them inside the IF statement in the example subroutine above to have them indicate the servo position.

Brandon

Thank you Brandon.
Maybe it is easier if I use switches with a fixed position instead of push moment buttons.
Could that help?

You could use either a switch or a button. The way you would handle the button in your script is fairly similar, only instead of checking the servo position after the button is pressed, you could just check the switch position directly, so it takes out one step. For example, here is the previous code modified to work with a switch:

begin
  1 get_position      #get the position of the switch on channel 1

  512 less_than if     #if it is low (0V)
    8000 0 servo        #set the position to 8000 (2000us)
  else                          #otherwise,
    4000 0 servo        #set the position to 4000 (1000us)
  endif

 50 delay                  #small delay
repeat

Brandon