Servo vs. GPS - Timer Problem?

Hi all,

I need some help for my first project. I know this Problem, using a servo and a GPS sensor, is I guess well known. I found a few discussion already. Unfortunately never a solution which worked with my setup.

Problem:
The Servo jitters as soon I pickup GPS data.

Components:

  • Arduino Uno Rev. 3
  • Servo Vilros SG90
  • Adafruit Ultimate GPS Breakout v3

SW Components:

  • Adafruit GPS Library example: "parsing" OR TinyGPSplus-0.94b Library example: "DeviceExample"
    and
  • servo Library example: "sweep" OR servoTimer2 Library example: "servoTimer2"

What I know so far:
Both GPS Libs are using an interrupt to read GPS signals. That interrupt stop's also my PWM signals for the servo, therefore the servo starts to jitter, because it receives random signals. The arduino UNO has three timers I could use. Now it gets loose: It looks like the Adafruit GPS Lib is useing timer1 for UNO boards, therefor I tried to use timer2 Lib for my servo. But I have the same Problem as before.

I tried a lot of different ideas, the timer2 was my biggest hope and often mentioned in other forum topics.

Can somebody help? Thx so much.

How are you powering the servo?
Always use a separate power supply for motors and servos.

I used the 5V Arduino Board output for GPS and Servo. With a separate power supply for the servo the problem still occur.

Can you move the GPS to the hardware serial?

Yes, I already tried this. Problem is, it looks like the Adafruit GPS example "parsing" crashes as soon as I comment out the line:

//SoftwareSerial mySerial(3, 2);

and enable:

HardwareSerial mySerial = Serial1;

and modify to:

HardwareSerial mySerial = Serial;

I get a compiler error if I use "Serial1". I guess Serial1 is for MegaBoards.

Got this answer from adafruit support:

It is more than just a simple timer conflict. It is a case of what is called "interrupt contention" When one interrupt comes in, the processor disables other interrupts until the first interrupt is handled. Then the other interrupt is allowed to proceed.
So if the servo timer interrupt occurs while handling a software serial interrupt, the servo timer may be delayed by a microsecond or two. The problem is that the servo pulse timing needs to be very precise and even a couple of microseconds delay can cause servo 'jitter'.
The options are to use hardware serial or to offload the servo timing to a dedicated servo controller like the PWM/Servo Shield or Breakout.

I ordered a motor shield today. Guess this is the only solution.

I am having the same problem. I am using an Adafruit HUZZAH ESP8266. I have a Parallax 16x2 LCD and an Ultimate GPS connected to the ESP8266. I also have two servos, on a separate power supply, connected to the ESP8266. The two servos and the LCD work fine together. When I introduce the Ultimate GPS, I get a 1hz servo jitter.

Unless anyone has any better ideas, I am going to order the servo breakout to stop the jitter.

A possible solution is to use the Atmega 328P's phase and frequency correct PWM instead of the servo library. As this hardware PWM isn't interrupt driven it should be unaffected by jitter caused by the GPS.

Phase and frequency correct PWM uses the 16-bit Timer1. This means that you can't simultaneousely use libraries that require this timer. On the Uno timer1 outputs are on digital pins 9 and 10, enough to drive two servos. As its name suggests, phase and frequency correct PWM allows control over the PWM frequency and it's possible to drive the servos at 50Hz with a 14-bit resolution.

The following code controls two servos with a 50Hz PWM signal on D9 and D10:

void setup() { 
  // Initialise timer 1 for phase and frequency correct PWM
  pinMode(9, OUTPUT);                         // Set digital pin 9 (D9) to an output
  pinMode(10, OUTPUT);                        // Set digital pin 10 (D10) to an output
  TCCR1A = _BV(COM1A1) | _BV(COM1B1);         // Enable the PWM outputs OC1A, and OC1B on digital pins 9, 10
  TCCR1B = _BV(WGM13) | _BV(CS11);            // Set phase and frequency correct PWM and prescaler of 8 on timer 1
  ICR1 = 20000;                               // Set the PWM frequency to 50Hz
  OCR1A = 1500;                               // Centre the servo on D9
  OCR1B = 1500;                               // Centre the servo on D10
}

void loop() {
  OCR1A = 1000;                               // Move the servo to min position on D9  
  OCR1B = 1000;                               // Move the servo to min position on D10
  delay(1000);                                // Wait for 1 second
  OCR1A = 2000;                               // Move the servo to max position on D9
  OCR1B = 2000;                               // Move the servo to max position on D10
  delay(1000);                                // Wait for 1 second
}

Just load the OCR1A or the OCR1B registers with the value in microseconds you'd like to send to each servo, for example to center the servo just load 1500, minimum 1000 and maximum 2000.

I started out with the Adafruit (Mediatek) GPS, but eventually switched to uBlox. uBlox allows communication over the serial port with their proprietary UBX protocol. This protocol sends fixed length data packets that can be loaded directly into a structure in your sketch and is far less computationally expensive than parsing a variable length NMEA string. I found this video on Youtube really helpful: 10Hz U-blox binary GPS data in 66 lines of code (arduino) - YouTube

MartinL,

Could your oscillator code be used to solve this problem?

Hi Bertolli,

Could your oscillator code be used to solve this problem?

The advantage of using hardware PWM is that it works independently of the CPU. Once you've loaded the OCR1x registers with your required duty cycle, it will continue outputting that duty cycle at the specified frequency irrespective of processor load.

The servo library on the other hand is software driven. It can cause jitter on the outputs if the processor is unable to service servo outputs quickly enough.

That's not to say it's not possible to experience jitter with hardware PWM, but the cause will be further upstream in the code that's controlling the PWM output to the servo, not the hardware PWM itself.

Hi,

Thanks Martin, do you think this problem be solved if GPS is connected to the UNO HW serial pins 0/1? I haven't seen any example code that is able to move servo according to gps data for example according to gps speed on UNO board. Read GPS serial -> parse speed -> convert it to servo position...seem simple but in reality, for UNO, this seems very difficult. I'd be very delighted if someone could give functioning example code how to get this work.

Read GPS serial -> parse speed -> convert it to servo position...seem simple but in reality

It is. With the right hardware.

for UNO, this seems very difficult.

Only if you need the Serial instance for something else.

To Paul S:

So is it so that if I use the UNOs HW serial for GPS I will not have these servo issues? Actually I don't need to use computer serial monitor or LCD at the same time. Any advice/example code?

So is it so that if I use the UNOs HW serial for GPS I will not have these servo issues?

You won't have servo issues related to SoftwareSerial taking too much time. Whether you have other servo issues, or not, remains to be seen.