Multiple R/C servo control

Hi folks,
I've been doing lots of tests with controlling R/C servos lately, some good experiences and some bad experiences. I even wrote an introduction paper on
how to interface the PC with R/C servos using the serial port and a PIC microcontroller.
The strategy I present in that paper is very basic, and although it works fine, it is kind of jittery and does not support too many servos. Now I'm working on a improved version of my servo controller that will theoretically get rid of the flicker and support unlimited servos (in theory).
I am a firm believer that the best way to learn something is to teach it. Therefore I will try to make another paper exposing this new method (of course, if it works). Before doing that, I need to know if someone else already did such tutorial paper, and if yes, if it is similar to my strategy.
Here's an outline of my strategy, please express yourself if you find a flaw in it as I'm going to test it tonight.
1-Assume there is an array of servos controlled by the uP and this array has the following fields: servo_idx, pulse_width_uS, servo_no Whenever the array is updated (through serial commands), it is sorted in by pulse_width_uS
2-Drive all servo lines high, set TMR0 with the time interval of the first servo of the array
3-When TMR0 triggers, set the respective servo low. Also set low all the subsequent servos from that list that have the same pulse_width_uS. Set new TMR0 interval as the difference between next servo pulse width and current one.
4-Repeat this operation for all servos until there are no more servos to drive low. At that point, set TMR0 with 20ms - current pulse_width_uS
And that goes forever. There are a couple more quirks to it, but that's the overall outline. If you are controlling 4 servos, TMR0 should trigger 5 times in the worst case, 1 time for driving all servo lines up and 4 times (less if some of them share the same time interval) to drive them low.
That gives me lots of time in between pulses to do whatever I want (receive USART bytes for example) without interfering too much with the PWM timing mechanism.
Do you think it is a good approach to try? If yes, do you think it would be worthy to write a short paper on that?
Cheers
Padu
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

good
on
---snip---
Padu... if I spoke Greek I might be able to give you an intelligent answer to your question. Now let me ask you a question: How many people out here in the real world could understand a word you said?
First of all, what kind of servo and what kind of interface are you using? If I buy a sail winch servo from Hitec, how do I connect it to what without going through the radio? How do I power it if not through the existing radio from the vendor?
Should you not set up the experimental parameters first for those of us with interest in this subject to duplicate your work in a scientific manner?
I've met you and recognize you as a brilliant automation engineer and only make this note from my own ignorance on behalf of others who may not be willing to share their own lack of experience but who would like to know more and who could appreciate your insight.
Wayne
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
"Wayne Lundberg"

It's always good to learn a new language right? ;-) I'm sorry if my post carried too many assumptions, I should have disclaimed that a certain knowledge on the subject was necessary beforehand. I am usually more explicit, but my post was long enough so I decided to summarize my request. I'm sure that some of the habitue PIC gurus will make some sense on what I said. Just to prove that I usually try to be more methodic, please read the paper I mentioned in my email: http://www.merlotti.com/EngHome/Computing/servo_controller.pdf If I fail to convey my point in the above paper, then blame it on me, because its intention is to bean introductory text on how to interface R/C servos with a PIC microcontroller.

R/C servos, the ones you buy in R/C hobby stores (hitec or futaba are good examples)

From my knowledge, it is usual for these types of servos to use a PWM signal of 20ms pulsetrain with a pulse width varying from 1 to 2 ms.

It will probably have 3 wires: VCC, GND and Signal. I don't know about sail servos, but usually R/C servos are powered out of 5VDC (current varies from manufacturer to manufacter). Signal line is the one you have to generate the PWM signal.

As mentioned above, any 5VDC will do. (but take a look at the specs first in order to determine current requirements)

I intend to do that if I write the paper. My previous post was only a feeler if someone else hasn't already written similar material... I don't like to write redundant stuff without adding something substantial to it.

Not a problem. I love to share my knowledge of things I know as well as things I don't know. 8^)
Cheers
Padu
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

