Descartar Líneas recibidas por Serial

Buenas de nuevo,

En vista de que no podía solucionar el problema que abrí en otro topic, abro este nuevo porque se me ha ocurrido una manera de realizar mi programa.

Os pongo en situación; conecto Arduino con un código via cable USB y el mensaje llega perfecto, ahora le envío los datos al PC mediante un APC220 (ya sea directamente al PC o haciendo puente con un MEGA2560 que pasa los datos a cable) y siempre, cada 12 líneas y luego cada 13 líneas me mete un línea con un caracter más, haciendo así inservible mi medición, de esa línea(Pense en fallo del APC220, pero probé un código que también envía cosas parecidas y no falla). Como encontrar el fallo en el código implica modificar una librería que no es mía. He decido, mediante el Arduino MEGA que hace de puente, reconocer el mensaje corrupto contando los caracteres y como tiene alguno más o alguno menos que los enviados correctamente obviarlo para no enviarselo al PC, de manera que cuando le llegue uno corrupto lo deseche.

Pues bien, mi duda es cómo hago el código jajajajaja, no tengo ni idea de por donde empezar...(en MatLab sería facilísimo eliminar un vector o string que no tiene el lenght que quiero, pero aquí ni idea)

Una vez más muchas gracias a todos, tanto por leer como por ayudarme.

Saludos

Saludos.

Para poder ayudarte hace falta mucha mas informacion. Primero el codigo de tus arduinos, segundo los ejemplos de las cadenas que recibes. Como pretendes utilizar los datos y otras cosas que creas pertinente al caso.

Gracias por la respuesta, adjunto todo tipo de información

Estacion_Aire.ino (1.58 KB)

FreeIMU.h (8.6 KB)

FreeIMU.cpp (21.2 KB)

Estacion_Tierra.ino (818 Bytes)

Tengo dos lineas de trabajo

  1. buscar el error

  2. No buscarlo pero agregar algo que lo descarte si hay valores malos

  3. Buscar el error
    Pregunto:

Si he interpretado correctamente tu código y esos valores son impresos por

DEBUG_PRINT(val[3] * M_PI/180);
  DEBUG_PRINT(val[4] * M_PI/180);
  DEBUG_PRINT(val[5] * M_PI/180);
  DEBUG_PRINT(val[0]);
  DEBUG_PRINT(val[1]);
  DEBUG_PRINT(val[2]);
  DEBUG_PRINT(val[6]);
  DEBUG_PRINT(val[7]);
  DEBUG_PRINT(val[8]);

y los valores de val son lecturas de los sensores, entonces como puede emitir valores corruptos?

Ahora no está disponible “DebugUtils.h” que creo contiene DEBUG_PRINT(value)

Confirma si estoy en lo correcto o no.

  1. Agrego un CRC para descartar valores fallidos
    Tal como hacen en algunos protocolos cuando se envian datos por aire pueden producirse errores y por esa razón se usa el CRC de 16 o mas bits.
    El algoritmo para calcularlo se envia junto con el paquete y se recalcula en tierra para confirmar o eliminar un paquete defectuoso.

Se debe agregar unos bytes crc producto del paquete a enviar

 // Esto agrega el CRC a tu mensaje
  uint16_t u16crc = calcCRC( u8BufferSize );
  au8Buffer[ u8BufferSize ] = u16crc >> 8;
  u8BufferSize++;
  au8Buffer[ u8BufferSize ] = u16crc & 0x00ff;
  u8BufferSize++;

y esto lo calcula calcCRC

/**
 * Este método calcula el CRC
 *
 * @return uint16_t calculated CRC value for the message
 * @ingroup buffer
 */
uint16_t Modbus::calcCRC(uint8_t u8length) {
  unsigned int temp, temp2, flag;
  temp = 0xFFFF;
  for (unsigned char i = 0; i < u8length; i++) {
    temp = temp ^ au8Buffer[i];
    for (unsigned char j = 1; j <= 8; j++) {
      flag = temp & 0x0001;
      temp >>=1;
      if (flag)
        temp ^= 0xA001;
    }
  }
  // Reverse byte order. 
  temp2 = temp >> 8;
  temp = (temp << 8) | temp2;
  temp &= 0xFFFF; 
  // the returned value is already swapped
  // crcLo byte is first & crcHi byte is last
  return temp; 
}

y finalmente se valida la respuesta

