Luz de freno bici ADXL345 (brake lights)

Hola,

Estoy intentando llevar a la práctica este proyecto, añadiendo o modificando su contenido si fuera necesario.

Lo compilo sin problemas Algún aviso : Low memory available, stability problems may occur.

pero realmento no acaba de funcionar la salida a la luz de freno se enciende cuando le viene en gana.

adjunto PDF que traduje de otros sitios y medio que adapté.

Me gustaría saber si alguién ha realizado un proyecto similar, y si es asi y desea contribuir a este desarrollo se ría de agradecer

Acelerometro Proyecto.pdf (758 KB)

Lo primero es que debes facilitar las cosas a todos, poniendo el código y no un pdf con el código.
Yo lo he extraído del pdf y solo te diré que compila sin errores, pero con advertencia

El sketch usa 5,992 bytes (18.6%) del espacio de almacenamiento. El máximo es 32,256 bytes.
Las variables globales usan 928 bytes (45.3%) de la memoria dinámica, dejando 1,120 bytes para variables locales. EL máximo es 2,048 bytes.
[Stino - Compilación terminada "ADXL345" en 7.7s.]

Has verificado los cables, hacen buen contacto? Estan bien las tensiones en todos los casos?
El tutorial es bastente cuidados advirtiendo sobre las tensiones del módulo.

#include <Wire.h> 
#define DEVICE (0x53)    //Definimos la dirección de nuestro dispositivo ADXL345 
#define TO_READ (6)      // Núm de bytes que va a leer cada vez ( dos bytes para cada eje ) 
byte buff[TO_READ] ;    // 6 bytes buffer para guardar los datos leídos del dispositivo 
char str[512];                  //Cadena de almacenamiento para transformer los datos antes de enviarlos al Puerto serial 

// * * * * * * * * * * * * * * * * * * * * * *  
// Asignando luz de freno 
int BrakeLight = 5; 
int iTol = 30; 

// Asignando el almacenamiento del pulsador 
int Target = 13;  // Pin para asignar el pulsador 
int iTarget = 0;   // Valor por defecto 
// * * * * * * * * * * * * * * * * * * * * * *  

void setup() 
{ 
 Wire.begin();            // Conecta el bus I2C (address optional for master) 
 Serial.begin(9600);  // Inicializando salida puerto serial 

 // Encendiendo el ADXL345 
 writeTo(DEVICE, 0x2D, 0);       
 writeTo(DEVICE, 0x2D, 16); 
 writeTo(DEVICE, 0x2D, 8); 

 // * * * * * * * * * * * * * * * * * * * * * *  
 // Configurando Luz de freno como salida y Pulsador como entrada 
 pinMode(BrakeLight, OUTPUT);      
 pinMode(Target, INPUT);     
 // * * * * * * * * * * * * * * * * * * * * * *  
} 

void loop() { 

   int regAddress = 0x32;    // Primer registro de datos de aceleración del eje en el ADXL345 
   int x, y, z; 

 readFrom(DEVICE, regAddress, TO_READ, buff); // Leyendo datos de aceleración del ADXL345 
  
 // Cada lectura de eje se da en resolución de 10 bit, 2 bytes. Primero el Byte menos significativo !! 
 // De esta forma, estamos convirtiendo los dos bytes en un int 
 x = (((int)buff[1]) << 8) | buff[0];    
 y = (((int)buff[3])<< 8) | buff[2]; 
 z = (((int)buff[5]) << 8) | buff[4]; 

 // * * * * * * * * * * * * * * * * * * * * * *  
 // added for brake lite kit                añadido para el pequeño kit de freno 
 if (digitalRead(Target) == HIGH) 
   setTarget(z); 
 if (z < (iTarget - iTol)) 
 digitalWrite(BrakeLight, HIGH); 
 if (z > (iTarget + iTol)) 
 digitalWrite(BrakeLight, LOW); 
 
 // * * * * * * * * * * * * * * * * * * * * * *  
 // Enviamos los valores XYZ como una cadena al puerto serie * * *  añadido para el pequeño kit de freno  
 sprintf(str, "%d %d %d %d", x, y, z, iTarget);   
 Serial.println(str); 
 //Parece que se necesita este Delay para no bloquear el puerto  

 delay(50); 
}   

