Manchester, New Hampshire
Offline
Edison Member
Karma: 0
Posts: 1120
Propmaker
|
 |
« on: November 11, 2012, 08:36:02 am » |
Hey guys,
I was taking a look at the Servo() lib, wondering why it was limited to only 12 servos per timer, and though I'm not certain, it seems like there may be room for improvement. (And that is an understatement.)
First, let's discuss how servos work, and why 12 servos per timer is the magic number here.
Servos work by keeping track of the length of time between pulses on their signal line. To keep them in a particular position, every 20 milliseconds, you need to set their signal pin high for between 1 and 2ms. A pulse of 1.5ms, with a low period of 18.5ms, will keep the servo centered. These pulses need to be sent constantly or the servo will stop trying to center itself and move freely instead.
So how does the Servo() lib send these pulses? Well, it looks like it uses the interrupt to time the pulse for only one servo at a time. So, for servo one, it sets the servo's signal pin high, then sets the interrupt to trigger when it should go low again... up to 2ms later. It then moves on to the next servo and does the same thing. The limit on the number of servos comes from the amount of time you have between when you need to send pulses. And the Servo() lib seems to play fast and loose with the standards, allowing up to 24 milliseconds between pulses instead of the usual 20, which give enough time for 12 pulses up up to 2ms each before it needs to repeat the first.
This seems really inefficient to me however.
It seems to me that every 20ms, one could toggle all the servo pins high at once and then turn them off one by one as needed when a particular servo's time is up. Using some sorted arrays could make deciding on how long to wait to trigger the next interrupt very fast. In this way, one could control as many servos as they wanted from a single interrupt. I see no reason why you shouldn't be able to control 64 of them in this manner with just one timer interrupt.
Anyway I'm interested in hearing your thoughts on this. I'm not going to have time myself to test this theory out for a while, and I don't really need more than 12 servos myself, but if one were developing a spider-bot or something and one didn't want to waste their precious timers or use a MEGA, then the ability to control 20 on a standard Arduino might come in handy.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 6
|
 |
« Reply #1 on: November 11, 2012, 08:46:33 am » |
if this lib can control up to 20 servos,then it will be more easy to do a Biped Robot 
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #2 on: November 11, 2012, 01:10:23 pm » |
Hi, Here are two libraries, the first will get you 20 servos from 4 pins, the second will drive a servo from every Arduino UNO pin upto 18 Servos. http://rcarduino.blogspot.com/2012/10/arduino-serial-servos-20-servos-4-pins.htmlThe interface to this one is ugly, but the philosophy is - if you asked me to do something you had a good reason. The ugly part is that it does not enforce a fixed refresh rate and so if you so not set one it will pulse your servos at much higher frequencies - some people want this ability - http://rcarduino.blogspot.com/2012/11/how-to-read-rc-channels-rcarduinofastlib.htmlIf your interested in using either of them let me know, they are well tested, I consider them reliable but they could be better documented. Here is the second library in action with some PPM reading code also included in the library - Duane B rcarduino.blogspot.com
|
|
|
|
|
Logged
|
|
|
|
|
Manchester, New Hampshire
Offline
Edison Member
Karma: 0
Posts: 1120
Propmaker
|
 |
« Reply #3 on: November 11, 2012, 11:09:21 pm » |
If I'm not mistaken those libs of your require an additional chip to drive the servos. I'm talking about driving them with software.
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #4 on: November 12, 2012, 07:13:14 am » |
You are mistaken, second library puts a servo on any pin, upto 20 pins - 18 is more pratical though as it allows you to keep serial comms - no additional hardware required.
For the other library, the additional chip costs about 30 cents, a bargain for so many servos from so few pins.
Duane B
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6820
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #5 on: November 12, 2012, 09:51:07 am » |
It seems to me that every 20ms, one could toggle all the servo pins high at once and then turn them off one by one as needed when a particular servo's time is up. That's how I'd do it. ______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #6 on: November 12, 2012, 02:29:18 pm » |
That's how I'd do it.
No, you would not. the reason it is not done this way is that you would need to loop through the servos at every pin change to see who should go next, with 20 servos that would be a lot of 16 bit operations. alternativley you could try and sort the servos at the start of each frame but again lots of 16 bit operations. The current servo library uses around 1% of arduino processing power for 12 servos, my library is more efficient but has a less friendly interface - I would only consider using it if you want those extra servos, a higher refresh rate or smoother RC signal interrupts. Duane B
|
|
|
|
|
Logged
|
|
|
|
|
Manchester, New Hampshire
Offline
Edison Member
Karma: 0
Posts: 1120
Propmaker
|
 |
