Software > Software

Project Designer error message when trying to use all AXON2 PMW + software

<< < (3/3)

You can get >9 hardware pwm servos if you can afford to dedicate all 16 bit timers - ie 4 timers = 12 hardware pwm servos. But since you've got more than 12 servos then you are using s/w pwm and hence need to grab one of the timers back. As for other folk claiming a different 'mix' then I can't vouch for how they did that - so if Admin claims more then perhaps ask him what he did.

As for 'banks'.... Hardware pwm doesn't really matter - the only advantage 'banks' give you is that you can instruct all servos in a bank at once rather than one at a time. For s/w pwm then each bank has its own timer - so if you put 'too many' servos into the bank then the total period may go over 20ms and the servos go floppy. But then you have to sacrifice another timer for another s/w bank.

So the rough equation is: a hardware pwm can drive 3 servos  per timer (unless its an ATMega168 which may only have two channels per timer). A software pwm can drive, say, 8 servos per timer but does take up more CPU utilization. I say 'say' because it depends on the min/max pulse time of your servos. Software pwm will always have more judder because its using s/w to time the required pulse - but if you have other hardware thats causing lots of interrupts like encoders then this timing may not be exact - hence judder. Hardware pwm is great in that there is no judder and you get maximum torque.

Hence it also depends on the kind of bot your are building. For example: a biped probably needs h/w pwm for the legs as you dont want judder and you dont want floppiness. Whereas arms, or head movement, may just be cosmetic and non-load bearing and so are better candidates for s/w pwm.

Never built a hexapod - but if there are 'key' legs that provide the most thrust then use hardware pwm for those. Other ancillary legs may not need to be as exact.

So quick answer is 'you need to see what works for you!'.

Final comment: if servo control is critical and your robot is also having to do lots of complex maths (inverse kinematics say) then you may find the amount of CPU time that is lost to controlling s/w pwm slows down all of your main loop. In which case you really need to think about a slave board (or several) that just controls the servos. Either an available commercial one - or just build your own using an ATMega168/328 + WebbotLib using, say, the multiplex driver that is part of WebbotLib and allows one timer channel to control 8 servos. You could probably build one on matrix board for a few dollars so long as you have a hardware program (AVRISP MKII etc) to blow the code onto the chip!

High precision timing without hardware PWM is totally possible, if you can live with disabling interrupts for 2 milliseconds every 20 milliseconds. Note that disabled interrupts may make a serial port drop bytes, for example. I2C is better, as it contains built-in flow control in the hardware protocol.

First, order all your outputs from "shortest pulse" to "longest pulse."

--- Code: ---struct pintime {
  unsigned char pin;
  unsigned short ticks;
pintime pin_off_time[18] = { ... };

--- End code ---

Then, build a set of output register values that have all the pulses on. For 18 outputs spread on 3 registers, it might look like:

--- Code: ---struct outputs {
  unsigned char rega;
  unsigned char regb;
  unsigned char regc;
  outputs cur = { 0x3f, 0x3f, 0x3f };

--- End code ---

Now, for each output pin in order (soonest to latest turn-off time) build a table:

--- Code: ---struct time_outputs {
  unsigned short ticks;
  outputs vals;
time_outputs table[18];

  for (int ix = 0; ix < 18; ++ix) {
    time_outputs[ix].ticks = pin_off_time[ix].time;
    clear_bit(time_outputs[ix].vals, pin_off_time[ix].pin;

--- End code ---

"clear_bit" would clear the appropriate register/bit value for the given pin number.

Now, disable interrupts, set all the pins to "on," then enter a tight loop that looks for the timer value, and turns off the pins when the time comes, by writing the regisers:

--- Code: ---  disable_interrupts();
  outputs val = { 0x3f, 0x3f, 0x3f };
  TIMER = 0;
  for (unsigned char ix = 0; ix < 18; ++ix) {
    while (TIMER < table[ix].ticks) {
      /* do nothing */

--- End code ---

On a typical Atmega, setting the timer to run 4 ticks per microsecond is common, so if your input time is in "microseconds" then your "tick" values have to be multiplied by 4 (and thus you'll have 0.25 microsecond resolution.)

@jwatte Yep WebbotLib has supported software PWM for years. By software PWM I mean anything that has a timer interrupt/delay that uses software - ie yours and WebbotLib. And the problem is always that you either have to disable all other interrupts at some point to keep the PWM correct or you keep them enabled and end up with potentially 'jittering' servos. You mention that your solution may loose the odd uart byte due to disabling interrupts - but what about an encoder generating 1000s of interrupts per second - can't afford to loose them! So my comment was really that: pure hardware PWM is 'exact no matter how many other things/interrupts youve got going on' whereas any PWM that has ANY software involved will always be flakey (unless all your program is doing is controlling servos - in which case buy/build a slave servo controller board)

Putting some code into a $2.50 AVR CPU is a lot cheaper than buying a $25 servo controller board, though! And then you can talk to that thing using I2C from your other CPU.


--- Quote from: jwatte on September 05, 2013, 08:41:12 PM ---Putting some code into a $2.50 AVR CPU is a lot cheaper than buying a $25 servo controller board, though! And then you can talk to that thing using I2C from your other CPU.

--- End quote ---
Absolutely - but why not build your own servo board ie $2.50 AVR CPU using WebbotLib to handle I2C and servos and nothing else - as suggested in the last paragraph of my earlier post? By having such a slave board then more timers become available for use by WebbotLib. My original comment was more to do with if you expect a single cpu to do lots of PWM + I2C devices + UARTS + Encoders + your main code etc etc then things may work - but not perfectly. Can't put a gallon in a pint glass! Its very easy to write each thing in isolation - but very difficult to do everything simultaneously.


[0] Message Index

[*] Previous page

Go to full version