Execution times
Spiral_72
Posts: 791
I'm working on a PING mounted servo and the servo is running pretty choppy.
The inside loop reads the PING and updates the servo:
to fire the PING I send a 0.000004ms pulse (4us)
PING burst is 0.2ms
the PING returns with a maximum 18.5ms echo time
Delay before next measurement ( I assume is pin hold time ) 0.2ms
Send one byte at 9600 baud ~1ms
update the servo position: ~2ms
so if I total all that up it's 21.9ms worst case. Why is the servo running so choppy?? What am I missing? Are any of my times wrong?
The inside loop reads the PING and updates the servo:
to fire the PING I send a 0.000004ms pulse (4us)
PING burst is 0.2ms
the PING returns with a maximum 18.5ms echo time
Delay before next measurement ( I assume is pin hold time ) 0.2ms
Send one byte at 9600 baud ~1ms
update the servo position: ~2ms
so if I total all that up it's 21.9ms worst case. Why is the servo running so choppy?? What am I missing? Are any of my times wrong?
Comments
I also think it may be optimistic to assume that serout only consumes 1mS to do the entire job of sending one byte. The actual transmit time should be around 1mS, but the total time includes formatting time if you are using any formatting and probably some housekeeping.
BTW, I finally ordered a BS2 OEM and a PING from Digi-Key today so I can retire that old BASIC ATOM.
C.W.
Does the servo have enough time to reach the desired angular position before being commanded to another position?
My inside loop and called subroutine:
There are some LCD updates and other stuff, but it's all outside this loop. This routine gets PING data, sends the distance then moves the servo..... then all over again.
The "STEP 1" is because I've changed it 50 times.... so I just left it in there. "1" is just the latest iteration. I also made a little pause routine that changed delay based on the delta-T of the PING echo, in an attempt to at least move the servo consistently regardless of the distance measured. Before (and this routine) the closer the PING measured, the faster the servo travels. I removed it just to make it easier to read. This routine drives the servo very choppy at distances greater than about 24"
The servo can be adjusted from 750 to 2500..... PULSOUT SVA_PIN, i which would be 0.2ms at 2500 plus execution time for PULSOUT
Yea, I guess one of my assumptions are wrong. Maybe it just won't work, but I've seen videos where it DOES work.
Oh, yea. The servo is fast - fast. 150ms for a 60 degree sweep. I can drive it with raw code no problem..... update, pause 20, update and it'll sweep beautifully.
I could just use the un-calculated rawdist and bitshift it to something Byte sized..... or even send Words for that matter, but I don't think the three calculations are eating my clocks. Could be wrong though. I can try it.
Quite honestly I ignored actual execution times of each command because we're talking microseconds to execute an instruction.... again, I could be wrong.
I looked at Mr. Allen's work on Stamp timings, but it doesn't include the BS2px, neither does it include much information for the next slower 20Mhz versions Maybe this data is not available.
I removed the calculations and just used the Word size "Rawdist" value the PING returns. I still get a choppy servo. If I put my hand ~3" away from the PING I get smooth motion..... 24"+ or so, it gets choppy.
That leaves the PULSOUT for the servo, the PULSIN for the PING and SEROUT. One or all are taking longer than I thought. Phooey.
I commented out the SEROUT instruction and there is no change in servo behavior. At least that's taking a minimal amount of time
I moved the PING routine into my inside loop to get rid of the two branch instructions GOSUB and RETURN. No change.
That leaves the PULSOUT for the servo and the PULSIN for the PING. I'm kinda stuck I guess.
for a grand total of 21.004ms on a much slower BS2. ARG!!!!!! The servo should be running perfectly given this!
Ignoring the PULSOUT for the servo, because the PULSOUT and PAUSE 20 runs the servo just perfect...... that leaves the PULSIN for the PING. It must be taking MUCH longer than the manual says.
It may be time to email Parallax about the PING. At least I'll know for sure.
In the code you posted I see...
Move the servo the smallest distance possible. In that time do a PING, a calculation, and send the result to a PC.
1) The PC could do the math not the STAMP?
2) The servo could have a larger sweep?
3) you could start the Ping, pulse the servo, read the result, pulse the servo?
I'm still not sure what you're trying to do. Where does lastSVA and SVA get set?
#1 Thank you for the reply. Post #9 is the most recent with all the options removed. It shows everything that's happening on the inside loop. I removed the calculations, no DEBUG, no PAUSE, just what you see and the servo runs erratic depending on the distance the PING senses.... the longer the distance the more "crunchy" the servo runs. at a PING distance of about 3", the servo runs perfectly just like PULSOUT and PAUSE 20 would perform. The point is, given this information one could surmise it takes 20ms for the PING to detect an object 3" away.
#2 The servo can have a larger sweep.... the larger the sweep, the more erratic the servo performs in THIS program.
If I run the following program to only update the servo 5 or 10 or 15 positions at a time with a PAUSE 20 it'll really walk the dog..... nice and smooooth
FOR i=750 to 2500 STEP 10
PULSOUT SVA_PIN,i
PAUSE 20
NEXT
#3 Yessir' that's exactly what the last code does (Post #9)
I'm just trying to get a consistent and smooth servo operation with a mounted PING. Theoretically and from what I understand from the docs, this would be quite simple since I thought the total execution time for the loop would be very close to the 20ms frequency the servo requires to move properly.
lastSVA is SerVo A's start position (the previous end position)
SVA is SerVo A's end position (The position we are moving to this time through the loop)
Both variables are set outside the loop. Sorry, I figured it would be easier to read if I posted only the work routine instead of the 100 or so lines of the full program.
What about something like this
I don't think that will work. There is a 750uS delay from the falling edge of the trigger pulse before the rising edge of the detection pulse. The PULSOUT to the servo will be roughly in the 1000uS to 2000uS range, so the PULSIN won't see the rising edge of the sonar detection pulse.
C.W.
So look at it this way: PULSIN ping, 1,rawdist....... If we were measuring the distance from Earth to the Moon with the PING the PING might hold the pin HIGH for 20seconds, the time it could take to receive the echo back, the BS2 will sit there and do nothing for 20 seconds until it sees the pin change state.
I AM a little worried about the fact that the servo PULSOUTs are sent like 75% time apart.... like if the routine took 30ms to execute we send a PULSOUT at 1ms and 25ms, then again at 31ms... We'll see though. It would very cool if it works!
1) If PULSIN does not start counting until is sees a rising edge on its pin, it won't start counting because the the pin will aready be high when PULSIN is executed. The documentation says "PULSIN is like a fast stopwatch that is triggered by a change in state (0 or 1) on the specified pin", so I think this is the case.
2) If PULSIN starts counting if the pin is already in the desired state when PULSIN is executed, you will see a count, but it will be inconsistent because of the variable delay caused by the PULSOUT to the servo.
The example also leaves out spending any time to send the data via serial, so that would also be an issue.
I have an idea bouncing around in my head, I'll try to put together some pseudo code at lunch.
C.W.
I have seen this my self up close to the ping works real fast far away take longer to run through the code routine
Yea, it's very noticeable too! Do you have any actual times?? I don't have a real time clock, and I can't run the PING off my computer.... no parallel port
I need to order some parts to play with this some more.
Thank you sir. The code looks good. I'll try it out and let you know what happens. The real solution for this is to run the Parallax servo controller.... That's probably where I'll end up
I bought these real nice HiTec Karbonite geared servos. They are fast and strong. I just hate the idea of sending pulses to them off-frequency because that means the motor stops and starts at high frequency.... That can't be good.
-Phil
Those sound nice, would be a shame to treat them harshly.
Another alternative is the Propeller. I think you mentioned on one of the other posts that the prop was on your horizon in the future. There are objects in the OBEX for servo control, serial comms, etc., should not be too hard to get going.
I've got a couple props and the PEK here, I've done some playing around but nothing serious yet, maybe this gives me an excuse to dive a little deeper. :-)
C.W.
That's a clever little device.
C.W.
<sigh> The Prop. I would love to get my hands on that I can just imagine. Hey COG#1 do this, hey COG#2 do that. Hey, COG#3 let me know when they're done and calculate all this Smile and send it over serial while #1 and #2 is busy running their stuff at the same time. BwaAHAHAHA!
Thank you for all the suggestions though, really. They've all been a big help.... and to Mike Green for pointing out what I didn't want to accept
I've been quite busy sir. I haven't touched my project in four days I think. I now hope to try your program tomorrow night. Tonight is booked up already
My OEM stamp and PING))) arrived Saturday, I built the stamp and modified my Atom code to work, but have not had a chance to do anything else. I doubt I have a chance to do anything else with it until next weekend.
C.W.
HA!HA!HA! It's kind of hard to put this into words, but I'll try.
So I have this flimsy plastic quarter roller hot glued to the top of the servo (Hey it's the first thing I found!!) then the PING hot glued to that so the sensor is perpendicular to the floor. I load your program into the BS2.....execute the PC end program and give it a servo position and. WHAT THE!???!!
So the servo is shaking violently from side to side, very very fast, like a dog after a bath.... the PING looks like a pair of eyes and they are just a blur. HAHA! Was hilarious man. I guess you had to be there.
Anyways, the problem was easy to find (because I just made the same mistake about 2 weeks ago) and fix with a set of parenthesis.
PULSOUT SVA_PIN, i + (increment >>1)
I bit shifted instead of your divide..... same thing.
The pause works very nicely. The PING reads 3" away or 100", the servo is constant speed, it is however brutally slow. It doesn't seem to want to tune out either.... I can hear the motor energize about thirty times a second with a little tick, tick, tick.....I THINK it's because we're updating the servo every 1 and 35ms.... or essentially once every 40ms. I'll play with your code a bit more.... I think that's it though
EDIT:
NO, I looked at your code again... You ARE updating the servo position every 20ms. Once at the start with "i" then after the PING stuff.... corrected to 20ms..... with "i+1"
Hmmm, let me work with this some more.
You wrote a nice routine actually. The sweep is very consistent regardless of the PING data. It works, "pretty" well, but the servo is still rough and I don't know why. To me it looks like it should run perfectly. The best I've been able to tune so far is:
Cool, glad it is getting closer to what you want.
When I put that code together I didn't realize that the stamps do left to right evaluation, so that is why I didn't use parens when I should have.
I discovered that the hard way when I converted some code for my OEM Stamp last weekend, ended up with my servo slammed against it's stop groaning loudly...
I'm not sure if you can really tune out the "tick-tick" because unless you sweep the servo at it's natural rate of rotation it will stop briefly at each commanded location.
C.W.
The only thing I can think of that makes sense is the PING is actually taking longer than 20ms for ANY reading and we're offsetting that 20ms to the next 20 for a total of 40ms. That would update the servo, wait 40ms, update the servo, wait 20ms, then over again. I can't verify that without a RTC though.