« Reply #7 on: November 13, 2012, 03:18:50 am » |
the reason it is not done this way is that you would need to loop through the servos at every pin change to see who should go next, with 20 servos that would be a lot of 16 bit operations.
You are mistaken. You see this? That is a circuit I built, which has an array of 64 multiplexed LEDs. Nothing special about that you might think, and I wouldn't blame you since the video doesn't demonstrate it very well, but if you look closely, you may notice the LEDs that aren't brightly lit are displaying a gradient. That's pulse width modulation. On a multiplexed display. How did I achieve this? By sorting the LEDs so as I illuminated each column of the display I needed only check the time against the next LED to turn off. alternativley you could try and sort the servos at the start of each frame but again lots of 16 bit operations. There's no need to sort the servos each frame as long as you keep your list sorted. When you set a new angle, all you need to do is a quick binary search to the left or the right of where the previous position was in the list to figure out where to insert the value, and you're done. Yes, this requires a few operations. But setting the servo position doesn't need to be super fast. Servos can't respond within microseconds to a change in position anyway. Where speed is important is in the servo interrupt, and that would be super fast with the list already sorted for it.
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #8 on: November 13, 2012, 06:32:18 am » |
Fair enough - as arduino is single threaded and you only need to re sort if a servo position changes, you can safely figure out the sort order with interrupts still enabled and then just disable them to do the update - should be smooth and simple.
Duane B
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #9 on: November 13, 2012, 07:13:08 am » |
This seems really inefficient to me however. The advantage of that is that it is inherently PPM, if you output the pwm pulses on the same pin. The disadvantage is that those pwm pulses are not phase aligned and there are channel limitations. It is not hard to write pwm output on any arbitrary number of channels. I think I provided one example somewhere. Basically you establish a counter that counts up to a the period. At each increment for the counter, you test for overflow and output pins; At the roll-over of the counter, you re/set all pins.
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #10 on: November 13, 2012, 07:37:21 am » |
I doubt very much that you could get anything like ppm out of the standard servo library. Your welcome to prove me wrong with a demostration though.
Duane B
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6820
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #11 on: November 13, 2012, 11:01:01 am » |
No, you would not. Yes I would, but on a processor that has enough RAM to have a large lookup table of values to write to the port(s). ____ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #12 on: November 13, 2012, 11:10:47 am » |
Hi Graynomad,
If you look at the response after mine from scswift, he is quite right, its trivial to sort the servos whenever the angle is updated and then just let the ISR CYcle through a pre sorted table.
The next problem is if you have 20 servos at very similar values, Do you stay blocking in the ISR to set all 20 of them ? What about if each is set to a value 1, 2, 3 or 4 microseconds more than the last ?
Its these boundary cases that will determine if the idea can work.
Duane B
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6820
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #13 on: November 13, 2012, 11:22:38 am » |
just let the ISR CYcle through a pre sorted table. Yep, sounds reasonable. The next problem is if you have 20 servos at very similar values, Do you stay blocking in the ISR to set all 20 of them ? What resolution are we talking? ______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #14 on: November 13, 2012, 01:41:38 pm » |
5us makes the gears in the servo jiggle around, 10us is a noticable tick at the output shaft. An ISR is going to be around that mark so for 10 or more servos all within 50us of each other, the simultaneous servos approach is going to have a problem - my guess is thats the reason that current approaches are sequential rather than having a simultaneous rising edge.
Duane B
|
|
|
|
|
Logged
|
|
|
|
|
|