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
), 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

