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

Pololu Forum

Auto start sequence but retaining existing script!


#1

Hi,

I have a script that moves servos once a button is pressed.
This all works really well.

I made a sequence for a separate servo on a separate channel but when I add this to the script it doesnt auto play.

Is this possible? I’ve seen people starting the sequence with a button but I would like this to auto play.

Thanks in advance.

begin

button_a if 1000 				#button_a = mouth
else 6000
endif
sequence_a

button_b if			            #if button_b is pressed

8000 8000 sequence_b	        	#move servos in one direction

else button_c if			   	 #if button_b is not pressed and button_c is

4000 4000 sequence_b  	    		#move servos in the other direction

 else				        	#if neither button is pressed

 6000 6000 sequence_b  			#move servos to center

endif

endif


repeat

sub button_a
  0 get_position 1 less_than
  return
 
sub button_b
  1 get_position 1 less_than
  return
 
sub button_c
  2 get_position 1 less_than
  return
 
sub sequence_a
 6 servo 10 delay
  return
   
sub sequence_b
  7 servo
  8 servo
  10 delay
return

### Sequence subroutines: ###

# BLINK
sub BLINK
  300 0 0 0 0 0 0 
  6615 0 0 frame_3..11 # Frame 0
  300 3392 frame_9 # Frame 1
  2000 6525 frame_9 # Frame 2
  400 3392 frame_9 # Frame 3
  6000 6466 frame_9 # Frame 4
  300 3392 frame_9 # Frame 5
  8000 6436 frame_9 # Frame 6
  300 3392 frame_9 # Frame 7
  200 6496 frame_9 # Frame 8
  200 3392 frame_9 # Frame 9
  200 delay # Frame 11
  200 6525 frame_9 # Frame 10
  6000 6555 frame_9 # Frame 12
  300 3392 frame_9 # Frame 13
  10000 6496 frame_9 # Frame 14
  300 3392 frame_9 # Frame 15
  20000 6525 frame_9 # Frame 16
  300 3392 frame_9 # Frame 17
  4000 6436 frame_9 # Frame 18
  return

sub frame_3..11
  11 servo
  10 servo
  9 servo
  8 servo
  7 servo
  6 servo
  5 servo
  4 servo
  3 servo
  delay
  return

sub frame_9
  9 servo
  delay
  return

#2

Hello.

The way your current script is set up, it looks like it will run either your sequence_a or sequence_b subroutine based on which buttons are pressed, but it will never execute your BLINK, frame_3..11, or frame_9 subroutines since your main BEGIN/REPEAT loop never calls them.

From your description, it sounds like you might be expecting two scripts to be running simultaneously. Please note that there is no way to do that; only one script can be ran at a time, so you would need to merge both of your scripts into one integrated script.

Brandon


#3

Hi Brandon,

Thanks for the reply.

What would be the easiest way to merge both of the scripts into one please?

Cheers,

Jon


#4

You will need to manually merge them.

If you try merging your scripts and have problems, can you describe how you want the two scripts to work together? If you can explain the kind of behavior are you trying to get, I might have some suggestions.

Brandon


#5

Hi Brandon,

Thanks for your help again.
I would like 3 servos to be operated by a button, which works perfectly thanks to your previous help. This is for operating eyes and a mouth on a puppet!

I would then like one servo to have “random” movement which would be the eyelids opening and closing at timed points without the operator having to use a button. Thats why I thought the sub blink routine would work. I didnt realise I couldnt put them both together :slight_smile:

Any help would be REALLY gratefully received.

Thanks,

Jon


#6

The Maestro does not support interrupts on its inputs, so in order to detect a button press, the Maestro must be actively polling the button channels. It will be tricky to monitor your buttons while the script is running through the sequence for the eyelid movements. Since the DELAY command is blocking, you would probably need to avoid using it. For example, instead of 5000 delay to wait 5 seconds, you could enter a while loop that uses GET_MS to measure how long it has been in the loop and break out after 5 seconds. Then, inside the loop, you can be checking for your button presses, which would interrupt the eyelid sequence if pressed.

Here is an example script that you might find helpful. It uses a nb_delay subroutine I wrote that can be used to do other things (like monitoring buttons) during a delay. It is set up to work like the normal delay command, so it takes 1 argument and delays for the specified time in microseconds. Unfortunately, since it uses the peek command, it will only work with Mini Maestro controllers (and not the Micro Maestro). If you have a Micro Maestro, let me know and I might be able to rework it so it can work with a Micro Maestro.

