Código MPU6050 + sensores i2c + serial

Hola!
Es mi primer post en el foro, hace un tiempito conozco arduino y hice algunas cosas, pero es la primera vez que me acerco a este recurso, que tanto me ayudó con el simple hecho de leer y leer.

Vamos a lo concreto: Estoy haciendo una estabilizadora de vuelo, basada en la librería de Jeff Rowberg, usando también PID (aunque por ahora, el D es 0 :wink: ), y dos servitos sosteniendo el sensor...
Fui un poco mas allá y le conecté un jostick, para simular lo que sería una futura conexión con un receptor Rc, por más que sean cosas distintas, quería ver como se comportaba. Obtuve muy lindos resultados, así que di otro paso: Probar conectar otros sensores i2c en simultaneo, ejecutar todo, y escribir el Serial con la info del sensor, así que preparé la conexión con un sensor de temperatura mlX90614, con correspondientes librerías.
El código que noto más abajo corresponde a todo lo anterior + lectura y envio de la temperatura mediante el serial usb.
Parecía venir todo bien, cuando oh sorpresa, entre ambos dispositivos suele haber una especie de "interferencia", que causa errores en la medición, tilda el arduino, el mpu se vuelve loco. Las conexiones están bien hechas, SALVO EL DETALLE QUE NO TENGO NINGUNA PULLUP CONECTADA
Creo que esto tiene bastante que ver, lo que sería mi primera consulta, si es posible que no tener pullups, influya.
Segunda cosa: Noto que el envio del dato mediante el serial, ralentiza bastante el proceso de la reacción del PID, que cambia su conducta y comienza a sobreoscilar. Mientras más escriba al Serial, peor....
EL CODIGO

#include <PID_v1.h>
#include "I2Cdev.h"
#include <Servo.h>;
#include <Adafruit_MLX90614.h>
Servo Ala1;
Servo Stab;
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
MPU6050 mpu;
#define OUTPUT_READABLE_YAWPITCHROLL
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
int potX = 1;
int potY = 0;
int puls = 2; 
int JoyX, JoyY;
double Setpoint, Input, Output;
double SetpintX, InX, OuX;
double Kp=0.6, Ki=5, Kd=0;
double Xp = 1, Xi = 5, Xd = 0;
PID pdX(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
PID pdY(&InX, &OuX, &SetpintX, Xd, Xi, Xd, DIRECT);
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

void setup() {
  Serial.begin(115200);
  Ala1.attach(9);
  Stab.attach(10);
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz). Comment this line if having compilation difficulties with TWBR.
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif
    mpu.initialize();
  pdY.SetSampleTime(10);
  pdY.SetOutputLimits(45, 135);
  pdY.SetMode(AUTOMATIC);
  pdX.SetMode(AUTOMATIC);
  pdX.SetSampleTime(10);
  pdX.SetOutputLimits(45, 135);
  pdX.SetControllerDirection(DIRECT);
  mlx.begin();

    devStatus = mpu.dmpInitialize();

    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(220);  // CALIBRAR TODOS ESTOS VALORES
    mpu.setYGyroOffset(76);  // CALIBRAR TODOS ESTOS VALORES
    mpu.setZGyroOffset(-85);  // CALIBRAR TODOS ESTOS VALORES
    mpu.setZAccelOffset(1688); // CALIBRAR TODOS ESTOS VALORES

    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {
        mpu.setDMPEnabled(true);
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        dmpReady = true;
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {

    }

}
void loop() {
  Serial.println(mlx.readObjectTempC());
    if (!dmpReady) return;

    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
        // other program behavior stuff here
        // .
        // .
        // .
        // if you are really paranoid you can frequently test in between other
        // stuff to see if mpuInterrupt is true, and if so, "break;" from the
        // while() loop to immediately process the MPU data
        // .
        // .
        // .
    }

    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

    }
      ejecucion (); 

}
int ejecucion () {
JoyX = analogRead(potX);
JoyY = analogRead(potY);
Input = ((ypr[2] * -180/M_PI)+90);
SetpintX = map(JoyY, 0, 1023, 0, 180);
           pdX.Compute();
           int Ss1 = map(Output, 45, 135, 135, 45);
           Ala1.write(Ss1);
           //Serial.println(map(Output, -90, 90, 0, 180));
InX = ((ypr[1] * -180/M_PI)+90);
Setpoint = map(JoyX, 0, 1023, 0, 180);
           pdY.Compute();
           int Ss2 = map(OuX, 45, 135, 135, 45);
           Stab.write(Ss2); 
}

Mi consulta es si esto se puede optimizar o tiene alguna peculiaridad, porque si mi pretensión es incluir presion barometrica, gps, y radioenlace para telemetria, ni andaría :o :o :o
El codigo, funciona. Pero requiere tocar esos detaller, pienso que viene bien encaminado, pero totalmente abierto a opiniones, criticas, todo bienvenido!
Desde ya, muchas gracias

Elcapo321:
Las conexiones están bien hechas, SALVO EL DETALLE QUE NO TENGO NINGUNA PULLUP CONECTADA

Prueba añadiendo los pull-up. Se usan para estabilizar señales digitales. Sin estos, los cambios (o lecturas) de estado de un pin, tienden a ser aleatorios e inestables.

Mientras más escriba al Serial, peor....

Es obvio. Cuantas más cosas tenga que hacer el microprocesador, más se queda rezagado cuando de atiempamientos se trata (excepto si se usan interrupciones, pero eso ya es un tema muy avanzado).

