Problema de compatibilidad al usar comunicación serial y modulo SD

Hola chicos, a ver si me ayudan a dar con el problema porque yo me voy a volver loco.
Resulta que en un sistema de control que tengo construido tengo un arduino Uno en donde, entre otras cosas, utilizo un motor PWM y un modulo lector de tarjetas microSD. En este sistema yo le mando una orden por serial y me arranca el motor, y con otra orden me lee un archivo de la tarjeta.
El problema es que si pongo todo esto junto no me funciona, me manda respuestas del serial de comando inválido, pero si elimino la lectura del serial y hago funcionar las os cosas directamente todo funciona bien.
El código con todo es el siguiente:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include "MeanFilterLib.h"
#include "AVR_PWM.h"
#include <SD.h>
#include <SPI.h>
#define _PWM_LOGLEVEL_       1

//Variables servos
Adafruit_PWMServoDriver controlservos = Adafruit_PWMServoDriver();
int tiempo=500;
int angulo = 0;

//Variables Pitot
float V_0 = 5.0; 
float rho = 1.204;
int offset1, offset2, offset3, offset4; 
MeanFilter<float> meanFilter0(10);
MeanFilter<float> meanFilter1(10);
MeanFilter<float> meanFilter2(10);
MeanFilter<float> meanFilter3(10);

//Lectura Serial
int accion=0;
double value1=0; 
double value2=0; 
double value3=0;

//Variables motores
AVR_PWM* PWM_Instance;
float frecuenciaPWMmotor;

//Variables SD
File myFile;

//Variables temporizador
unsigned long actual, inicio, fin, transcurrido;
int activreloj=0;

void setup() {
  Serial.begin(9600);
  Serial.print("Iniciando SD ...");
  if (!SD.begin(10)) {
    Serial.println("No se pudo inicializar");
    return;
  }
  Serial.println("inicializacion exitosa");
  iniciarPCA9685();
  Serial.println("Iniciando calibración Pitots");
  offset1=pitotoffsetcalibracion(1);
  offset2=pitotoffsetcalibracion(2);
  offset3=pitotoffsetcalibracion(3);
  offset4=pitotoffsetcalibracion(4);
  //iniSD();
  iniciarmotor();
}

void loop() {
if (Serial.available()) {
    String command = Serial.readStringUntil('\n'); // Leer el comando enviado por el puerto serial
     command.trim(); // Elimina espacios en blanco al principio y al final
    // Extraer el comando y el valor (si está presente)
    String task = command.substring(0, command.indexOf(' '));
    command.remove(0, command.indexOf(' ')+1);
    String valueString = command.substring(0,command.indexOf(' '));
    command.remove(0, command.indexOf(' ')+1);
    String value2String = command.substring(command.indexOf(' ')+1);
    command.remove(0, command.indexOf(' ')+1);
    String value3String = command.substring(command.indexOf(' ')+1);
    value1 = valueString.toDouble();
    value2 = value2String.toDouble();
    value3 = value3String.toDouble();

    // Ejecutar la tarea correspondiente al comando recibido
    if (task == "iniciclon") {
      accion = 1;
      }else if (task == "valvula") {
      accion = 2;
      }else if (task == "calibracion") {
        accion = 3;
      }else if (task == "leer") {
        accion = 4;
      }else if (task == "parar"){
        accion = 5;
      }else{
          Serial.println("Comando inválido");
          }
    }
  
  switch(accion){
    case (1):
    Serial.println("Succion activada");
    arranquerampa(1, value1, 1);
    accion = 0;
    break;

    case (2):
    Serial.print("Moviendo servo "); Serial.print(value1); Serial.print(" a posicion ");
    Serial.println(value2);
    setServo(value1,value2);
    accion = 0;
    break;

    case (3):
     Serial.println("Empezando calibración: ");
     //calibracionlecturas(value1);
     accion = 0;
    break;

    case (4):
    Serial.println("Leyendo SD");
    lecturaSD();
    accion = 0;
    break;

    case (5):
    pararmotor();
    Serial.println("Sistema parado");
    accion = 0;
    break;
  }
  
  //float V1=caudalimetro(1,offset1);
  //Serial.println(V1);
  delay(1000);
}

Lo peor es que si le quito toda la parte de la lectura y solo pongo el siguiente codigo en el loop, este funciona perfectamente:

arranquerampa(1, 20, 1);
  delay(1000);
  lecturaSD();
  delay(1000);
  arranquerampa(1, 50, 1);
  delay(1000);
  lecturaSD();
  delay(1000);

