text: NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
  Sensors, Actuators, and Robotics » Controlling more than one servo
  How can I control more than one servo motor? I am using code similar to the Servo Squirter code.
  Can you post a schematic of what you've done? If you have enough free pins of the right can, you can control another. Maybe more, depending also on the above.
  Boba, I am currently working on that aspect. Will fill you in when I get it figured out.
  Mongo
  Ethanal-
  Take a look at the schematic in the Servo Squirter tutorial. It only takes a pin or two to control either the pump or the servo.
  Add the necessary components, modify the code, re-upload new code to the chip and voila!
  Let us know how you get on!
  BM
  I think I might have figured this one out. I'm also trying to figure out how to control 2 servos. The ATMega168 only has one 16 bit timer/counter with PWM. The output compare registers are OCR1A and OCR1B. In the servosquirter project, Mode 15 is being used which allows us to use the OCR1A register as the TOP value. Since we want to use OCR1A as an output register we can store the TOP value in a different register, the ICR1. To do this we have to set the timer to mode 14 (see page 133, table 15-4 of the spec sheet). To set mode 14 we simply remove the bit being shifted into the WGM10 bit on register TCCR1A. So, instead of this:
  TCCR1A = (1<<COM1B1) | (1<<WGM11) | (1<<WGM10);
  We change it to this:
  TCCR1A = (1<<COM1B1) | (1<<WGM11);
  And so then this declaration:
  OCR1A = 36864
  Should be changed to this:
  ICR1 = 36864
  Then we can make two functions that look like this:
  void pwm_setx(uint16_t x){
  OCR1B = x;
  }
  void pwm_sety(uint16_t y){
  OCR1A = y;
  }
  From there we can hook up our two servos to PB2 and PB3 and then use whatever code you want to change those two values.
  I haven't tried this yet, this was the very next step in my 1 joystick / 2 servos project that I hadn't yet figured out until I decided to study the spec sheet and wrap my brain around it this morning.
  Please correct me if I'm going about this all wrong but this seems like the logical explanation to the problem.
  Also, from this morning's study I gather that only two servos can be controlled with the ATMega168 since they require a 16 bit timer to handle the 20.0ms pulse, and the ATMega168 only has one 16 bit timer with two output compare registers.
  Also, some information learned from the spec sheet as to why we would want to use OCR1A instead of ICR1: OCR1A is double buffered and would allow for dynamically changing the TOP value, this would be if we wanted to actively change the PWM frequency. Since we're keeping it at 20ms, the ICR1 register can be used since we're using a fixed TOP value.
  Ted
  Sorry, correction: the servos would need to be hooked up to PB1 and PB2, not PB3..just re-looked at the pinout.
  Hi Ted,
  You're definitely on the right track! One thing I wanted to address -- you suggest that only two servos can be controlled because a 16 bit timer is needed. However, you can also use Timer0 and Timer2 (each of which is an 8-bit counter with two Output Compare Registers each) to generate PWM for a servo.
  For example, in the "Fast PWM" mode with a prescaler of 1024, the overall PWM cycle period is 1024*256/14745600 = 17.8 milliseconds. That's in the 16-20ms range that servos "prefer". You do lose some resolution, however, as one counter unit is now 1024/14745600 = 0.069 milliseconds, meaning that the entire space between 1 and 2 ms is held in just ~14 units, meaning that you're basically limited to 14 position steps. But for many applications this is perfectly fine.
  There's another technique that you can use, which takes advantage of the fact that servos only care about the "on" time, and not too much about the "off" time (probably as long as they get an update within 15-100 ms or so, although the high end probably varies with different servo types). You could use the timer at a smaller prescale value to get a high resolution, but use an outside piece of code to explicitly trigger the counter to run each time.
  You could even get fancy with interrupts and have the timer switch between a high-resolution mode where it is running the servo via PWM (say with prescaler 256), and then a "slower" mode with PWM disabled that just times the "off" time. Really neat idea -- I might have to do this as a video tutorial!
  Mike
  Yer blowin' my mind, Mike! Yeah, I was thinking after my post, that using the 8-bit timers and the right prescaler I'm sure it could work, but I guess I was thinking about the smoothness factor when driving the servos with a joystick. I had a feeling it would have to lose some resolution in the overall throw of the servo.
  The last part about using outside code to trigger the timers has me envisioning the timer jumping all over the place just throwing pulses at a whole array of servos. Is this similar in concept to the LED array? Very cool stuff, you SHOULD do a video.
  Anyway, here is a link to the code I have come up with for my 1 joystick / 2 servos project. Haven't tested it yet at all...still waiting for the other half of my soldering iron and some breakout boards for the joysticks to arrive.
  2pots2servos
  Hmm, yeah the servo only works on PB2 right now. If plugged into PB1, no worky. I am pretty sure it has something to do with setting interrupts, but I am still not grasping that. Gonna have to do more research. Stay tuned.
  <Forehead smack> I think all I am forgetting is (1<<COM1A1) in the TCCR1A. So the line should be:
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11);
  Too late to try it tonight. Will test again tomorrow.
  Yep that was it...
  Good show! I just put it together here and after getting through the last bit, it took right off.
  wow! you solution is perfect! i have used it on my PPM decoder for my rc plane and it functioned wonderfully. the best part is how easy it was added to my code that uses the servo squirter code. good job!
  -Icarus
  A new hitch in the workings...
  I have been causing more brain damage that I like, trying to get two servos to work independently via the keyboard, (like the servosquirter does with one) I started out with the servosquirter program and began duplicating what looks like it should be but I keep getting compilation errors.
  I am combining parts of the 2pots2servos concept as well. Alone by them selves, I understand their ways but for some reason, I am having trouble grasping the dual system.
  Ideas?
  OK, I got it!
  I can now control two individual servos AND the pump motor giving me x, y axes as well as the pump.
  The rest is a simple batch file to sent key sequences to the port and the servos will follow the choreography coded within.
  Here's the code: I don't know why it changes fonts and sizes but here it is...
  void pwm_setx(uint16_t x) {
  OCR1A = x;
  }
  void pwm_sety(uint16_t y) {
  OCR1B = y;
  }
  void pwm_init() {
  // setup Timer1 for Fast PWM mode, 16-bit
  // COM1B1 -- for non-inverting output
  // WGM13, WGM12, WGM11 -- for Fast PWM with ICR1 as TOP value
  // CS11 -- for CLK/8 prescaling
  // each count is 8/14745600 = 0.5425us.
  // so 1.0ms = 1843.2
  // 1.5ms = 2764.8
  // 2.0ms = 3686.4
  // 20.0ms = 36864
  ICR1 = 36864; // sets PWM to repeat pulse every 20.0ms
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);
  }
  int main() {
  // init LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_write_string(PSTR("robot "));
  // init serial port
  uart_init();
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;
  // set PB1,PB2,PB3 as output
  DDRB |= (1<<PB1) | (1<<PB2) | (1<<PB3);
  // init PWM
  pwm_init();
  uint16_t pos1 = PWM_START;
  uint16_t pos2 = PWM_START;
  char tc;
  while(1) {
  pwm_setx(pos1);
  pwm_sety(pos2);
  // Print the current servo positions to the LCD.
  lcd_line_two();
  fprintf_P(&lcd_stream, PSTR("servo 1: %d "), pos1);
  lcd_line_three();
  fprintf_P(&lcd_stream, PSTR("servo 2: %d "), pos2);
  // Wait for a character to be sent to the serial port.
  tc = uart_read();
  if(tc==']') pos1+= 25;
  if(tc=='[') pos1-= 25;
  if(tc=='=') pos1+= 5;
  if(tc=='-') pos1-= 5;
  if(tc==',') pos1 = 1300;
  if(tc=='.') pos1 = 4200;
  if(tc=='m') pos1 = 2750;
  if(tc=='}') pos2+= 25;
  if(tc=='{') pos2-= 25;
  if(tc=='+') pos2+= 5;
  if(tc=='_') pos2-= 5;
  if(tc=='<') pos2 = 1300;
  if(tc=='>') pos2 = 4200;
  if(tc=='M') pos2 = 2750;
  if(tc=='0') PORTB &= ~(1<<PB3);
  if(tc=='1') PORTB |= (1<<PB3);
  // bounds checking
  if(pos1 > PWM_MAX) pos1 = PWM_MAX;
  if(pos1 < PWM_MIN) pos1 = PWM_MIN;
  if(pos2 > PWM_MAX) pos2 = PWM_MAX;
  if(pos2 < PWM_MIN) pos2 = PWM_MIN;
  // Print the current servo position to the serial port.
  printf_P(PSTR("%d\r\n"), pos1);
  printf_P(PSTR("%d\r\n"), pos2);
  return 0;
  }
  That is why your code shows up that way. The pound sign at the define and include statements tell the forum software you want that text as header1.
  To prevent that, precede each line of your code with 4 spaces. This will format the text as code as shown below.
  #include "../libnerdkits/lcd.h"
  If you follow the linke at the bottom of the page, you'll find more neat things you can do.
  Rick
  AHAH!!!
  Now I get it!
  The trouble I have is that the instructions get a bit wordy for my ADD to deal with so I end up skimming rather than reading.
  Little chunks at a time like what you just showed me are what it takes. Thanx, Rick.
  Now on to the next project...
  Here is a short video of the 2 servos in operation on the desk. The circuit is running a script in real time from the PC.
  Next step is to get the radio link to work right. (A little help Jim?)
  2 servos and an LED
  Please log in to post a reply.