Servo and Serial

Hi everyone.

I am an beginner in Arduino programming but I have some experience with other microcontroller platforms.

What I want to do is to control 12 Servos on my Arduino mega 2560. And I want to send/receive data over the serial port.
I use Arduino IDE 1.0.1 on Ubuntu 12.04 but I also tried to use version 0023 but the problem was always the same.

I spent quite a long time searching, but i cant get it to work properly. The servo control works, but only when i dont have serial communication enabled.
As far as I know this happens because the serial library disables interrupts. I found a software servo library but it seems to be limited to 2 servos.

I used the sweep sample and modified it for testing. As soon as I call Serial.begin(xxx); (any baudrate) the servo stops moving.

Is there a way to control 12 servos and use serial communication?

#include <Servo.h>

//Servos:
Servo ShoulderVL;
Servo ElbowVL;
Servo WristVL;
Servo ShoulderVR;
Servo ElbowVR;
Servo WristVR;
Servo ShoulderHL;
Servo ElbowHL;
Servo WristHL;
Servo ShoulderHR;
Servo ElbowHR;
Servo WristHR;

int pos;  //dummy movement

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(19200);
  //Serial.print("Test");
  servosetup();
  
  //Serial.println();
  //Serial.println("Send inputs to execute servo movement");
}

void loop() {
  //if(Serial.available() > 0) {
  //  s1 = Serial.read();
 // }
  
  dummymovement();
}

void dummymovement() {
 digitalWrite(13, HIGH);
 for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
  {                                  // in steps of 1 degree
    //Serial.print(pos);
    //Serial.println();
    ShoulderVL.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
  {         
    //Serial.print(pos);
   // Serial.println();    
    ShoulderVL.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);   
  }
  ShoulderVL.write(180);
  digitalWrite(13, LOW);
}

void servosetup() {
  ShoulderVL.attach(0);
  ElbowVL.attach(1);
  WristVL.attach(2);
  ShoulderVR.attach(3);
  ElbowVR.attach(4);
  WristVR.attach(5);
  ShoulderHL.attach(6);
  ElbowHL.attach(7);
  WristHL.attach(8);
  ShoulderHR.attach(9);
  ElbowHR.attach(10);
  WristHR.attach(11);
}

Many thanks for your help :slight_smile:

Kind regards
Alex

Is there a way to control 12 servos and use serial communication?

Sure, but you should slow down and first get one or two servos moving first. What code have you tried that works?

for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees

Either make the comment meaningful and/or accurate, or don't bother with it at all.

That code works when i comment out everything that does something with serial.
The documentation tells me that the servo library can control 12 servos at once. I am still waiting for the servos to arrive.

The problem is, that the servo stops moving as soon as i call Serial.begin(). So when serial and servos dont work together the arduino board is not suitable for my project and i have to switch to something different...

Make the comment meaningful? Well... its mostly the sample servo project from arduino.cc and i did not remove the comments...

Hi.

I solved the problem by throwing the servo library out the window and using PWM instead.
The Mega2560 has enough pins that support pwm for my project and this version seems to work with serial communication enabled.
The downside is that I can not use the full range of the servo movement. I can only adjust the angle between 0 and somewhat around 120 degrees instead of 180 like i could with the servo library.
This is okay for my project because i just have to move between 0 and 60 degrees.

I wrote a quick-and-dirty function for servo controlling:
ANGLE_0 and ANGLE_90 are the PWM values where the servo reached 90 or 0 degrees.
This values seem to depend on the servos. For my Hitec hs-303 Servos the values 75 and 180 work.
I am still waiting for the other servos to arrive so i can test this with 12 servos for real.

void writeServo(int pin, int angle) {
  int pwm=0;
  if((pin >= 2) && (pin <= 13) && (angle >= 0) && (angle <= 90)) {
      pwm = map(angle, 0, 90, ANGLE_0, ANGLE_90);
      analogWrite(pin,pwm);    
  }
}

-Alex

I solved the problem by throwing the servo library out the window and using PWM instead.

But you reduced the PWM frequency, didn't you?

PWM frequency is somewhat around 500 hz according to this thing here: http://arduino.cc/en/Main/ArduinoBoardMega2560