//---------------- FUNCIONES 
// * * * * * * * * * * * * * * * * * * * * * *  
// added for brake lite kit      añadido para el pequeño kit de freno 

void setTarget(int zVal){ 
 iTarget = zVal; 
 for (int lp = 0; lp <4;lp++) { 
 digitalWrite(BrakeLight,HIGH); 
 delay(50); 
 digitalWrite(BrakeLight,LOW); 
 delay(50); 
 } 
} 

// * * * * * * * * * * * * * * * * * * * * * *  
// Escribe el valor al registro de direcciones en el dispositivo  

void writeTo(int device, byte address, byte val) { 
 Wire.beginTransmission(device); //Comenzando la transmisión al dispositivo.  
 Wire.write(address);        //  Enviando registro de direcciones. 
 Wire.write(val);        //envia el valor de escritura 
 Wire.endTransmission(); //finalización de transmisión 
} 


// lee num bytes, empezando por el búfer array de registro de direcciones del dispositivo 
void readFrom(int device, byte address, int num, byte buff[]) { 
 Wire.beginTransmission(device); //comenzando la transmisión al dispositivo. 
 Wire.write(address);        //enviar a la dirección de registro 
 Wire.endTransmission(); //finalización de transmisión 
 Wire.beginTransmission(device); //comenzando la transmisión al dispositivo. 
 Wire.requestFrom(device, num);    // solicitar 6 bytes desde el dispositivo  
 int i = 0; 

 while (Wire.available()) {    // el dispositivo puede enviar la información inferior a la solicitada (anormal) 
       buff[i] = Wire.read(); // recibe un byte 
   i++; 
 } 
 Wire.endTransmission(); //finalización de transmisión 
}

Si el tutorial me lo curré yo, añadi alguna cosilla más, como un par de resistencias de 10k a positivo, en las sallidas del accelerometro x e y, la Z está puesta a masa.

Las conexiones las tengo bien, aunque es cierto que uno siempre se puede equivocar, que decir tiene que trabajo de tecnico electronico en un laboratorio, el hardware no me da ningún miedo y software algo mas.

Gracias por tu comentarío

Exactamente, ¿qué tiene que hacer el código? ¿un acelerómetro para una luz de freno? no entiendo su función.

carmeloco:
Exactamente, ¿qué tiene que hacer el código? ¿un acelerómetro para una luz de freno? no entiendo su función.

La idea es que tras un frenazo se encienda la luz de freno de la bici, es decir tras una deceleración comprendida entre determinadas "g" que es la unidad de medida de aceleración, o deceleración que es su componente negativa.

Y has probado el módulo cuando esta conectado a la PC via USB si entrega datos negativos.
Es facil de probar el conjunto.
No lo conectes a la bicicleta aún, eso es para un equipo probado.
Primero las pruebas que dicen que te da valores negativos y que interfaces, cables, conexiones, tensiones, y programa todos estan funcionando como deben hacerlo.

surbyte:
Y has probado el módulo cuando esta conectado a la PC via USB si entrega datos negativos.
Es facil de probar el conjunto.
No lo conectes a la bicicleta aún, eso es para un equipo probado.
Primero las pruebas que dicen que te da valores negativos y que interfaces, cables, conexiones, tensiones, y programa todos estan funcionando como deben hacerlo.

Si, me de portan valores positivos y negativos en los ejes de x e y , cuando hago variaciones de movimiento, aceleración/deceleración, el problema lo tengo dentro de la condicional, no soy capaz de hacer una condición para que me reporte esa franja en la que se tiene que encender la luz de freno.

surbyte:
Y has probado el módulo cuando esta conectado a la PC via USB si entrega datos negativos.
Es facil de probar el conjunto.
No lo conectes a la bicicleta aún, eso es para un equipo probado.
Primero las pruebas que dicen que te da valores negativos y que interfaces, cables, conexiones, tensiones, y programa todos estan funcionando como deben hacerlo.

Es cierto no lo heconectado a la bici, hago pruebas con una batería y desplazándome yo....
También dudo que el botón del pulsador actúe en la calibración...

