Servo control on BSIIsx?
Vern Graner
Posts: 337
Quick question on the BSIIsx:
I am trying to position servos and I'm using the information and sample code shown in the Basic Stamp Manual (v1.9 pg 86):
SERVO:
PULSOUT 0,150
PAUSE 20
GOTO SERVO
UNfortunately, this does not place the servo at "center' but rather "bangs" the servo against the stop. I have tried this with different servos and they react the same. Do I need to use different values for the BSIsx (like I do for the serial baud rate)?
Thanx
Vern
Post Edited (Vern) : 10/20/2004 9:50:47 PM GMT
I am trying to position servos and I'm using the information and sample code shown in the Basic Stamp Manual (v1.9 pg 86):
SERVO:
PULSOUT 0,150
PAUSE 20
GOTO SERVO
UNfortunately, this does not place the servo at "center' but rather "bangs" the servo against the stop. I have tried this with different servos and they react the same. Do I need to use different values for the BSIsx (like I do for the serial baud rate)?
Thanx
Vern
Post Edited (Vern) : 10/20/2004 9:50:47 PM GMT
Comments
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax
Dallas Office
1us = 1000/.8 = 1250 "bottom" or "0-degrees"
2us = 2000/.8 = 2500 "top" or "180 degrees"
I then wrote this snippet of code to test the formula by seeking the servo through it's entire range:
Unfortunately, it only seeks the servo through about 60 degrees. Also, it is rather slow moving. I tried speeding it up by using "step 2" or "step 5" on the FOR statement, that seemed to work.. Don't know if thats the right approach.
Thats not the main problem though. I still don't understand why it is only seeking through such a small range when it would appear I am setting values that should generate a continuous sweep 180 degrees from 1us to 2us..?
Also, if I were to include multiple servos in this code, for example:
Would I have to recalculate the .8 value or change the pause value? I'm also a little unclear on the "pause" time and how I should determine it's value...? Arg. I wish I could just budget for a Serial Servo Controller, but I have to make this on a shoestring budget and If I can get sucessful control of the servos directly, it would cut the project cost in half...
Vern
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax
Dallas Office
1. You *must* leave at least 20 mSec between pulses to the Servo. It can't react faster than that.
2. You *should* repeat a pulse to the servo, and give it some time to move.
I'm guessing that since you did all this in a fast loop, that the servo never had time to move all the way to one side, before your code started commanding it to move to the other side.
Jon's solution has two pieces to it -- he repeats each command, and he uses the 20 mSec pause between commands.
By repeating each position command 50 times, with a 20 mSec pause between each PULSOUT, he gives the servo time to move. (A good lab would be to command the servo all the way one way, time its movement, then command it all the other way, and time its movement. This will tell you the fastest rate you can get out of the servo, and how many times you should repeat the command)
However, the speed of seek is not the *primary* problem, in fact, if anything I need the seek to be slower or adjustable as the end result is servos controlling a "puppet" so the fast movements do not appear "natural". What I am looking to make is a series of "positions" that the servos could seek to that I can step through over and over.
Where I am confused is in the timing of the pause statements and the reason my BSIIsx seems to not be able to seek the servo through the entire 180 degree range. Allan theorized that the PULSEOUT command was not being given enough time to seek the servo to it's end position. So, using Jon's example of "seek to zero, then 1/2 way then full rotate: above, I found the servo still only seeks through about a 60 degree arc. In fact, to get the full 180 degree arc, I had to use this code:
Using the above I get a full 180 degrees, in three distinct steps. I tried this with two different servos, a Futaba S3004 and Futaba FP-S148, they both required these values to do a full 180 degree seek. Is my BSIIsx "broken" in it's timing?
Also, is there a way to position and hold more than one servo, like this:
Should the "PAUSE" value be altered based on the number of PULSOUT commands? And if this won't work, what should I use for values or is there a "better" way to code this? TIA!
Vern
Post Edited (Vern) : 10/21/2004 5:15:50 PM GMT
You can leave the PAUSE value at 20 -- any value from 15 to 35 is going to be okay; 20 is the standard.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax
Dallas Office
GOF:
INDEX = (DIRA & %0011)
BRANCH, INDEX [noparse][[/noparse]F,F,GOSB,GOPT,ect]
F:
PULSOUT 15, 1500
GOTO GOF
Yes, your last example will work fine. This is why people use Servo's with the BS2sx. The Servo refresh rate is loose enough that anything from 20 mSec to 50 mSec will work -- so you can 'refresh' 4 or 8 servos, then do a single 'Pause 20' before refreshing them again. The servo's will seem to move at the same time (*maybe* theres a few 100 uSecs delay between the actual movements).
I havn't used the BS2sx myself yet. Once you've found the right numbers, however, I think repeatability between different BS2sx should be excellent. It's easy to move servo's slower by stepping to positions close together -- it may still need a few repeats of each command to give the mechanical components time to move.
Again, any input would be appreciated...
http://www.spiderspreyground.com/howto/dk-toepincher/
The servos control head pan/tilt, eye motion (left/right) and the position of one arm (the other one is static). I sure would love to get a "smoother" motion from this. I have a number of other people that are intersted in replicating this design so getting it down to a stamp, some code and a handful of servos is the optimal goal... Any help/comment would be greatly appreciated.
Vern
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Post Edited (Vern) : 9/21/2006 4:13:41 PM GMT
Your servo comparator may be missing some of your pulses, which might lead to jerky action. Never done this myself, so I'm blue-sky theorizing for that.
OH! I just saw an optimization. You are pausing after EVERY servo update 10 mSec. You only need to have ONE 20 mSec pause after updating ALL FOUR servo's.
IF Servo=4 THEN ' Existing
Servo = 0 ' Existing
PAUSE 20 ' New
ENDIF
and remove the 'PAUSE 10' lower in the code. This way, every time you have updated all 4 servo's, your code will wait 20 mSec for your servo's to move, before updating them to the new positions.
Thanks for the code optimization! That did really help (four pulses, one pause). I guess I still need to get a "feel" for how much time it takes to execute the code. I had imagined the execution of the code would take some time and that I would have to shorten the pause in response to those delays... Guess the BSIIsx is faster than I thought! [noparse]:)[/noparse]
The good news is that I can sucessfully control four servos, running through a series of "Random" movements in a pretty smooth manner to make a mostly realistic looking puppet! I ended up adding some code to accelerate and decelerate the motion and also placed some motion limits so the servos would not move beyond certain ranges (i.e. only move the arm between minimum and maxmimum point). I have provided the finished code here for those who might be trying to do the same:
Thanks again for everyone's help, and if anyone has any other comments, or questions, please let me know! This has been a very enlightening experience and shows me the stamp is capable of operating multiple servos w/o having to resort to a PWM pal or Serial Servo Controller! [noparse]:)[/noparse]
Vern
Post Edited (Vern) : 10/26/2004 3:11:08 PM GMT
I really like how you've made use of the arrays, and the subroutines to produce relatively simple code that does quite complicated things. Very nicely structured code *and* data.
Going through your code I would suggest this based on my game programming and refresh rates of video output.
When programming for smooth output of 3D or 2D video, one packs as much processing of the numbers between the vertical scan
as the screen gets painted from the top left corner all the way to the bottom right corner it has to move the gun back to the top right corner.
During that time your program crunches numbers and puts the new screen update in a seperate buffer of memory.
Your code can do the same thing. First calculate the amount of time your crunching of numbers takes to do all 4 servo calculations
if its under 20 ms then subtract that number from 20 to get your pause time.
Send all 4 servos the new positions at one time
crunch the next set of numbers
repeat
I dont know because I just started working with pbasic, if there is a timer function you can use to get an exact execution time for each time the code runs thru so you can calculate the pause time for each set of servo commands sent but if you do all 4 calculations every time it should be pretty close.
If your code takes longer than 20 ms you could do 2 servos at a time but remember the code will take different times to execute.
I am thinking the jerky part is the physics of the model you are moving as the force of each servo enguages one after the other creating a worse condition depending on the actual direction of the movement. for example one arm moves forward servo1 and them servo 2 moves the other arm backwards, the momentum of the first arm going forward effects the balance of the model and when the second servo enguages your model may already have some energy propelling it backwards if the forward movement of the first arm caused the model to spring or lean foreward like a pendulum.
Thanks for the feedback. That is exactly what I was looking for. To be honest, this code "grew" ( kinda like "mold"! ) as I hammered it into submission! I should probably re-code it now that I have it running. In response to your suggestion, I actually had theorized about the execution time of the "number crunch" portion of the code.. In fact, in my first pass I placed the pause command with 10us taking a "guess" that the code might take somewhere around 10us to complete....I really don't know of a way to evaluate the amount of time it takes. Someone mentioned a logic analyser to discover execution time, but I don't have one so..
Anywya, I appreciate the feedback as I do hope tooptimize the code at some point so that I can use it to "interpret" strings of coordinates that are "recorded". Ideal case would be a joystick type input that I could run through and record motions into an array, then run the array back... This would make it simple to animate a servo-controlled prop.. That'll have to wait since I'm out of resources for the moment... my haunted house is this friday so I'm out of time, and the code I wrote eats about all the RAM in the BSIIsx (those "WORD" sized arrays to hold the servo positions eat the space!) Maybe I can figure out how to use less ram later.
Vern
You may find the following link helpful in determining the exectution time of various Stamp instructions:
http://www.emesystems.com/BS2speed.htm
Thanks go to Dr. Tracy Allen, for all his hard work in determining these instruction speeds for the BS-2, and BS-2sx platforms.
Regards,
Bruce Bates
A "Pause 20" pauses for 20 mSec (milli-seconds) not 20 uSec (micro-seconds). 20 mSec is a *much* longer time in BS2 land.
A BS2sx does one 'primitive' PBasic instruction in around 60 uSec ("HIGH 1"). so it can do about 18 instructions per milli-second, or 357 instructions in 20 mSec. The time for instructions like "PAUSE xx", SEROUT, etc. are driven more by the data than the time to actually execute the instruction.
Servo's need a 20 mSec to 50 mSec delay before repeating the pulse, so the "Pause 20" is correct.
Then average the time (using a stopwatch to measure the time it takes to execute the loop)
As each pulse is received (every 20milliseconds or so) the servo will move a little closer to it's position.
So the number of pulses required to actually reach the position depends on where it started.
So you can see how confused the servo gets if you are sending different pulse widths all the time.
You should send the pulse width for some time to reach the desired position.
Bean.