Ya no se por donde seguir mirando que puede ser el error.
Aprovecho y pregunto si les gusta esta forma de organizar las ordenes y realizar la lectura del serial, o ustedes lo harían de otra forma.

Un saludo y gracias de antemano

Si tiene delay() , corre el riesgo de perder comandos en el puerto serie, el búfer de recepción es de solo 64 bytes.

falta también un accion = 0; si no se ha reconocido ninguna orden sin duda

   } else {
      Serial.println("Comando inválido");
      accion = 0; // <====
    }

Añadiré lo que me comentas del accion=o.

Con respecto a los delay, a cual de ellos te refieres, estoy un poco verde en el uso del serial.

Si lees inglés, aquí tienes un buen tutorial Serial Input Basics

Algo entiendo, me pongo a leer ya mismo

HI,
Si esta usando el serial pin 0 & 1 tienes que tener cuidado ya que si mandas un mensaje al IDE puedes danar la comunicacion a la parte que estas controlando. Consejo es que uses software serial paraa comunicarte con el control ya que puedes usar otro pines como serial para controlar los motores. Solamente una sugerencia.

Hola tauro, no he entendido lo que has dicho, me lo puedes explicar mejor?

Has un print() de task y las 3 valuex para ver que es lo que estas obteniendo del puerto serial.

Bueno, creo que voy viendo por donde va el problema, reduciendo algunos serial print, y la longitud de los comandos de entrada parece que funciona mejor.
Supongo que eso indica algún tipo de problema de memoria

Bueno, pues comentando todos los serial.print me funciona todo a la perfección. No soy un gran entendido de programación así que me toca ahora ver como reduzco las variables globales que ocupan los serial prints.

No se si dar por zanjada esta consulta de forma parcial, haré lo que me indiquen los moderadores.

Hi,
Primero que nada si no me equivoco estas usando los pines 0=RX 1=TX para controlar los motores. Si es asi entonces esto te puede traer interferencia con el control de los motores ya que estos pines se usan para comunicarse con la computadora atraves del usb cuando envias mensajes. Cuando mandas un mensaje en tu programa ejemplo Serial.print("hello"); estos va a salir por los pines 0=RX 1=TX a la pantalla del IDE. Si usas esos pines para controlar los motores entonces si envias mensajes de status de las lecturas y envias menssajes para controlar los motores como sabes si estos mensajes son de control o mensajes de informacion. Por eso deberias separar los mensajes de los de control usando SoftwareSerial ya que te permita usar otros pines del arduino para comunicacion serial. Esto te permite eliminar el conflictos de los mensajes de informacion y los mensajes de control.. Esto es siempre y cuando uses los pines 0 y 1 para controlar los motores. Si todavia tienes dudas haz un google "using arduino pins 1 and 0". Esta en ingles ya que hay mas infornacion que en espanol. Tanbien puedes buscar informacion de la libraria de software serial.

No encuentro dónde usa los pines 0 y 1 más allá del uso que hace Serial.
¿En cuáles líneas los usa?

Si, acorta los comandos, 3 caracteres son suficientes.
Reusa la variable valueString, obtén el primer valor y conviértelo a float, usa la misma variable para el segundo y tercer valor.
En print() puedes usar la macro F() para las cadenas y liberas algo de memoria.
Por ej.

Serial.println(F("Succion activada"));
1 Like

Muchas gracias MaximoEsfuerzo, me ha servido de mucho tanto las dos soluciones que me has dado. Tal vez este proyecto se queda un poco justo para un UNO y debería usar un MEGA para la próxima.
Ya solo me queda tratar de convertir todas las variables globales posibles en locales para aligerar un poco más.

Muchas gracias de nuevo

Hi,
MaximoEsfuerzo el explica [quote="montagut, post:1, topic:1262528"]
mando una orden por serial y me arranca el motor,[/quote] No dice que otro output puede usar sino pin 0 y 1. Por eso pregunte si usa pin 0 y 1. Puede ser que haya mal interpretado mal ya que puede usar wire or spi para controlar los motores y me imagine que posiblemente estaba usando el serial port pin 0 y pin1..

Por serial recibe un "comando" para mover los motores, no mueve los motores con los pines del puerto serial. :wink:

No me parece que sea un código que demande mucha memoria, lo más "pesado" son los buffers de los filtros.
Lo que tendrías que mejorar es el manejo del puerto serie, String si es un "pacman" de memoria y más aún con tanto "movimiento" de cadenas.

Ahora mismo voy a contrarreloj con este proyecto, así que lo dejaré con la lectura tal como está, pero tengo claro que si quito los chart y creo arrays con números enteros que ejecuten las ordenes, todo irá más ligero de consumo de memoria.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.