begin			#main sequence, just moving 1 servo back and forth
  4000 0 servo
    5000 nb_delay	#non-blocking delay subroutine (5000 = 5 seconds)
  8000 0 servo
    5000 nb_delay
repeat

sub nb_delay
  get_ms  		#save the time you entered the while loop
    begin dup get_ms swap minus 0 peek less_than   	#compare that to current time
      while		#this while loop is where you would do your button processing
        button_a if sequence_a endif 	#when button_a is pressed, it will run sequence_a, then return back to this spot
      repeat
  drop drop #empty the values on the stack before returning
return

sub button_a
1 get_position 500 less_than 
return

sub sequence_a	#simple example sequence - this sequence is blocking since it uses the normal delay command
  5000 0 servo
  500 delay
  7000 0 servo
  500 delay
return

Brandon


Servo Sequence triggert by Audio?
#7

Hi Brandon,

Thanks so much for the reply earlier this week, it has helped a lot but I’ve tried everything to try and get my other buttons working.

I have button 0 - which controls the mouth
button 1 makes both eyes look to the right
button 2 makes both eyes look to the left
and when theyre not pressed they return to the centre.

This was working perfectly so thanks for all your previous help.

Now I can get button 0 to operate the mouth and have the blink sequence at the same time but I cant get the other two buttons to work! my stupidity I know!! any help would be really graefully received thanks.

begin #main sequence, just moving eyelids back and forth for a blink

4000 9 servo #servo 9 = Blink
300 nb_delay #non-blocking delay subroutine
8000 9 servo
300 nb_delay
10000 nb_delay
4000 9 servo #servo 9 = Blink
300 nb_delay #non-blocking delay subroutine
8000 9 servo
300 nb_delay
20000 nb_delay

repeat

sub nb_delay
get_ms #save the time you entered the while loop
begin dup get_ms swap minus 0 peek less_than #compare that to current time
while #this while loop is where you would do your button processing
button_a if sequence_a endif #when button_a is pressed, it will run sequence_a, then return back to this spot
repeat
drop drop #empty the values on the stack before returning
return

button_b if #if button_b is pressed

8000 8000 sequence_b #move servos in one direction

else button_c if #if button_b is not pressed and button_c is

4000 4000 sequence_b #move servos in the other direction

else #if neither button is pressed

6000 6000 sequence_b #move servos to center

endif

endif

sub button_a
0 get_position 500 less_than #mouth button
return

sub button_b #eye right button
1 get_position 500 less_than
return

sub button_c #eye left button
2 get_position 500 less_than
return

sub sequence_a #sequence to move mouth
5000 6 servo
200 delay
7000 6 servo
200 delay

return

sub sequence_b #sequence to move both eyes
5000 7 servo
5000 8 servo
300 delay

return


#8

It looks like you have your button_a check in the right place (inside the while loop of the nb_delay subroutine), but your button_b and button_c checks were added after the return command, so the script will never reach them.

You should be able to get it to work by putting your button_b and button_c checks just after your button_a check (and before the repeat command of the while loop). I added some comments to your nb_delay subroutine below to indicate where:

sub nb_delay
  get_ms
   begin dup get_ms swap minus 0 peek less_than
      while
        button_a if sequence_a endif #when button_a is pressed, it will run sequence_a, then return back to this spot
        # place additional button processing code here
        repeat
   drop drop #empty the values on the stack before returning
return

Brandon


#9

Thanks for the help Brandon,

but putting the code to make the two servos move together freaks everything else out!!The “blink” or sequence to make the blink (servo 9) just repeats and doesnt get to the rest of the script and then crashes!
I’m obviously doing something stupid :slight_smile:
Please help though :slight_smile:

begin #main sequence, just moving eyelids back and forth for a blink

4000 9 servo #servo 9 = Blink
300 nb_delay #non-blocking delay subroutine
8000 9 servo
300 nb_delay
10000 nb_delay
4000 9 servo #servo 9 = Blink
300 nb_delay #non-blocking delay subroutine
8000 9 servo
300 nb_delay
20000 nb_delay

repeat

sub nb_delay

get_ms #save the time you entered the while loop

begin dup get_ms swap minus 0 peek less_than #compare that to current time

while #this while loop is where you would do your button processing

button_a if sequence_a endif #when button_a is pressed, it will run sequence_a, then return back to this spot

button_b if #if button_b is pressed

8000 8000 sequence_b #move servos in one direction

else button_c if #if button_b is not pressed and button_c is

4000 4000 sequence_b #move servos in the other direction

else #if neither button is pressed

6000 6000 sequence_b #move servos to center

endif

endif

repeat
drop drop

return

sub button_a
0 get_position 500 less_than #mouth button
return