answer
here
disclaimed
summarize
sense
paper
signal
sail
from
the
in
feeler
only
Thank you Padu.. You have illuminated a few chunks of darkness in my brain. My son Lyle, originator of the RCWindjammer (www.rcsailcars.com) has a few servos left over from some production runs. I'll have to take one apart and play with it. I do have a Basic Stamp X-24, so... I should be in the shop playing instead of here writing!
Wayne
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Is there any open source& design multi channel servo controller board with board 9 or 10 bit accuracy?
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Thu, 22 Sep 2005, it was written:

I'm not exactly sure what you are asking for but just in case this is of use:
The XCSB servo library uses 8 bit resolution and it controls multiple RC servos. You can buy the source and change this to 9 or 10 bit resolution yourself very easilly.
There is a simple circuit at http://www.xcprod.com/titan/XCSB/CONTRIB labelled "PIC Servo Controller" that shows how to control 4 servos with this library using a VERY low cost PIC.
The software for this circuit is compiled using the LITE edition of the compiler and the servo library that comes with it (not source).
Regards Sergio Masci
http://www.xcprod.com/titan/XCSB - optimising PIC compiler FREE for personal non-commercial use
.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

Another shameless plug: Look at my servo controller (which is an open design) http://www.modularcircuits.com/servo_32.htm . Right now it's 8-bit, but it has the HW capability do go to ~12 bits of precision for 16 of its 32 channels. I have plans to change the FW to support it but for now, you are welcome to make the change yourself. It's not that complicated actually.
Regards, Andras Tantos
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Thu, 22 Sep 2005 23:30:53 +1000, <Nick> wrote:

The below servo chip has up to 1us resolution if desired. I did some testing with a standard servo and with ~190 deg of rotation, I could only get ~425 descrete steps in the 190 deg rotation. It appears that a regular cheap servo will get little improvement from higher than 8 bit resolution at ~255 steps.
http://www.kronosrobotics.com/xcart/customer/product.php?productid273&cat)2&page=1
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
You may like to have a look at http://www.rc-cam.com/servotst.htm - a PIC servo driver - you may find a number of similar circuits and projects that were designed for RC models
David - just passing info along
Padu wrote:

Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Tue, 20 Sep 2005 22:19:44 GMT, "Wayne Lundberg"

If you want a really simple and cheap start with controlling servos via the pc, check my page below. I use the servos for a pan/tilt cam, but you could use them for robotic stuff too. I've given up on trying to program my own servo conrol chips, as Kronos robotics sells them for $7 which fits my budget. You can check the bottom link to see how simple it is to control the servos over the net.
http://www.geocities.com/zoomkat/ezservo.htm http://www.geocities.com/zoomkat/ezservo1.htm
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

I could. All of it.
Anyway, Padu, the problems I see are:
1) You have to make TMR0 tick fast enough to give you the resolution you need. My digital Futaba RC gear gives 1024 steps over the 1-2ms range of pulse widths. To match that you'd need a 1MHz tick on TMR0.
2) you have to make sure everything you do takes <1 tick of TMR0 (imagine you want one servo off at 1.501ms and one at 1.502ms). On a 20MHz PIC that's 5 instructions, ignoring whatever overhead firing the interrupt adds.
Me? I use an AVR with hardware PWM :)
Tim
--
You are being watched. This gives you power.

Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Tim Auton wrote:

Yes, the AVR ATmega128 has two 16bit timers, each capable of controlling three pins. Set few bits, then update the 6 registers for the 6 servos, no interrupt code required. AVRs rule, and the Linux environment works great with them.
--
Mike Ross

Instructions said Win98 or better, so I used Linux.
  Click to see the full signature.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Padu wrote:

