Hola,
Llevo un tiempo haciendo un drone (que está de moda) de tres rotores y he logrado hacerlo volar de manera decente con varios sensores y de forma muy sencilla.
- GY-85: ADXL345, ITG3205, HMC5883L -> I2C, Pines A4 y A5
- Receptor RX de 6 canales (PPM) -> Pin 2
- ESC + Motores sin escobillas (PWM) -> Pines 3, 5 y 6
Bien, hasta aquí no he tenido demasiados problemas.
Ahora lo que quiero es ampliar su funcionamiento añadiéndole un GPS y un módulo BT para poder enviarle a través del móvil varios comandos para hacer diferentes tareas, es decir, básicamente convertir el BT en la consola de comandos y de debug (obviemos el hecho de que el rango del BT es muy pequeño)
Receptor GPS: UBlox 6M. Se conecta a través de puerto serie. Configurado a 38400 baudios y una frecuencia de 5hz (200ms)
Módulo BT: HC-05. Se conecta a través´ de puerto serie. Lo puse a 57600.
Intenté conectar ambos usando la librería SoftwareSerial que en principio parecía muy prometedora, pero tuve problemas y esq, por lo visto, la librería no puede trabajar con esos baudrate y la información del GPS llega cortada y/o nisiquiera recibe los comandos que envío a través del BT.
Podéis echar un vistazo de como llegamos a esta conclusión en este post: GPS (uBlox) a través de BLUETOOTH HC-05 - Software - Arduino Forum
GPS pines 8 y 9 (en verdad 8 ya que no necesito enviar datos)
BT pines 10 y 11 (aquí sí que necesito ambos pines)
He probado con AltSoftSerial, la verdad es que ha mejorado mucho la recepción del GPS pero aún así no me vale para el BT.
Aquí viene una idea que he tenido q lo mismo no se puede hacer, y es donde vienen mis dudas.
Pretendo conectar dos Arduinos. Uno de ellos tendría el GY-85 y el GPS (es decir, una IMU como tal) que enviaría la información cada X ms. Esta información sería el YPR y la información del GPS que me pueda interesar (LONG, LAT, TIME, etc).
Con la IMU no tendría problemas ya que el GY85 iría por I2C (SCL/SDA) y podría usar la AltSoftSerial para la conexión del GPS.
Esta información la encapsularía y la enviaría a través del puerto serie con un Serial.write o Serial.print según me interesase.
Bien, entiendo que ambos arduinos los tendría que conectar por el puerto serie ¿no? No existe otra manera de mandarse información entre ellos ¿no?.
Si fuese así, entiendo que en principio perdería el poder programarlos como he hecho hasta ahora, por el puerto serie. ¿Qué otras formas hay de cargar un sketch al arduino?
En el segundo arduino (el que NO es el IMU), entiendo que el "Serial.read()" me daría la info del IMU ¿correcto? Por lo que a través de la libería de SoftwareSerial o AltSoftSerial conectaría el BT y podría ver la información que envía y enviarle comandos a través del BT ¿es correcto?
He llegado a este punto porque creo que NO es posible conectar "todo a la vez" en un único Arduino.
Sé que existe el Arduino Mega que lleva varios puertos serie y sería mejor y mucho más simple para esto, pero tengo sobrepoblación de Arduinos Unos y me gustaría exprimir esta opción
Os dejo el código del sketch principal, el resto son librerías.
#include <Arduino.h>
#include <Wire\Wire.h>
#include <ServoTimer2\ServoTimer2.h>
#include <AltSoftSerial\AltSoftSerial.h>
//#include <SoftwareSerial\SoftwareSerial.h>
#include <TinyGPS\TinyGPS.h>
#include "ADXL345.h"
#include "ITG3205.h"
#include "HMC5883L.h"
#include "AHRS.h"
#include "ESC.h"
#define ANGLE(x,y) (degrees(atan2(x,y))
#define RC_PIN 2
#define RC_CHANNELS 6
int rcData[6] = { 1500, 1500, 1500, 1500, 1500, 1500 }; // interval [1000;2000]
bool failSafe = false;
void readSerial();
void processCommand(char* command);
void readPPM();
void getSensorData();
void getYawPitchRoll();
void getComplementaryFilter();
void getAHRS();
void printYPR();
ADXL345 accel;
ITG3205 gyro;
HMC5883L magn;
AHRS ahrs;
ESC motors;
AltSoftSerial gps;
TinyGPS gpsParser;
bool newGPSData = false;
unsigned long gpsChars;
unsigned short gpsSentences, gpsFailed;
long gpsLastRead = 0;
//FAILSAFE COUNTER
long lastFailSafe = 0;
long failSafeTh = 900;
//SERIAL PRINTDATA
float ypr[3] = { 0.0f, 0.0f, 0.0f };
long samplePeriod = 20;
long lastSamplePeriod = 0;
long lastSampleTime = 0;
long lastSamplePrint = 0;
// Complimentary filter
float ALPHA = 0.2;
float GYRO_GAIN = 1;
float ACCEL_GAIN = 1;
int step = 0;
//Commands
char command[100];
char commandId[10];
byte commandIndex;
int now, diff;
int main()
{
init();
Wire.begin();
Serial.begin(38400);
Serial.println("Ready");
gps.begin(38400);
accel.initAccel();
accel.calibration();
accel.printOffsets();
gyro.init();
gyro.calibration();
gyro.printOffsets();
magn.init();
//magn.calibration();
//magn.printOffsets();
//RC
pinMode(RC_PIN, INPUT);
attachInterrupt(0, readPPM, RISING);
////ESC
motors.initESC();
motors.setupESC();
for (;;)
{
lastSampleTime = micros();
//YPR
getYawPitchRoll();
//COMMANDS
readSerial();
//MOTOS
motors.setMotorSpeed(1, rcData[0]);
motors.setMotorSpeed(2, rcData[1]);
motors.setMotorSpeed(3, rcData[2]);
////GPS
//if (gps.available())
//{
// char chr = gps.read();
// gpsParser.encode(chr);
//}
//printYPR();
}
return 0;
}
void readPPM()
{
static int last = 0;
static int chann = 0;
now = micros();
sei(); //Enable Interrupts
diff = now - last;
last = now;
if (diff > 3000)
{
chann = 0;
}
else if (900 < diff && diff < 2200 && chann < RC_CHANNELS)
{
//Only if the signal is between these values it is valid, otherwise the failsafe counter should move up
rcData[chann] = diff;
chann++;
failSafe = false;
}
else if (diff < failSafeTh)
{
//TODO: Si los ultimos 10 son < failSafeTh, failSafe = true
failSafe = true;
lastFailSafe = now;
}
}
void readSerial()
{
char charRecv;
while (Serial.available())
{
charRecv = Serial.read();
if (charRecv == '\n')
{
// Termino el string
command[commandIndex] = '\0';
processCommand(command);
//Inicializo el string
commandIndex = 0;
command[0] = '\0';
}
else
{
command[commandIndex] = charRecv;
commandIndex++;
}
}
}
void getYawPitchRoll()
{
//YPR
lastSamplePeriod = micros() - lastSampleTime;
getSensorData();
getComplementaryFilter();
lastSampleTime = micros();
}
void getSensorData()
{
switch (step)
{
case 0:
//ACCEL
accel.getAngleData();
step++;
break;
case 1:
//GYRO
gyro.getDSData();
step++;
break;
case 2:
//MAGN
magn.getClearRawData();
step = 0;
break;
default:
break;
}
}
void getComplementaryFilter()
{
//if (lastSamplePeriod > samplePeriod * 1000)
//{
ypr[0] = ALPHA * (ypr[0] + (gyro.dsData[0] * GYRO_GAIN) * ((float)(micros() - lastSampleTime) / 1000000)) + (1.0f - ALPHA) * (accel.angleData[0] * ACCEL_GAIN);
ypr[1] = ALPHA * (ypr[1] + (gyro.dsData[1] * GYRO_GAIN) * ((float)(micros() - lastSampleTime) / 1000000)) + (1.0f - ALPHA) * (accel.angleData[1] * ACCEL_GAIN);
//}
}
void printYPR()
{
long now = micros();
if (now - lastSamplePrint > 1000000)
{
lastSamplePrint = now;
//float flat, flon;
//unsigned long age;
//gpsParser.f_get_position(&flat, &flon, &age);
//gpsParser.stats(&gpsChars, &gpsSentences, &gpsFailed);
Serial.print((int)ypr[0]);
Serial.print("\t");
Serial.print((int)ypr[1]);
Serial.print("\t");
Serial.print((int)ypr[2]);
Serial.print("\t");
//Serial.print("CHARS=");
//Serial.print(gpsChars);
//Serial.print("\t");
//Serial.print("SENTENCES=");
//Serial.print(gpsSentences);
//Serial.print("\t");
//Serial.print("CSUM ERR=");
//Serial.print(gpsFailed);
//Serial.print("\t");
//Serial.print("LAT=");
//Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
//Serial.print(" LON=");
//Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
//Serial.print(" SAT=");
//Serial.print(gpsParser.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gpsParser.satellites());
//Serial.print(" PREC=");
//Serial.print(gpsParser.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gpsParser.hdop());
Serial.print(diff);
Serial.print("\t");
Serial.print(lastSamplePeriod);
Serial.print("\t");
Serial.println("");
}
}
}