Si no es para comunicación, entonces el puerto serial se está usando para depuración solamente.
Ya si del todo no lo utilizas, elimina o comenta la siguiente línea:

Serial.begin(115200);

No estoy seguro si la tasa de baudios genera directamente carga al procesador. Si así lo fuera, entonces sería otro factor más a tomar en cuenta.

Y... hasta aquí mi crítica (constructiva, por supuesto :smiley: )

Las generalidades como hablar de pull-ups y no decir donde? no me parecen apropiadas.
Habla en concreto.
Haz un esquema de todo lo usado a menos que esto que entiendo es tu esquema este correcto:
Arduno (no dices cual) +Código MPU6050 + mlX90614 + Joystick
viendo la hoja de datos del mlX90614 me cabe preguntarte si lo tienes en módulo o como elemento.

Entonces en el caso de multiples dispositivos, se ve que no hace falta usar resistencias PULL UP ya que se usa las presente en el otro dispositivo, en este caso el MPU6050.

Asi que habría que ver en detalle tu código que es algo complejo por cierto.

Lucario448:
Prueba añadiendo los pull-up. Se usan para estabilizar señales digitales. Sin estos, los cambios (o lecturas) de estado de un pin, tienden a ser aleatorios e inestables.

Lucario: En estos días voy a conseguir las resistencias y probar, a ver como reacciona. Sobre el Serial, encontré que a mayor velocidad en Baudios, menos sobreoscila (o lo hace más rapido)
Sobre las Interrupts, no creo que me sirvan de momento, quizás para encender o apagar el estabilizador, con un canal de la radio, pero será cuando disponga los otros elementos, o el Rc acá en casa

surbyte:
Las generalidades como hablar de pull-ups y no decir donde? no me parecen apropiadas.
Habla en concreto.
Haz un esquema de todo lo usado a menos que esto que entiendo es tu esquema este correcto:

Bien bien, mal de mi parte no aclarar ni siquiera que arduino estoy usando, ni siquiera un pequeño esquema... La verdad, gran detalle que se me pasó, pero me sirve para aprender a manejarme con esto...
Adjunto un esquema, intenté que fuera lo más prolijo y detallado posible (El serial lo leo mediante USB), el arduino es un UNO R3, tanto el MPU como el Sensor MLX vienen ya en módulos armados, de ahí mi duda:
Las resistencias incluidas en el MPU 6050 sirven como "generales"?? Que pasa si pruebo con agregar otras, de forma que tengo entendido que las Pull-ups van en el cableado correspondiente a SDA y SCL; estuve leyendo para concretarme en un valor definido para las resistencias.
Por ahora, la complejidad del código, es bastante cierta. Se me hace que la primera parte del LOOP, donde se chequea el DMP y esas cosas, pueden estar atrasando bastante, pero creo que son totalmente necesarios para una buena lectura del buffer del MPU....
Voy a seguir probando, luego de que pruebe con añadir las resistencias, ya que tendría que dejarlo listo, en primera instancia, para que funcione como estabilizador,
Como mencioné antes, mi idea es que haga unas cuantas funciones más, tengo un GPS, Sensor Barometrico y Radioenlaces 2.4 ghz en camino a casa, pero falta mucho para que lleguen...
Será posible que el ardu se banque leer/corregir servos/mandar telemetria? Tengo que considerar alguna plaqueta mas "polenta2? (Seguramente utilice el Mega por el tema puertos Serial...)

Muchas gracias!

Hola.
Creo que traté hace tiempo un problema similar de ralentización de un programa por el uso del puerto serie.
Echa una ojeada a este hilo a ver si entiendes el problema que se está produciendo. Si te queda alguna duda, postéala por aquí.
Saludos.

No hace falta mirar ninguna resistencia.
Tu módulo MPU6050 ya las tiene, y aunque el mlX90614 no las tenga, no significa que debes usar otras resistencias pull up porque terminas teniendo un paralelo de resistencias y comprometes todo el BUS I2C.
Te lo puse claramente en mi posteo anterior.

noter:
Hola.
Creo que traté hace tiempo un problema similar de ralentización de un programa por el uso del puerto serie.
Echa una ojeada a este hilo a ver si entiendes el problema que se está produciendo. Si te queda alguna duda, postéala por aquí.
Saludos.

Perfecto, lo implementé en el código y no tuve problemas, incluso probando a velocidades de 9600 baudios, cosa que antes era incontrolable

surbyte:
No hace falta mirar ninguna resistencia.
Tu módulo MPU6050 ya las tiene, y aunque el mlX90614 no las tenga, no significa que debes usar otras resistencias pull up porque terminas teniendo un paralelo de resistencias y comprometes todo el BUS I2C.
Te lo puse claramente en mi posteo anterior.

Muchas gracias por sacarme las dudas!
El proyecto queda en stand by hasta la llegada del rc y de los demás componentes, cualquier cosa vuelvo a comentarles, y el día que el proyecto funcione correctamente, seguro arme otro hilo presentándolo adecuadamente, para el que lo necesite
Saludos!

No armes otro hilo.
Desde mi punto de vista ya comenzaste con tu proyecto.
Cambiale el título y si quieres te muevo el hilo a Proyectos y le das continuidad e incluso lo describes mejor si lo crees necesario.
Es importante que las cosas tengan historia como en este caso, resultan mas beneficiosas para los demás.