Problems with my servo while using the Wire.h Library.

Since I'm using a sensor that communicates with the Arduino via I2C, I'm having problems trying to use the Servo library that comes by default with Arduino IDE. I know both libraries uses the same timer (No. 1), and then I tried to find out if there is other library out there that can use other timer. Then I found ServoTimer2 library, but it didn't work. The Servo was doing the same thing but slower, making the same movement step by step.

So my question is, can the Arduino Uno (ATmega 328P) work with an I2C connection and a Servo at the same time? Does the Arduino Mega have the same issue or solve this problem?

I really want to know this before implementing a board with 2 ATmegas 328P in the worst case. So, one of them can control a DC motor plus a Servo, and the other one process the information that the sensor is giving. Finally, I can comunicate them via UART.

So my question is, can the Arduino Uno (ATmega 328P) work with an I2C connection and a Servo at the same time?

Yes.

The Servo was doing the same thing but slower, making the same movement step by step.

You want us to guess what that means? Doing what thing? The same as what?

Does the Arduino Mega have the same issue

If "the same issue" is Wire and Servo using the same timer, yes.

Hi Paul, thanks for your kind answer. Sorry for not being specific. I want my servo to make a movement to an angle, so for the same thing I mean it was going crazy. In my code I'm telling the servo to make an angle, but it was doing the angle and a second later it was making another angle, and then it was making the same angle as before. So when I was using ServoTimer2 it was doing this too, but slower. Like step by step. Sorry for my bad english. And well, I'm correcting my first question. Can they work together without any problem as the one I'm getting? Because I know it is working, but not as I'm specting. Do you recommend using 2 ATmegas 328P for better performance, since the Mega have the same issue?

Can you post your code? You should be able to move the servo to a position, and have it stay there, using either Servo or ServoTimer2. If Servo interferes, because of re-purposing a timer, then ServoTimer2 can be used, and should behave the same as Servo.

You should not need two Arduinos.

Hi Paul, sure. This is my code:

#include <ServoTimer2.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <TinyGPS++.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_10DOF.h>

Adafruit_10DOF                dof   = Adafruit_10DOF();
Adafruit_LSM303_Mag_Unified   mag   = Adafruit_LSM303_Mag_Unified(30302);

static const int RXPin = 5, TXPin = 6;
double latitud, longitud, distancia, angulo, complat[50], complon[50]; 
double Setpoint, Input, Output, Kp = 1, Ki = 0, Kd = 1;
int orientacion;

TinyGPSPlus GPS;
SoftwareSerial GPSData(RXPin, TXPin);
ServoTimer2 DirMot;

void initSensors()
{
  if(!mag.begin())
  {
    Serial.println("No LSM303 detected");
    while(1);
  }
}

void setup() {
  Serial.begin(9600);
  GPSData.begin(9600);
  initSensors();
  DirMot.attach(2);
  DirMot.write(0);
  complat[0] = 11.016690;
  complon[0] = -74.805919;
//  Input = 0;
//  Setpoint = 0;
//  myPID.SetMode(AUTOMATIC);
}

void loop() {
  while (GPSData.available()>0){
    GPS.encode(GPSData.read());
  }
  if (millis() > 5000 && GPS.charsProcessed() < 10)
  {
    digitalWrite(13, HIGH);
  }
  else {
    digitalWrite(13, LOW);
  }
  if (GPS.location.isValid()){
    latitud = GPS.location.lat();
    longitud = GPS.location.lng();
    digitalWrite(13,HIGH);
  }

  sensors_event_t mag_event;
  sensors_vec_t orientation;
  
  mag.getEvent(&mag_event);
  if (dof.magGetOrientation(SENSOR_AXIS_Z, &mag_event, &orientation)){
    orientacion = orientation.heading;
    
  }

  distancia = (unsigned long)TinyGPSPlus::distanceBetween(latitud, longitud, complat[0], complon[0]);
  angulo = TinyGPSPlus::courseTo(latitud, longitud, complat[0], complon[0]);

  Input = orientacion - angulo;
  if (Input < -1 || Input > 181) {
    //DirMot.write(180);
    
  }
  else if (Input > 1 || Input < 179) {
    DirMot.write(0);

  }
  else {
    //DirMot.write(90);
    
  }

  Serial.print(latitud,6);
  Serial.print(", ");
  Serial.println(longitud,6);
  Serial.print("Angulo: ");
  Serial.println(angulo);
  Serial.print("Orientacion: ");
  Serial.println(orientacion);
  Serial.print("Input: ");
  Serial.println(Input);
  delay(500);
  digitalWrite(13,LOW);
  Serial.print("Distancia: ");
  Serial.println(distancia);
  
}

The thing here is, it changes angle as I said before but step by step. For example, if I want it to be 90 degrees, it goes from 90 to 50 everytime, but step by step.

  while (GPSData.available()>0){
    GPS.encode(GPSData.read());
  }

The encode() method returns a value of true (the last character completed a sentence) or false (the last character was not the last character in a sentence). Why are you ignoring that value?

double latitud, longitud, distancia, angulo, complat[50], complon[50];

Why are complat and complon arrays, when you only use the first element of each?

I only see where you write a position to the servo in one place. I do not see that you wait anywhere for the servo to get to that position. I do not see where you call the ServoTimer2::refresh() method anywhere.

Did you look at the examples that came with the ServoTimer2 library?

To get TinyGPS++ to work, I have to repeatedly funnel the characters to it from the GPS module using the encode() method. I'm not ignoring this value, I'm calling later the GPS object to collect the information from it.

My project it's not done yet, so I have an array to get different destinations, that's why I'm just using one. But the final project it will accept maximum 50 directions.

And yeah, you're right. I didn't add the refresh method after I made the changes. My bad, I will work on it and post my results later this night. Thank you Paul.

Hi Paul, I checked the documentation and there is no ServoTimer2::refresh(), and I'm having the same issue over again. :frowning:

I'm not ignoring this value

The line of code is:

      GPS.encode(GPSData.read());

The encode() method returns a value. You are not storing the value. You are not testing the value. You are, therefore, ignoring the value.

I'm calling later the GPS object to collect the information from it.

You are ASSuming that the GPS instance HAS data to return.

Swagseneyer:
Hi Paul, I checked the documentation and there is no ServoTimer2::refresh(), and I'm having the same issue over again. :frowning:

My bad. ServoTimer2 operates the same as Servo, except with a different timer. I was thinking of SoftwareServo, with it's need to call refresh().

Hi Paul, you can read the documentation of TinyGPS, don't know why the said it's needed the encode method. On the other hand, I've been reading a lot documentation, and seems like the Software Serial Library uses timer 2 too. So I don't know if I can use another timer (seems like not). So, having two microcontrollers doesn't sound pretty crazy right now. What do you think? Any recommendations?