I just did what I wrote in that code snippet in my last post.

PWM frequency is somewhat around 500 hz

...and the servo expects PWM at almost exactly 1/10th that frequency.

I did a quick search on changing the PWM frequency.
It seems that this influences the timers that are used by commands like delay and the serial communication again.
So I guess it is not possible to change that (because erverything else stops working right?).

I also noticed that pins 4 and 13 on the board seem to run on much higher frequencys... so i cant use them.
The page about the mega2560 sais that it also provides pwm on pins 44-46.
But when i look on the pin mapping page of the 2560 it is very different :frowning:

It seems that there is much information on that boards that contradicts each other...

So my question is this:

  1. Is it possible to control 12 servos on the mega2560 without conflicting with timers, serial communication etc?
  2. which and how many pins do provide pwm output?

At the moment it looks like it is not possible to have 12 pwm outputs without changing behavior of serial communication or timers so maybe I just go back to my old hcs12 board and throw the mega out the window :frowning:

I don't have a Mega, but the Servo library notes say that 12 servos are supported for the standard Arduino, and 48 are supported for the Mega.
Personally, I have had no problems with eight servos and serial on a Nano.

The Servo library works fine for 12 Servos as i mentioned in my first post (i used one servo and plugged it in the different pins).

The problem is that I want to send commands to the arduino over the serial port to control the servos.
And the serial and servo library just dont work together. So as soon as i start a serial port, all servos stop and only serial communication is working.
There are samples on arduino.cc liek this one: Arduino Playground - SingleServoExample
but these samples are just not working. at least on the mega2560.

I hope there is a way to get that working.

The problem is that I want to send commands to the arduino over the serial port to control the servos.
And the serial and servo library just dont work together. So as soon as i start a serial port, all servos stop and only serial communication is working.

The below code works on my computer to control servos via the serial port.

// zoomkat 10-22-11 serial servo test
// type servo position 0 to 180 in serial monitor
// or for writeMicroseconds, use a value like 1500
// for IDE 0022 and later
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control 
  Serial.println("servo-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string 
    int n = readString.toInt();  //convert readString into a number

    // auto select appropriate value, copied from someone elses code.
    if(n >= 500)
    {
      Serial.print("writing Microseconds: ");
      Serial.println(n);
      myservo.writeMicroseconds(n);
    }
    else
    {   
      Serial.print("writing Angle: ");
      Serial.println(n);
      myservo.write(n);
    }

    readString=""; //empty for next input
  } 
}

Oh my... Sometimes it is just better to stay in bed i guess :blush:

I got it all working now... I somehow did not see that pin 0 and pin 1 are connected to the usb-serial converter on the board.
I used those pins during testing.

I am soooo stupid xD

Thank you guys for your help :slight_smile:

zoomkat:
The below code works on my computer to control servos via the serial port.

// zoomkat 10-22-11 serial servo test

// type servo position 0 to 180 in serial monitor
// or for writeMicroseconds, use a value like 1500
// for IDE 0022 and later
// Powering a servo from the arduino usually DOES NOT WORK.

String readString;
#include <Servo.h>
Servo myservo;  // create servo object to control a servo

void setup() {
 Serial.begin(9600);
 myservo.writeMicroseconds(1500); //set initial servo position if desired
 myservo.attach(7);  //the pin for the servo control
 Serial.println("servo-test-22-dual-input"); // so I can keep track of what is loaded
}

void loop() {
 while (Serial.available()) {
   char c = Serial.read();  //gets one byte from serial buffer
   readString += c; //makes the string readString
   delay(2);  //slow looping to allow buffer to fill with next character
 }

if (readString.length() >0) {
   Serial.println(readString);  //so you can see the captured string
   int n = readString.toInt();  //convert readString into a number

// auto select appropriate value, copied from someone elses code.
   if(n >= 500)
   {
     Serial.print("writing Microseconds: ");
     Serial.println(n);
     myservo.writeMicroseconds(n);
   }
   else
   {  
     Serial.print("writing Angle: ");
     Serial.println(n);
     myservo.write(n);
   }

readString=""; //empty for next input
 }
}

Was extremely helpful thx