uint8_t Modbus::validateAnswer() {
  // check message crc vs calculated crc
  uint16_t u16MsgCRC = 
    ((au8Buffer[u8BufferSize - 2] << 8) 
    | au8Buffer[u8BufferSize - 1]); // combine the crc Low & High bytes
  if ( calcCRC( u8BufferSize-2 ) != u16MsgCRC ) {
    u16errCnt ++;
    return NO_REPLY;
  }

  // check exception
  if ((au8Buffer[ FUNC ] & 0x80) != 0) {
    u16errCnt ++;
    return ERR_EXCEPTION;
  }

  // check fct code
  boolean isSupported = false;
  for (uint8_t i = 0; i< sizeof( fctsupported ); i++) {
    if (fctsupported[i] == au8Buffer[FUNC]) {
      isSupported = 1;
      break;
    }
  }
  if (!isSupported) {
    u16errCnt ++;
    return EXC_FUNC_CODE;
  }

  return 0; // OK, no exception code thrown
}

Adjunto toda la librería Modbus para que tengas todo el contexto de donde salen las rutinas y variables para hacerlo. No es complicado.

Modbus.zip (6.93 KB)

surbyte:

  1. Buscar el error
    Pregunto:

Si he interpretado correctamente tu código y esos valores son impresos por

DEBUG_PRINT(val[3] * M_PI/180);

DEBUG_PRINT(val[4] * M_PI/180);
  DEBUG_PRINT(val[5] * M_PI/180);
  DEBUG_PRINT(val[0]);
  DEBUG_PRINT(val[1]);
  DEBUG_PRINT(val[2]);
  DEBUG_PRINT(val[6]);
  DEBUG_PRINT(val[7]);
  DEBUG_PRINT(val[8]);




y los valores de val son lecturas de los sensores, entonces como puede emitir valores corruptos?

Ahora no está disponible "DebugUtils.h" que creo contiene DEBUG_PRINT(value)

Confirma si estoy en lo correcto o no.

Gracias surbyte por contestar.
Las líneas que indicas están comentadas. Las lecturas de los acel y gyro se obtienen con getValues de la siguiente manera(aquí, al ser la librería, está el genérico para todos los tipos de sensores; lleven Magnetómetro o no, S. de Presión o no…):

