Soy de Villajoyosa, una localidad entre Alicante y Benidorm.
Siempre e querido iniciarme en esto de la electrónica.
Soy programador y electricista de profesión, y siempre lo he ido dejando...
Por fin a mis 48 tacos, me he hecho con una placa y he empezado a trastear un poco.
Después de muchos fracasos y tras mucho investigar me he decidido ha realizar mi primer programa "decentillo", un seguidor solar.
Si... ya se que es casi un clásico, pero en mi caso era un reto... me hice con una estructura, un par de servos, y ala... pa lante como puedas...
Aquí os mando el código para que lo juzguéis.... (no seáis muy duros)... funciona bien y me gustaría acabar montando una maqueta a escala con regulador, baterías etc....
Bienvenido al foro y buen trabajo.
Y ahora y solo por enredar y ser minimalista (que me gusta mucho)
Emplear solo tres LDR, ya que tres puntos definen un plano (el de la placa)
Tres casi juntas equidistantes y separadas por un tabique triangular (mas o menos alto) que les de sombra a una o dos si no están perfectamente alineadas con el sol.
Lo dicho, solo por enredar.
Ya estamos.... y yo que creía que hoy me podría dar libre...
Ahora por culpa de Jopapa tengo trabajo que hacer...
jejeje...
Bien visto... si es una buena mejora, faltaría evaluar si en cuanto a lineas de programación sale "rentable", de cualquier modo tengo pensadas muchas mejoras, como crear un contenedor para las placas, regulador, baterías, etc..., así como medidores de tensión y corriente, pantalla lcd para controlar todo el sistema y diferentes aplicaciones que hagan "productivo" el invento, y así mismo una estructura para el seguidor mas estable, ya que la comprada por internet es un poco mucho "chapuza", muy bonita, pero chapuza... lo que sucede es que los costes del "prototipo" eran así mas abordables...
pero de momento "el paro"no me da para muchos gastos así que.. poco a poco...
Bueno, se me ocurren muchos detalles que ayudarian a mejorar (y optimizar) el proyecto.
De momento la configuracion del sensor de luz no me parece muy aconsejable, prefiero juntar las cuatro LDR en un pack con dos tabiques perpendiculares (4 plazas) o bien con cuatro tubos (cortos y sin brillo) y las LDR en el fondo.
Las razones son en gran parte subjetivas y las dejaré para otro momento.
El programa es correcto desde el punto de vista del funcionamiento, aunque segun yo lo veo no es demasiado eficiente (NADA que objetar al ser tu debut, que quede claro).
En un primer repaso lo he reducido a esta version (sin probar, claro) que seguro que es mejorable. Pero para ilustrar el fin perseguido creo que vale. Y ademas te ayuda al "ahorro" que comentas aunque sea solo en código.
#include <Servo.h>
const byte LedPin = 13; // Pin digital del led integrado en placa
const byte AngB = 3; // Pin digital del servo de la Inclinacion
const byte AngX = 9; // Pin digital del servo Azimutal
unsigned long Pausa = 100; // tiempo en milisegundos para pausas
int Grados= 1; // Grados en que los servos se moveran de golpe
int Sensibilidad= 50; // Diferencia de lectura de las LDRs para que provoque movimiento
boolean control= false; // para accionar o no los servos
int AbetaMin=45; // Angulo Inclinacion minimo permitido (equivale a 0 grados, posicion horizontal de la inclinacion), esto es asi porque el servo esta defectuoso
int AbetaMax=135; // Angulo Inclinacion maximo permitido (equivale a 90 grados, posicion vertical de la inclinacion), esto es asi porque el servo esta defectuoso
int AalfaMin= 0; // Angulo Azimut minimo permitido (inicialmente el minimo del servo, posicion ESTE del azimut)
int AalfaMax= 180; // Angulo Azimut maximo permitido (inicialmente el maximo del servo, posicion OESTE del azimut)
int Abeta=AbetaMin+45; // Angulo actual de la Inclinacion. Se inicia en su posicion media.
int Aalfa=AalfaMax/2; // Angulo actual del Azimut. Se inicia en su posicion media.
int SIz, SDr, SAr, SAb; // Valores de las LDRs (Izquierda, Derecha, Arriba y Abajo)
//Variables usadas para calibrar sensores
int CIz=62; //le quita este valor al valor leido por el sensor
int CDr=0;
int CAr=0;
int CAb=25;
//Define los pines para las diferentes lecturas analogicas de las LDRs
const byte PinSIz= A2;
const byte PinSDr= A3;
const byte PinSAr= A4;
const byte PinSAb= A5;
int EsDeDia= 50; // sensibilidad minima para que el buscador trabaje, en caso contrario se entiende que es de noche y se colocara en posicion de reposo
Servo Inclinacion; // Estara conectado al pin digital AngB
Servo Azimut; // Estara conectado al pin digital AngX
boolean LeeSensores()
{
// leemos las LDRs y controlamos si es de dia
SIz = analogRead(PinSIz) - CIz;
SDr = analogRead(PinSDr) - CDr;
SAr = analogRead(PinSAr) - CAr;
SAb = analogRead(PinSAb) - CAb;
// Creo que cualquier problema en una sola LDR bloquearia el sistema llevandolo al inicio
// Opto por esta modificacion. Si una sola detecta que es de dia ¿para que el resto?
if ((SIz>EsDeDia) || (SDr>EsDeDia) || (SAr>EsDeDia) || (SAb>EsDeDia))
{
return true;
}
else
{
return false;
}
}
void setup()
{
pinMode(LedPin,OUTPUT);
pinMode(AngB,OUTPUT);
pinMode(AngX,OUTPUT);
Inclinacion.attach(AngB); //Servo Inclinacion en pin digital AngB= 3
Azimut.attach(AngX); //Servo Azimut en pin digital AngX= 9
Serial.begin(9600);
// Inicialmente: Inclinacion = 45, y Azimut = 90
// esta es la unica situacion peligrosa dado que como es imposible leer la posicion actual del servo al inicio
// se puede crear un momento de mucha inercia o peligrosidad por la velocidad del giro
Azimut.write(Aalfa);
Inclinacion.write(Abeta);
}
void loop()
{
if(LeeSensores())
{
// Ejecutamos de corrido el escaneo buscando el máximo de luz
// Para el Azimut
while(((SIz-SDr)>Sensibilidad) && (Aalfa>AalfaMin))
{
Azimut.write(Aalfa);
Delay(20); // Ajustar para dar tiempo a los posicionamientos
Aalfa -= Grados;
}
while(((SDr-SIz)>Sensibilidad) && (Aalfa<AalfaMax))
{
Azimut.write(Aalfa);
Delay(20); // Ajustar para dar tiempo a los posicionamientos
Aalfa += Grados;
}
// Para la Inclinacion
while(((SAr-SAb)>Sensibilidad) && (Abeta>AbetaMin))
{
Inclinacion.write(Abeta);
Delay(20); // Ajustar para dar tiempo a los posicionamientos
Abeta -= Grados;
}
while(((SAb-SAr)>Sensibilidad) && (Abeta<AbetaMax))
{
Inclinacion.write(Abeta);
Delay(20); // Ajustar para dar tiempo a los posicionamientos
Abeta += Grados;
}
}
else
{
// Es de noche. Seguidor en posicion de amanecer (apuntando al ESTE en 45 grados)
Azimut.write(AalfaMax); // Ejecutamos
Aalfa=AalfaMax; // Guardamos posicion
Inclinacion.write(AbetaMin+45); // Ejecutamos
Abeta=AbetaMin+45; // Guardamos posicion
delay(5000); //pausa un tiempo la ejecucion del programa para simular el ahorro de energia hasta el dia siguiente
}
}
Hay muchos mas detalles a considerar por ejemplo cambiar los servos por motores paso a paso que pese al nombre pueden encontarse a muy buen precio (driver incluido) por ejemplo aqui: los conjuntos motor-driver porque pienso que permiten un mejor control del seguidor.
Este post es solamente para que veas que te puedes divertir un monton con el proyecto porque admite muchas variantes.
Bien visto Alfaville.... gracias por tu respuesta, pero te comento:
He cambiado la linea
if ((SIz>EsDeDia) && (SDr>EsDeDia) && (SAr>EsDeDia) && (SAb>EsDeDia))
por
if ((SIz>EsDeDia) || (SDr>EsDeDia) || (SAr>EsDeDia) || (SAb>EsDeDia))
Tienes más razón que un santo, no se ni porque la pensé así... lo que no entiendo es que a mi me funcionaba correctamente (tapando un sensor al azar con el dedo, y cuando tapaba los 4 se ponía en reposo).... en fin misterios de la tecnología...
En cuanto al ahorro de código... si... veo que eres de los míos... jeje.. nos gusta reducir y ser eficientes... Este código lo realice aprisa y corriendo para probar y una vez más ... bien visto por tu "ahorro" con los bucles "While" en lugar de los "if"...
Solo un pero a tus comentarios... a mi me gusta pensar en que los proyectos pueden hacerse "grandes" en un futuro, y la seguridad es lo primero, por eso tu último cambio no me gusta, me refiero a que si "es de noche" se posiciona de forma "inmediata" los servos... de ahí mi uso de los bucles "for" para ralentizar el proceso.
Ese problema lo tengo también en el inicio, ya que al no ser posible leer la posición del servo en el momento de arrancar el programa, también se posicionan de golpe y esto en un proyecto grande puede crear problemas dado que se puede generar demasiada inercia en la estructura o "atropellar" a alguien que pase por allí"....
Por cierto Alfaville... creia que resultaba "obvio" que las resistencias no deben de ir donde las he colocado para probar el proyecto...jejeje... el problema es que no tenia mas cables para la protoboard y solo se me ocurrio ponerlas en un cable ide, y por comodidad sujetarlas con unas pinzas... pero es obvio que deben ir en otra configuracion mucho mas efectiva como la que comentas...
Quería preguntarte sobre la placa solar que usas ¿Qué voltaje suele dar? ¿Te sirve esa plaquita para alimentar lo que necesitas?
Lo comento porque cuando empecé con el mismo proyecto estuve comprando unas de "6V" y entrecomillo porque aunque sé que varía dependiendo de la intensidad de luz, calor, etc probé con varias de esas y fueron una maldita broma incluso conectadas en serie. Miraba el multímetro y me desesperaba...
Compré en varias tiendas por si me habían dado gato por liebre y pasaba lo mismo, poco voltaje y cambios muy bruscos. Conseguía a lo mucho una media de 2,4 V por placa.
Y tu dirás: -"Quizás faltaba sol." Pero si eres de Alicante entenderás que en Canarias precisamente sol no nos falta ni ninguna otra fuente renovable.
¿Puedes contarme cual es tu experiencia con ese tipo de placas? porque me dejaron mal salbor de boca. Sé que incluso usan esas en los kits de seguidores solares como el tuyo, aunque nunca me dió por comprar esos ¿De media que voltaje tienes tras un rato con pleno sol?
Yo opté finalmente para el mismo proyecto por una de esta para alimentar una Lipo de tipo Battery power bank (teléfono móvil) ya que trae también una salida USB de 5V y 1A que enciende un led rojo cuando tiene el voltaje necesario para proporcionarte dicha salida.
Todas las que he comprado que vienen protegidas con resina epoxy (y no me refiero al plástico electroestático que se ve con bolsas de aire como en la foto que pones) me han dado malos resultados ¿Cómo va esa? Gracias.
Te comento. Todo esto empezo con un proyecto de tecnologia de mi hija para hacer una noria solar...
A partir de ahi, y por mis conocimientos en electricidad empece a pensar en un cargador de baterias solar, y mas tarde se me ocurrio lo del seguidor solar...
El kit lo compre en Thingnovation, y consta de servos, placa clonica de arduino, estructura y panel.
La placa dice que otorga 6 voltios y 330 mA, lo cual y tras numerosas pruebas se convierten en casi 5V y algo mas de 150 mA a plena irradiacion, lo que me valio para mover la noria, pero poco mas...
En la misma pagina venden unos paneles que dicen tener 6 V y 600 mA por 11 euros... que me da que se quedaran en 5V y algo mas de 300 mA... Este es el enlace.
Lo que si te puedo asegurar, desde mi experiencia, es que si pretendes alimentar algo a 6 voltios, con una intensidad que te permita cargar baterias y alimentar el proyecto, te debes de ir como minimo a un panel que te de 12 V. Si... ya se lo que estas pensando... "Entonces cojo 4 de los anteriores, coloco dos ramas en serie de dos paneles y estas, entre si en paralelo"... lo cual te daria 12 V y casi 1 Amperio... pero yo no me creo nada... O me estan contando que por 44 euros obtengo 12 W?... no se....
Despues de mucho investigar, creo que la mejor opcion (De ahi mi obsesion por hacer lentos los cambios de posicion del seguidor y de crear una estructura mas solida), es algo asi como esto:
La cual dice que da 30 W, 22'5 V y 1'67 A, por 70 euros, lo que se convertira seguramente en unos 18 V y 1 A.
Si... ya se... demasiada tension e intensidad de sobra para arduino...
no lo creas... Ahora viene la segunda parte...
Si te estas planteando implementar un cargador de baterias, los "powerbank" como comentas, suelen dar muchos problemas. Unos porque no pueden cargar al tiempo que suministran y otros porque tienen un "consumo minimo" para activar la salida, con lo que si nuestro proyecto se pone es "espera"... el power bank se apaga y se jodio el invento...
Por tanto... y construyendo la casa por los cimientos... lo ideal seria:
El panel que te he comentado, Un regulador de 12/24 voltios, Dos portapilas en serie que te proporcionarian 12 voltios o bien dos power bank en serie que te proporcionarian 10 V y se cargarian a 12V... o baterias li-po o algo similar a esta bateria que es pequeñita y comple de sobra...
Si ya se que parece que tiro por lo alto, pero si quieres cargar baterias, alimentar a arduino con todos los sensores, servos, etc para que el proyecto sea funcional y demas... esto es lo mejor...
Espero haberte ayudado en algo, de todos modos no soy la mente mas lucida en estos temas y puedo equivocarme. Por ello lo que te recomiendo es que te plantees tu proyecto, sumes intensidades de consumo que necesitas, observes que voltaje es el mas adecuado y que a partir de ahi veas que necesitas... pero HUYE como alma que lleva el diablo de "panelitos" que dicen dar mucho por muy poco... a la larga todos dan problemas y petan que da gusto...
Hola de nuevo eltiotass. Como te comenté el seguidor solar fue mi primer proyecto, ya está acabado (aunque en mi caso es casero y no queda tan bonito como esas piezas negras plásticas o de fibra de carbono )
No he tenido los problemas que comentas con las "powerbank".
Mi duda era si me la habían jugado 3 veces 3 tiendas con las especificaciones de las placas. Y dado que las de ese tipo a ti te proporcionan esos 6V o al menos casi 5 e obvio que sí. Conste que las placas dicen ser de 6V pero no dan ni la mitad a pleno sol, al contrario de la que puse en el post anterior.
Si te fijas en el multímetro de la fotografía que puse verás que con esas escapé del apuro. Lo triste es que la especificación correcta viniese de una placa comprada en China y que en España fueran demasiados "listos".
En su día estuve preguntando sobre este proyecto y dudas respecto a las baterías a usar para así alimentar el arduino (Gracias noter) y por supuesto acabó en mis manos el LM2596 que pones en el enlace, que no usé porque me vino la placa con una de las salidas a: 5V 1A .
También llegué a comprar el TP4056 1A para pilas AAA que imagino trae tu kit pero dada la salida de 5V acabé usando las lipo tipo teléfono móvil que me encienden bien el arduino y acabaron guardados en la caja de piezas sueltas .
Ya las usaré para algún juguete o similar aprovechando que ya me hice un mando a distancia con los módulos HC-05.
Un saludo y gracias por la info. Tres tiendas descartadas para futuras compras.
Desempolvando mis conocimientos de "C", aqui os presento la ultima version del programa al que le he reducido 40 lineas de codigo al emplear "estructuras" para operar los servos....
Sigo diciendo que es muy mejorable... pero poco a poco...
Espero que os guste...
#include <Servo.h>
typedef struct
{
Servo xServo[2]; // Define los 2 servos que vamos a tener, 0 para inclinacion y 1 para Azimut
int PinServo[2]={3, 9}; // Define los pines de los servos; 3 para la inclinacion y 9 para el azimut
int MinPos[2]={45, 0}; // Define el angulo minimo de los servos, 45 para la inclinacion (equivalente a 0 por estar defectuoso) y 0 para el azimut
int MaxPos[2]={135, 180}; // Define el angulo maximo de los servos, 135 para la inclinacion (equivalente a 90 por estar defectuoso) y 180 para el azimut
}StServos;
StServos MisServos; //Se crea la estructura que almacenara los dos servos
int LedPin = 13; // Pin digital del led integrado en placa
int Pausa = 100; // tiempo en milisegundos para pausas
int Grados= 1; // Grados en que los servos se moveran de golpe
int Sensibilidad= 50; // Diferencia de lectura de las LDRs parapara que provoque movimiento
int SIz, SDr, SAr, SAb; // Variables de las LDRs (Sensor Izquierda, Derecha, Arriba y Abajo)
//Varialbes usadas para calibrar sensores
int CIz=62; //le quita este valor al valor leido por el sensor
int CDr=0;
int CAr=0;
int CAb=25;
//Define los pines para las diferentes lecturas analogicas de las LDRs
int PinSIz= A2;
int PinSDr= A3;
int PinSAr= A4;
int PinSAb= A5;
int EsDeDia= 150; // sensibilidad minima para que el buscador trabaje, en caso contrario se entiende que es de noche y se colocará en posicion de reposo
bool LeeSensores()
{
// leemos las LDRs y controlamos si es de dia
SIz = analogRead(PinSIz); SIz= SIz - CIz;
SDr = analogRead(PinSDr); SDr= SDr - CDr;
SAr = analogRead(PinSAr); SAr= SAr - CAr;
SAb = analogRead(PinSAb); SAb= SAb - CAb;
if ((SIz>EsDeDia) || (SDr>EsDeDia) || (SAr>EsDeDia) || (SAb>EsDeDia)) //antes estaba asi y tambien funcionaba if ((SIz>EsDeDia) && (SDr>EsDeDia) && (SAr>EsDeDia) && (SAb>EsDeDia))
{
return true;
}
else
{
return false;
}
}
void PosicionaServo (int Posicion, int IntServo)
//Posicion es la posicion deseada, xServo sera 0 para inclinacion y 1 para Azimut
{
int PosActual=MisServos.xServo[IntServo].read(); // guarda la posicion de inicio del servo
// Serial.print("Estoy en: "); Serial.print(PosActual); Serial.print("; y tengo que ir a: "); Serial.print(Posicion); Serial.print("; Con el servo: "); Serial.println(IntServo);
if (PosActual>Posicion)
{
while ((PosActual > Posicion) && ((PosActual-Grados)>MisServos.MinPos[IntServo]))
{
digitalWrite(LedPin,true); //solo se utiliza el led de la placa aqui para simular señalizacion
PosActual=PosActual-Grados;
MisServos.xServo[IntServo].write(PosActual);
delay(Pausa);
digitalWrite(LedPin,false);
}
}
else
{
while ((PosActual < Posicion) && ((PosActual+Grados)<MisServos.MaxPos[IntServo]))
{
digitalWrite(LedPin,true); //solo se utiliza el led de la placa aqui para simular señalizacion
PosActual=PosActual+Grados;
MisServos.xServo[IntServo].write(PosActual);
delay(Pausa);
digitalWrite(LedPin,false);
}
}
}
void setup()
{
pinMode(LedPin,OUTPUT);
pinMode(MisServos.PinServo[0],OUTPUT);
pinMode(MisServos.PinServo[1],OUTPUT);
MisServos.xServo[0].attach(MisServos.PinServo[0]);
MisServos.xServo[1].attach(MisServos.PinServo[1]);
PosicionaServo((MisServos.MinPos[0]+45), 0); //Posicionamos el servo de inclinacion en su posicion media
PosicionaServo((MisServos.MinPos[1]+90), 1); //Posicionamos el servo de azimut en su posicion media
Serial.begin(9600);
}
void loop()
{
if (LeeSensores())
{
//Analizamos la diferencia de iluminacion entre los sensores derecha e izquierda
if (((SIz-SDr)>Sensibilidad) && (MisServos.xServo[1].read()>MisServos.MinPos[1]))
{
PosicionaServo (((MisServos.xServo[1].read())-Grados), 1);
}
if (((SDr-SIz)>Sensibilidad) && (MisServos.xServo[1].read()<MisServos.MaxPos[1]))
{
PosicionaServo (((MisServos.xServo[1].read())+Grados), 1);
}
//Analizamos la diferencia de iluminacion entre los sensores arriba y abajo
if (((SAr-SAb)>Sensibilidad) && (MisServos.xServo[0].read()>MisServos.MinPos[0]))
{
PosicionaServo (((MisServos.xServo[0].read())-Grados), 0);
}
if (((SAb-SAr)>Sensibilidad) && (MisServos.xServo[0].read()<MisServos.MaxPos[0]))
{
PosicionaServo (((MisServos.xServo[0].read())+Grados), 0);
}
}
else
{
// Colocamos los servos en posicion de reposo hasta el dia siguiente
PosicionaServo (((MisServos.MinPos[0])+45), 0);
PosicionaServo ((MisServos.MaxPos[1]), 1);
delay(5000); //pausa un tiempo la ejecucion del programa para simular el ahorro de energia hasta el dia siguiente
}
}
// Parametros:
// <Posicion> posicion deseada
// <IntServo> servo a mover (0= inclinacion, 1= Azimut)
//
void PosicionaServo(int Posicion, int IntServo)
{
// Analiza si la posicion solicitada esta fuera de rango
if((Posicion < MisServos.MinPos[IntServo])||(Posicion > MisServos.MaxPos[IntServo])) return;
int PosActual=MisServos.xServo[IntServo].read(); // Toma posicion actual del servo
// Serial.print("Estoy en: "); Serial.print(PosActual); Serial.print("; y tengo que ir a: "); Serial.print(Posicion); Serial.print("; Con el servo: "); Serial.println(IntServo);
// Solo se ejecuta si cumple la condicion
while(PosActual > Posicion)
{
if((PosActual=(PosActual-Grados))<(MisServos.MinPos[IntServo])) // Decrementa y compara
{
PosActual=MisServos.MinPos[IntServo]; // Aseguramos posicion por si Grados > 1
}
digitalWrite(LedPin,true); // Señaliza la maniobra
MisServos.xServo[IntServo].write(PosActual); // Ejecuta
delay(Pausa); // Suaviza el movimiento
digitalWrite(LedPin,false);
}
// Solo se ejecuta si cumple la condicion
while(PosActual < Posicion)
{
if((PosActual=(PosActual+Grados))>(MisServos.MaxPos[IntServo])) // Decrementa y compara
{
PosActual=MisServos.MaxPos[IntServo]; // Aseguramos posicion por si Grados > 1
}
digitalWrite(LedPin,true); // Señaliza la maniobra
MisServos.xServo[IntServo].write(PosActual); // Ejecuta
delay(Pausa); // Suaviza el movimiento
digitalWrite(LedPin,false);
}
}
He intentado asegurar los limites de funcionamiento, y el desajuste que se produciría si en algun momento decides hacer "Grados" distinto de 1 (por ejemplo 3)
Saludos