sub button_b #eye right button
1 get_position 500 less_than
return

sub button_c #eye left button
2 get_position 500 less_than
return

sub sequence_a #sequence to move mouth
5000 6 servo
200 delay
7000 6 servo
200 delay

return

sub sequence_b #sequence to move both eyes
5000 7 servo
5000 8 servo
300 delay

return


#10

There’s a couple problems with the way you have your sequence_b subroutine that I didn’t notice before. It looks like you are putting 2 values on the stack before calling the sequence (e.g. 8000 8000 sequence_b). From your comments in the code, I suspect those are the positions you want the servos to go to, but the subroutine does not use those values (instead, it is adding its own values to the stack and using those). This means that the servos probably aren’t going to the position you want them to, and the extra values on the stack are probably interfering with the nb_delay. It will eventually cause a stack overflow error, too. Since you are supplying values when calling the subroutine, you should be able to remove the values specified in the sequence_b subroutine.

Also, sequence_b is using a blocking delay for 300ms; since it is being called every time the program cycles (even when no buttons are pressed), this is going to cause your program to only check the buttons once every 300ms. I am not sure the purpose of this delay, but I suspect you do not need it, and your script will be much more responsive without it.

Brandon


#11

Thanks Brandon,

Totally confused now :smiley:
I removed the delay, and removed the values from the sequence_b subroutine and now nothing works!!

Help!!
I’m going crazy :smiley:
I’m going to test another maestro incase I’ve damaged this one somehow?

Please help my stupidity!

Jon


#12

Sorted!!
Thanks for all your help, I just forgot to tick the servos and inputs on thechannel settings area!!!

I’m tired :smiley: :smile:

Thanks again,

Jon


#13

Wait!!

If I want one of the servos to move anti clockwise is there a quick way to do that?

Thanks again,

Jon


#14

I am glad it is working for you now!

The Maestro does not have some kind of invert direction feature like that. If you want one of the servos to turn the other direction, you would need to change the set target value you are using (e.g. instead of 5000 7 servo, you can send 7000 7 servo).

Your project sounds pretty fun; if you are willing to share more details, we would love to hear more about it. I am sure other members here would be interested as well.

Brandon


#15

Hi Brandon,
Id love to share the project when its finished, hopefully tomorrow as it needs to be mounted into the puppet and sent to the client on Friday!!! AHHH!!!

Anyway, last problem , I hope.
When I run the maestro off the battery everything works great :)…but… )

The MOUTH servo defaults to a different starting position everytime the power is reset.
I checked the control centre and noticed everytime the tick box next to the servo unchecks!
Once checked it all works fine, I make a change go back and check it and its unchecked itself again!!

Is there something I can do to stop this happening please and keep it in the enabled state please.

Thanks,

Jon


#16

By default, the Maestro does not have any special default starting position for any of the servo channels (they will all be disabled). The channel is automatically enabled when you send it a set target command. Since your script does not send that particular servo channel a set target command until the button is pressed, it will be disabled until then.

You can change the startup behavior for each channel in the “Channel Settings” tab of the Maestro Control Center. So, if you want it to go to a particular position as soon as the system is powered up, you can change the “On startup or error” setting for that channel to “Go to”, and specify the position you want it to start at.

Brandon


#17

Hi Brandon,
The script has worked really well thanks just due to your help.

One servo motor did burn out though due to too much pressure against an object.

I have found an area in the channel settings where I can set the min and max for the servo which I have now done, but…

How does this work with the script?
I thought I added the position of the servo in the script?

sub sequence_a #sequence to move mouth
5000 6 servo
200 delay
7000 6 servo
200 delay

Is there something I’m missing :blush:

Thanks again,

Jon


#18

The “Min” and “Max” settings in the Channel Settings tab will limit the minimum and maximum pulse width signal the Maestro will output on each channel. For example, if you lowered the Max setting for channel 0 to 1750 microseconds, commanding that channel to output anything higher than that will result in 1750 microseconds. Note that this value corresponds to a set target position of 7000 in a script, since it is in units of quarter microseconds. For example, if you have the max set to 1750 for channel 0 and use a 8000 0 servo command, the position sent to the servo will be limited to 1750 microseconds (7000 quarter microseconds)

If you are having problems with servos burning out, they are likely under too much load. Depending on your setup, you might be able to reduce the load on the servos by adjusting the target position you are sending them to in your script. For example, if your servo is stalling out before it reaches it’s target, you should reduce the target so this does not happen. It could also be the case that the servos you are using are underpowered for your application; in that case you would probably need to upgrade your servos.

Brandon