void FreeIMU::getValues(float * values) { 

  float acgyro_corr[9] = {0.,0.,0.,0.,0.,0.,0.,0.,0.};
  float values_cal[9] = {0.,0.,0.,0.,0.,0.,0.,0.,0.};
  uint8_t i;

  #if HAS_ITG3200()  //assumes adxl3345
    int accval[3];
    acc.readAccel(&accval[0], &accval[1], &accval[2]);
	accval[0] = mfilter_accx.filter((float) accval[0]);
    accval[1] = mfilter_accy.filter((float) accval[1]);
    accval[2] = mfilter_accz.filter((float) accval[2]);
	
    gyro.readGyro(&values_cal[3]);	
	gyro.readTemp(&senTemp);
	if(temp_corr_on == 1) {
		if(senTemp < senTemp_break) {
			for(i = 0; i < 9; i++) { 
				acgyro_corr[i] = c3[i]*(senTemp*senTemp*senTemp) + c2[i]*(senTemp*senTemp) + c1[i]*senTemp + c0[i];
			}		
		} 
	} else {
		for(i = 0; i < 9; i++) { 
			acgyro_corr[i] = 0.0f;
		}
	}

	values_cal[0] = (float) accval[0] - acgyro_corr[0];
	values_cal[1] = (float) accval[1] - acgyro_corr[1];
	values_cal[2] = (float) accval[2] - acgyro_corr[2];
		
	values_cal[3] = (values_cal[3] - gyro_off_x)/gyro_sensitivity;
	values_cal[4] = (values_cal[4] - gyro_off_y)/gyro_sensitivity;
	values_cal[5] = (values_cal[5] - gyro_off_z)/gyro_sensitivity;

  #elif HAS_ALTIMU10()
	gyro.read();
	compass.read();
	values_cal[0] = (float) compass.a.x;
	values_cal[1] = (float) compass.a.y;
	values_cal[2] = (float) compass.a.z;
	//values[0] = mfilter_accx.filter((float) compass.a.x);
	//values[1] = mfilter_accy.filter((float) compass.a.y);
	//values[2] = mfilter_accz.filter((float) compass.a.z);	
	values_cal[3] = (float) gyro.g.x;
	values_cal[4] = (float) gyro.g.y;
	values_cal[5] = (float) gyro.g.z;
    values_cal[6] = (float) compass.m.x;
    values_cal[7] = (float) compass.m.y; 
    values_cal[8] = (float) compass.m.z;
	
	values_cal[3] = (values_cal[3] - gyro_off_x) / gyro_sensitivity;  //Sensitivity set at 70 for +/-2000 deg/sec, L3GD20H
	values_cal[4] = (values_cal[4] - gyro_off_y) / gyro_sensitivity;
	values_cal[5] = (values_cal[5] - gyro_off_z) / gyro_sensitivity;
	
  #else  // MPU6050
    int16_t accgyroval[9];
	#if HAS_MPU9150() || HAS_MPU9250()
		mag.getHeading(&accgyroval[6], &accgyroval[7], &accgyroval[8]);	
		delay(10);
		accgyro.getMotion6(&accgyroval[0], &accgyroval[1], &accgyroval[2], 
						   &accgyroval[3], &accgyroval[4], &accgyroval[5]);	   
		// read raw heading measurements from device
		
		accgyroval[0] = mfilter_accx.filter((float) accgyroval[0]);
		accgyroval[1] = mfilter_accy.filter((float) accgyroval[1]);
		accgyroval[2] = mfilter_accz.filter((float) accgyroval[2]);
		
		values_cal[6] = mfilter_mx.filter((float) accgyroval[6]);
		values_cal[7] = mfilter_my.filter((float) accgyroval[7]);
		values_cal[8] = mfilter_mz.filter((float) accgyroval[8]); 

	#else
		accgyro.getMotion6(&accgyroval[0], &accgyroval[1], &accgyroval[2], 
						   &accgyroval[3], &accgyroval[4], &accgyroval[5]);
	#endif
	
	DTemp = accgyro.getTemperature();

	if(temp_corr_on == 1){
		if(DTemp < temp_break){    
			for( i = 0; i < 9; i++) { 
				acgyro_corr[i] = c3[i]*(DTemp*DTemp*DTemp) + c2[i]*(DTemp*DTemp) + c1[i]*DTemp + c0[i];
			}
		} 
	} else {
		for( i = 0; i < 9; i++) { 
			acgyro_corr[i] = 0.0f;
	  }
	}
	
    // remove offsets from the gyroscope
	if(temp_corr_on == 1){
		//accgyroval[3] = accgyroval[3] - acgyro_corr[3];
		//accgyroval[4] = accgyroval[4] - acgyro_corr[4];
		//accgyroval[5] = accgyroval[5] - acgyro_corr[5];
		
		values_cal[3] = (float) accgyroval[3] - acgyro_corr[3];
		values_cal[4] = (float) accgyroval[4] - acgyro_corr[4];
		values_cal[5] = (float) accgyroval[5] - acgyro_corr[5];
		}
	  else {
		values_cal[3] = (float) accgyroval[3] - gyro_off_x;
		values_cal[4] = (float) accgyroval[4] - gyro_off_y;
		values_cal[5] = (float) accgyroval[5] - gyro_off_z;
	  }
	  
    for( i = 0; i<6; i++) {
      if( i < 3 ) {
        values_cal[i] = (float) accgyroval[i] - acgyro_corr[i];
      }
      else {
        //values[i] = ((float) accgyroval[i] - acgyro_corr[i])/ 16.4f; // NOTE: this depends on the sensitivity chosen
		values_cal[i] = values_cal[i] / gyro_sensitivity;   //for 6050 etc
	  }
    }	
  #endif

  
  #warning Accelerometer calibration active: have you calibrated your device?
  // remove offsets and scale accelerometer (calibration)
  values_cal[0] = (values_cal[0] - acc_off_x) / acc_scale_x;
  values_cal[1] = (values_cal[1] - acc_off_y) / acc_scale_y;
  values_cal[2] = (values_cal[2] - acc_off_z) / acc_scale_z;
  
  #if HAS_HMC5883L()
    magn.getValues(&values_cal[6]);
  #endif
  
  #if HAS_HMC5883L() || HAS_MPU9150() || HAS_MPU9250() || HAS_LSM303()
    // calibration
	if(temp_corr_on == 1) {
		values_cal[6] = (values_cal[6] - acgyro_corr[6] - magn_off_x) / magn_scale_x;
		values_cal[7] = (values_cal[7] - acgyro_corr[7] - magn_off_y) / magn_scale_y;
		values_cal[8] = (values_cal[8] - acgyro_corr[8] - magn_off_z) / magn_scale_z;
	}	
	else {
		#warning Magnetometer calibration active: have you calibrated your device?
		values_cal[6] = (values_cal[6] - magn_off_x) / magn_scale_x;
		values_cal[7] = (values_cal[7] - magn_off_y) / magn_scale_y;
		values_cal[8] = (values_cal[8] - magn_off_z) / magn_scale_z;	
	}
  #endif
  
  for(int i = 0; i < 9; i++) {
	values[i] = sensor_sign[i] * values_cal[sensor_order[i]];
  }
}