Padu:
Controlling servos from a PIC has been done before. My PIC based servo controller can be found at the URL below:
<http://gramlich.net/projects/robobricks/servo4/rev_j/index.html
There is a subtle issue with servos -- they are very sensitive to the pulse width. Changing the pulse width by a uSec or two will cause the servo to move a small but noticable amount.
The scheme you propose will have a difficult time producing pulse widths that are close to one another. Changing the pulse width of one servo might cause the pulse widths of the other servos to change a little.
The simpler strategy is to forget all the sorting and just pulse one servo at a time in sequence. Turn on servo 1, set TMR1, turn off servo 1, and repeat for each servo in sequence. Given a maximum pulse width of 2.5uSec, you can visit 8 servos every 20uSec.
Lastly, remember that PIC's are really really cheap. If you find yourself doing all sorts of tricks to get them to do what you want, consider using more PIC's. For example, suppose that you are using a digital servo and need a really fast update rate. Dedicating a PIC to each digital servo is not unthinkable.
Once you get your PIC code working, by all means write it up.
My $.02,
-Wayne
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
"Wayne C. Gramlich" wrote

That's a very nice write up! I also found some literature about a guy named Scott Edwards who has a similar board. I don't know if he's around here though.

I noticed that in my previous experiments...

Yes, I realize that, but the way I'm planning to do is to do very little computing in the first 2 miliseconds of the pulse train. The sorting procedure (heck, I'm a software engineer, I SHOULD know how to write a very efficient sort procedure) will be done in the remaining 18ms, while the PIC is sitting there doing nothing.

I'm not sure I understood completely this last part. What you are saying is to generate each one of the pulses back to back? If yes, then how do you guarantee the 20ms interval between pulse rises? Are you taking advantage on the fact that pulse train in most rc servos is very forgiving? (I've heard people saying that even 5ms pulse trains worked fine)

I'm aware of that, and that's probably what I'm going end up doing, driving two servos per uC, but I always like to think in more abstract terms. Actually, if I write up this, I think I will completely abstract which processor I am using. (but maybe I'll post the source code as an appendix)

I'll let you know tomorrow what are my findings, I'll pay special attention to your (and mine) concerns about two servos with very close positions.
Thanks for your comments
Padu
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Padu wrote:

A number of us have done PIC based servo controllers over the years. The first one I saw was the one by Dennis Clark.
[snip pulse width sensitivity]

The sort time is a non-issue.
The issue is that there is a delay from the time that you get an interrupt until you stuff the next difference number into the TMR1 register. You have to take that into account. Also, you have to get out of the interrupt routine before TMR1 wants to generate another interrupt. There is a great deal of tricky programming to be done. It is best to avoid all of that tricky stuff.