Y cuales son las condiciones que satisfen una desaceleración?

 // added for brake lite kit                añadido para el pequeño kit de freno 
 if (digitalRead(Target) == HIGH) 
   setTarget(z); 
 if (z < (iTarget - iTol)) 
 digitalWrite(BrakeLight, HIGH); 
 if (z > (iTarget + iTol)) 
 digitalWrite(BrakeLight, LOW);

evidentemente esto no es suficiente?

surbyte:
Y cuales son las condiciones que satisfen una desaceleración?

 // added for brake lite kit                añadido para el pequeño kit de freno 

if (digitalRead(Target) == HIGH)
  setTarget(z);
if (z < (iTarget - iTol))
digitalWrite(BrakeLight, HIGH);
if (z > (iTarget + iTol))
digitalWrite(BrakeLight, LOW);




evidentemente esto no es suficiente?

Ando un poco perdido, esto lo copie de otras webs, que era como una estandarización a la
hora de trabajar con el acelerómetro ADXL345, pero no le veo lógica, como cuando pulsas y llamas a la función del pulsador y coge el valor de zval, que no se para que lo quiere si esa salida está a masa y nos dará un valor fijo¿? Y las condicionales siguientes de activar y desactivar la luz, no las entiendo…

Lo que te agregué fue un promedio movil de 20 muestras.
Eso debería estabilizar las lecturas (por un lado

void loop() { 

    int regAddress = 0x32;    // Primer registro de datos de aceleración del eje en el ADXL345 
    int x, y, z; 
    int Raw, Filtrada, FiltradaPrevia;

	readFrom(DEVICE, regAddress, TO_READ, buff); // Leyendo datos de aceleración del ADXL345 

	// Cada lectura de eje se da en resolución de 10 bit, 2 bytes. Primero el Byte menos significativo !! 
	// De esta forma, estamos convirtiendo los dos bytes en un int 
	x = (((int)buff[1]) << 8) | buff[0];    
	y = (((int)buff[3])	<< 8) | buff[2]; 
	z = (((int)buff[5]) << 8) | buff[4]; 

	// * * * * * * * * * * * * * * * * * * * * * *  
	// added for brake lite kit                añadido para el pequeño kit de freno 
	if (digitalRead(Target) == HIGH) 		//	Esto fija el punto de disparo,atención!!
		setTarget(z); 
	Raw = z;
	Filtrada = FiltradaPrevia + (Raw - FiltradaPrevia ) / 20;
	// Esto es un filtro pasabajos 1/20 usando promedio movil.
	// solo requiere que no haya delay y que se tomen muchas muestras 
	// en este caso solo 20, pero luego de las primeras 20 ni cuenta te das.
	
	if (Filtrada < (iTarget - iTol)) 
		digitalWrite(BrakeLight, HIGH); 
	if (Filtrada > (iTarget + iTol)) 
		digitalWrite(BrakeLight, LOW); 

	// * * * * * * * * * * * * * * * * * * * * * *  
	// Enviamos los valores XYZ como una cadena al puerto serie * * *  añadido para el pequeño kit de freno  
	sprintf(str, "%d %d %d %d", x, y, Raw, iTarget);   
	Serial.println(str); 
	//Parece que se necesita este Delay para no bloquear el puerto  
	FiltradaPrevia = Filtrada;

	delay(50); 
}

Ok, añidi lo que me comentabas, pero ahora el inicio es similar a lo que me hacia anteriormente, lo único es que ahora ya se queda encendido la luz de freno siempre, al momento de pulsar el pulsador

A ver.. según lo entiendo todo depende del valor que establezcas cuando presionas

if (digitalRead(Target) == HIGH) 		//	Esto fija el punto de disparo,atención!!
		setTarget(z);

Cuando presionas ese botón Target, se ajusta el valor con setTarget(z)..mmmmmm me equivoqué. Debería ser justamente el valor promediado (Filtrada). Bueno sigamos asi por ahora.

Ese valor es el que luego se usa para comparar ya que iTarget = z (del momento en que presionaste)

Si es una bicy, y uno frena, 50 mseg de delay es una eternidad.
Quita o comenta ese delay(50);

Ahora después de pulsar no se enciende la luz, solamente el parpadeo de la subrutina del pulsador, después se va a off, a menos que en el movimiento le des un golpe, entonces si luce, otra cosa curiosa, me imagino que serán interferencias, cuando voy moviendo la placa y pasa por encima!a del teclado del PC la luz se enciende, como si fuera un detector de metales,

Porque no pones el código que estas usando ahora.

#include <Wire.h>
#define DEVICE (0x53) //Definimos la dirección de nuestro dispositivo ADXL345
#define TO_READ (6) // Núm de bytes que va a leer cada vez ( dos bytes para cada eje )
byte buff[TO_READ] ; // 6 bytes buffer para guardar los datos leídos del dispositivo
char str[512]; //Cadena de almacenamiento para transformar los datos antes de enviarlos al Puerto serial
 
// Variables Luz Freno
int LuzFreno = 5;
int iTol = 30;
 
// Variables Pulsador
int Pulsador = 13; // Pin para asignar el pulsador
int iPulsador = 0; // Valor por defecto
 
void setup()
{
Wire.begin(); // Conecta el bus I2C (address optional for master)
Serial.begin(9600); // Inicializando puerto serial
 
// Encendiendo el ADXL345
writeTo(DEVICE, 0x2D, 0);
writeTo(DEVICE, 0x2D, 16);
writeTo(DEVICE, 0x2D, 8 );
 
// Configurando Luz de Freno como salida y Pulsador como entrada
pinMode(LuzFreno, OUTPUT);
pinMode(Pulsador, INPUT);
}
 
void loop()
{
int regAddress = 0x32; // Primer registro de datos de aceleración del eje en el ADXL345
int x, y, z;
int Raw, Filtrada, FiltradaPrevia;

readFrom(DEVICE, regAddress, TO_READ, buff); // Leyendo datos de aceleración del ADXL345
// Cada lectura de eje se da en resolución de 10 bit, 2 bytes. Primero el Byte menos significativo !!
// De esta forma, estamos convirtiendo los dos bytes en un int
x = (((int)buff[1]) << 8 ) | buff[0];
y = (((int)buff[3])<< 8 ) | buff[2];
z = (((int)buff[5]) << 8 ) | buff[4];
 
 
// CONDICIONALES de Funcionamiento
if (digitalRead(Pulsador)==HIGH) subrutinaPulsador(Filtrada); // Si el pulsador ON,  vamos a Subrutina del Pulsador
Raw = z;
Filtrada = FiltradaPrevia + (Raw - FiltradaPrevia ) / 20;
 // Esto es un filtro pasabajos 1/20 usando promedio movil.
 // solo requiere que no haya delay y que se tomen muchas muestras 
 // en este caso solo 20, pero luego de las primeras 20 ni cuenta te das.
 
if (Filtrada < (iPulsador - iTol)) digitalWrite(LuzFreno, HIGH); //Luz de Freno ON
if (z > (iPulsador + iTol)) digitalWrite(LuzFreno, LOW) ; // Luz de freno OFF
 
 
// Puerto Serie
sprintf(str, "%d %d %d %d", x, y, Raw, iPulsador ); // Enviamos los valores XYZ como una cadena al puerto serie
Serial.println(str);
FiltradaPrevia = Filtrada;

// delay(50);   //Parece que se necesita este Delay para no bloquear el puerto
}
//------ FUNCION  PULSADOR  ON
 
void subrutinaPulsador(int zVal){
iPulsador = zVal;
for (int lp = 0; lp <4;lp++) {
digitalWrite(LuzFreno,HIGH);
delay(50);
digitalWrite(LuzFreno,LOW);
delay(50);
}
}
 
// Escribe el valor al registro de direcciones en el dispositivo
void writeTo(int device, byte address, byte val) {
Wire.beginTransmission(device); //Comenzando la transmisión al dispositivo.
Wire.write(address); // Enviando registro de direcciones.
Wire.write(val); //envia el valor de escritura
Wire.endTransmission(); //finalización de transmisión
}
// lee num bytes, empezando por el búfer array de registro de direcciones del dispositivo
void readFrom(int device, byte address, int num, byte buff[]) {
Wire.beginTransmission(device); //comenzando la transmisión al dispositivo.
Wire.write(address); //enviar a la dirección de registro
Wire.endTransmission(); //finalización de transmisión
Wire.beginTransmission(device); //comenzando la transmisión al dispositivo.
Wire.requestFrom(device, num); // solicitar 6 bytes desde el dispositivo
int i = 0;
while(Wire.available()) // el dispositivo puede enviar la información inferior a la solicitada (anormal)
{
buff = Wire.read(); // recibe un byte
i++; 
}
Wire.endTransmission(); //finalización de transmisión
}

A esta altura no has visto que los códigos se insertan usando tag?
Por favor edita ese post.

// De esta forma, estamos convirtiendo los dos bytes en un int
x = (((int)buff[1]) << 8 ) | buff[0];
y = (((int)buff[3])<< 8 ) | buff[2];
z = (((int)buff[5]) << 8 ) | buff[4];
 
// CONDICIONALES de Funcionamiento
if (digitalRead(Pulsador)==HIGH) subrutinaPulsador(Filtrada); // Si el pulsador ON,  vamos a Subrutina del Pulsador
Raw = z;
Filtrada = FiltradaPrevia + (Raw - FiltradaPrevia ) / 10;
 // Esto es un filtro pasabajos 1/20 usando promedio movil.
 // solo requiere que no haya delay y que se tomen muchas muestras
 // en este caso solo 20, pero luego de las primeras 20 ni cuenta te das.

 // added for brake lite kit                añadido para el pequeño kit de freno 
 if (digitalRead(Target) == HIGH) 
   setTarget(Filtrada);
 
if (Filtrada < (iPulsador - iTol)) digitalWrite(LuzFreno, HIGH); Luz de Freno ON
if (Filtrada > (iPulsador + iTol)) digitalWrite(LuzFreno, LOW) ; // Luz de freno OFF
 
 
// Puerto Serie
sprintf(str, "%d %d %d %d", x, y, Raw, iPulsador ); // Enviamos los valores XYZ como una cadena al puerto serie
Serial.println(str);
FiltradaPrevia = Filtrada;

Te reduje el promedio a 10 muestras y agregue en la 2da condicion la variable que corresponde y el SetTarjet que no se porque no estaba y es fundamental.

Ahora no se en que momento presionas ese pulsador?

if (digitalRead(Target) == HIGH) 
   setTarget(Filtrada);

porque es importante que el filtro tome algunas muestras.
Si no funciona cambia a setTarget(z);

Ok, gracias, ya lo edité e inserté como código

Modifiqué las variables (solo el nombre) de algunas para adecuarlo al proyecto

Target por Pulsador
iTaget por iPulsador
BrakeLights por LuzFreno

Por cierto, en estas condicionales cambié la “z” por Filtrada, es correcto?

if (Filtrada < (iPulsador - iTol)) digitalWrite(LuzFreno, HIGH); Luz de Freno ON
if (Filtrada > (iPulsador + iTol)) digitalWrite(LuzFreno, LOW) ; // Luz de freno OFF

Si, pero además YO había olvidado la etapa en la que fijas el valor iPulsador que es cuando presionas el boton

if (digitalRead(Target) == HIGH) 
   setTarget(Filtrada);

Me imagino que lo haces una vez y luego ya queda configurada.
iTol es un valor fijo. Asi que todo depende de que iPulsador tenga el valor apropiado para detectar la frenada.

Estos tres valores Raw, Filtrada, iPulsador, deberías verlos. X e Y me parece que no contribuyen en nada para lo que necesitas.

Algo mas. lo pensé y salió mal en el post anterior.
Agregaste algo y cuando lo hiciste o yo cometí el error o fuiste tu. No importa, pero esta mal.
Aca te corrijo la parte que corresponde.

Raw = z;
Filtrada = FiltradaPrevia + (Raw - FiltradaPrevia ) / 10;
 // Esto es un filtro pasabajos 1/20 usando promedio movil.
 // solo requiere que no haya delay y que se tomen muchas muestras
 // en este caso solo 20, pero luego de las primeras 20 ni cuenta te das.

// CONDICIONALES de Funcionamiento
if (digitalRead(Pulsador)==HIGH) 
   subrutinaPulsador(Filtrada); // Si el pulsador ON,  vamos a Subrutina del Pulsador

Ok, luego lo pruebo, cambio el muestreo a /10

Otra pregunta, yo ando siempre con el soldador encendido y las comexiones las sueldo con cableados en PCB de lineas,
me imagino que hay decenas, pero alguna Protoboard (conexionado de agujeros para pinchar) que sea decente o algún formato especifico?