En cuanto a lo que decías del fallo del sensor, no es posible debido a que si transmites vía cable USB el mensaje llega intacto y cada línea de la comunicación serie con el mismo número de caracteres ASCII

Me pongo con el cálculo del CRC que, ahora que me lo menciona, algo me suena haber leído.

Muchas, muchas gracias. Cuando obtenga algún resultado, ya sea satisfactorio o no lo posteo

Saludos

bueno te puse toda la librería modbus para que puedieras tomar todo lo necesario desde la creación del crc hasta su comprobación.

NOTA: me había quedado claro la forma de tomar los datos, pero aun no entiendo como pueden producirse los errores. Voy a mirar de nuevo los archivos. Se me acaba de ocurrir algo pero no se.

Pensando y mientras chequeo lo que acabo de escribir, te comento algo para que investigues
El mayor responsable para que un programa aparentemente bien hecho tenga errores es la falta de SRAM.
Introduce esta función para mostrar el estado de la RAM en los lugares sospechosos.

Falta memoria RAM
Memoria disponible

Saludos
Estoy viendo el codigo y veo muchas librerías que están sin uso que no comentaste.
Cada librería incluida consume memoria de programa y SRAM, elimina las que no usas. Como comunicationUtils.h y otras cosas, que creo que las copiaste de otro codigo y no te has atrevido a borrar.

Para hacer el codigo mas ligero:

//Reemplazar
serialPrintFloatArr(q, 4);  
//por

for(int i = 0; i < 4; i++{
 Serial.print(q[i],HEX);
 Serial.print(",");
}
  Serial.print(baro);
  Serial.print("\n");

Y no envíes constantemente datos, revisa tus sensores y algunos de ellos tienen un tiempo para preparar los datos, establece un tiempo de envió para poder enviar mas datos, así te asegurar que el buffer TX se limpia correctamente.
Puedes programar con un delay o usando millis() (mas recomendado). Y luego de enviar limpia el buffer.

max_saeta:
Saludos
Estoy viendo el codigo y veo muchas librerías que están sin uso que no comentaste.
Cada librería incluida consume memoria de programa y SRAM, elimina las que no usas. Como comunicationUtils.h y otras cosas, que creo que las copiaste de otro codigo y no te has atrevido a borrar.

Para hacer el codigo mas ligero:

//Reemplazar

serialPrintFloatArr(q, 4); 
//por

for(int i = 0; i < 4; i++{
Serial.print(q[i],HEX);
Serial.print(",");
}
  Serial.print(baro);
  Serial.print("\n");




Y no envíes constantemente datos, revisa tus sensores y algunos de ellos tienen un tiempo para preparar los datos, establece un tiempo de envió para poder enviar mas datos, así te asegurar que el buffer TX se limpia correctamente. 
Puedes programar con un delay o usando millis() (mas recomendado). Y luego de enviar limpia el buffer.

Gracias max_saeta, ya lo he cambiado pero, apenas genera cambios en la memoria del Arduino, dado que las librerías que estaban no eran llamadas por ninguna función no las cargaba y en cuanto a la impresión de los float, tu código baja un poco lo que ocupa el sketch y en cuanto a efectos de memoria la verdad que ni idea porque no lo he comprado.

Volviendo al hilo principal del programa ya se cual es el fallo aqui en el departamento de electrónica me han dado las claves y si era ese el fallo. Es un desbordamiento del búffer que tiene el módulo de RF por tanto, tengo que bajar el Baud Rate o, lo que he hecho para probar primeramente, meterle un delay para que le de tiempo a vaciarse. Era un problema de velocidades, le metía más bytes por segundo al RF de los que admite entonces, por eso se desbordaba con una secuencia de repetición cada 12 o 13 mensajes, que realmente es cada 512 bytes que es la memoria del búffer si mal no recuerdo.

Gracias a todos y sigo comentando por aquí los avances.

Saludos y gracias de nuevo

Saludos

Me alegro que hallas solucionado, por eso te había escrito:

max_saeta:
Y no envíes constantemente datos, revisa tus sensores y algunos de ellos tienen un tiempo para preparar los datos, establece un tiempo de envió para poder enviar mas datos, así te asegurar que el buffer TX se limpia correctamente.
Puedes programar con un delay o usando millis() (mas recomendado). Y luego de enviar limpia el buffer.

Aunque no creas eso que te paso pasa muy seguido con transmisión de datos.