It is simpler than that. Set TMR0 to interrupt every 2.5ms. It picks the next servo delay from the array and stuffs it into TMR1 and returns from interrupt. When TMR1 fires, clear the servo line. The pulses look as follows:
0 ---XXX-----------------------------XXX-------------------------XXX-- 1 ----------XX-----------------------------XX------------------------- 2 -----------------XXXX--------------------------XXXX----------------- 3 -------------------------XXX---------------------------XXX----------
It should be a piece of cake to keep 8 servos running with 20ms between servo pulses.
I always wind up doing 4 servos, since I put resistors in series with the servo ground return to measure stall current. I simply run out of pins on the smaller PIC's.
[snip PIC's are cheap]
[snip write-up]
-Wayne
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
"Wayne C. Gramlich"

The strategy you explained in here plus Sergion Masci's argument have convinced me of that. Perhaps my strategy would work in most of the cases, where values were far apart (or exactly coincident). As you said, the advantage of being able to control an undefined number of servos is quickly lost in an environment with as many restrictions (physical time to compute, number of pins, etc).

very
PIC
And now I know how hard it is to debug this type of application.

is
advantage on

heard
0 ---XXX-----------------------------XXX-------------------------XXX--

1 ----------XX-----------------------------XX-------------------------

2 -----------------XXXX--------------------------XXXX-----------------

3 -------------------------XXX---------------------------XXX----------

Very simple idea and I don't see why it wouldn't work. If you don't mind I'll borrow your idea and implement it on my robot... Now looking at my flowchart (yes, I can only program if I flowchart it first), it looks like a nice piece of logic, but I spend a good amount of time to implement it and find out that it wouldn't work as I expected.
Thanks for your help!
Cheers
Padu
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Padu wrote:
[much snippage]

I don't mind at all. Have fun.
-Wayne
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
"Wayne C. Gramlich" wrote

I've implemented it on my devboard yesterday, with USART interrupts and all, and works perfectly! No jitter even when sending a constant flow of serial data at 9600baud. Thank you very much.
The only thing I noticed was that when I set TMR1 to 1500uS for example, I would see 1480uS on the oscope. It didn't turn out to be a huge problem, as the error was constant. I did a quick test, doing a program with the only purpose of generating a square wave of fixed width, and even there I had a very small error (about 100uS) between expected (calculated) interval and measured interval.
I'm using a PIC18F452 with an external crystal can at 4MHz. TMR1 is set to 16 bit and no prescaler. The way I'm calculating the interval is pretty simple, at 4MHz each instruction cycle takes 1uS (4/FOSC), therefore a full cycle of TMR1 (0xFFFF) would take 65536uS right? If I want to calculate a TMR1 interval of 1500uS, then it is 65536-1500-2 right? (the 2 is because updating TMR1 takes two instruction cycles), that would give me 64034 or $FA22. Is that correct?
I believe I can compensate for the error and no harm done, but I thought it was weird. The only thing done in TMR1 interrupt is driving servo lines low, nothing else.
Cheers and thanks for all contributions!
Padu
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
Padu wrote:
[snippage]

You are welcome.

I think you are witnessing classic interrupt latency. I suspect that you have 20uSec between the time the interrupt occurs until you actually clear the servo pulse. You can verify this by inspecting your interrupt service routine and counting instruction times. Remember, there is "psuedo" CALL instruction required to initiate the interrupt. I'm more familiar with the 16F series, but I think the 18F series CALL takes 3 cycles (I could be wrong.)
Also, if you crank of the beam intensity on your oscilliscope, I suspect that you discover that there is 1-2 uSec of jitter on the pulse. If an interrupt occurs in the middle of a multi-cycle instruction, the interrupt is delayed until the instruction is done. The vast majority of instructions on PIC's are one cycle, but some instructions such as CALL, RETURN, GOTO, etc. take more than one cycle. If the interrupt occurs during one of those instructions, there will be an extra cycle (or two) before the servo pulse is cleared. Given that your servos are not experiencing jitter, I would not recommend worrying about the issue.
-Wayne
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload
On Tue, 20 Sep 2005, Padu wrote:

For this to work your processor would need to be VERY fast.
Say you divided the full travel of your servo into 256 steps so that a value placed in a byte wide veriable mirrors the position of the servo.
The full travel is covered by a 1ms pulse (1ms being one end and 2ms being the other end).
So you would divied your 1ms pulse into 1/256 ms units.
If you had servo A set to position 10 and servo B set to position 11, the amount of time you have available to complete servicing the interrupt that handles servo A and start processing the interrupt to service servo B is 1/256 ms.
this is about 3.9 microseconds. On a fast PIC executing instructions at about 5 MIPS this is about 20 instructions between servicing servo A and servo B. ***ANY*** delay (such as servicing another interrupt - maybe a heartbeat system clock or serial I/O) would give jitter.
You might be able to get away with building groups of servos that have a minimum position difference that is greater than 5. Then you could interleave servicing of the groups say every 10ms. but this would only allow you two groups. if you did this for every 5ms you could interleave 4 groups but this would limit minimum position difference to 4.
Even with this interleaving I still think you would have problems with other interrupts causing jitter.
Regards Sergio Masci
http://www.xcprod.com/titan/XCSB - optimising PIC compiler FREE for personal non-commercial use
.
Add pictures here
<% if( /^image/.test(type) ){ %>
<% } %>
<%-name%>
Add image file
Upload

Polytechforum.com is a website by engineers for engineers. It is not affiliated with any of manufacturers or vendors discussed here. All logos and trade names are the property of their respective owners.