Índice general Foros Digital, Electricidad e Informática Memorizar posición de los servos al encender arduino.

Memorizar posición de los servos al encender arduino.

Moderador: 241-2001



Desconectado
Mensajes: 14
Registrado: 22 Jul 2017 17:33
Buenas noches:
Tengo un problema con los arduinos que tengo instalados en mi maqueta (tres que controlan un total de 28 servos y con polarización del corazón de los desvíos).
Resulta que cuando se apaga toda la instalación los arduinos al iniciarse de nuevo, no memorizan como estaban situados los desvíos al apagarlos, total que cuando quiero moverlos con mi central z21 no están sincronizados y no se sincronizan hasta que no se mueven cada uno de ellos al menos una vez.
¿Se podría arreglar a traves del código de los arduinos?
Os anexo el código mencionado.
Muchas gracias.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Arduino DCC Servo and Function Decoder
// Version: 1.4 - 2015-04-23
// Author: Ruud Boer
// This sketch turns an Arduino into a DCC decoder with max 12 servo motor outputs combined with function outputs.
// The DCC signal is optically separated and fed to pin 2 (=Interrupt 0). Schematics: http://www.mynabay.com
// Many thanks to http://www.mynabay.com for publishing their DCC monitor and -decoder code, which is used in this sketch.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTANT: GOTO lines 23 and 44 to configure some data!
// IMPORTANT: To avoid servo movement and possible high current draw at startup:
// - First start the Arduino, the software now sets the servo angle values to 'offangle'.
// - After a few seconds, switch the servo power on ... they will possibly show just a minor jitter.
// - This only works if you set all servo's to offangle before shutdown!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <DCC_Decoder.h>
#include <Servo.h>
#define kDCC_INTERRUPT 0

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in these 2 values ...
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const byte maxservos = 12; //The number of servos you have connected to this Arduino
const byte servotimer = 10; //Servo angle change timer. Lower value -> higher speed
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned long timetoupdatesetpoint = millis() + servotimer;

struct servoItem {
int address; // DCC address to respond to
byte output; // State of DCC accessory: 1=on, 0=off (ECoS: on=straight, off=turnout)
byte outputPin; // Arduino output pin for additional function (not where servo is attached to)
byte angle;
byte setpoint;
byte offangle;
byte onangle;
Servo servo;
};
servoItem servos[maxservos];

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the data for every function and servo.
// COPY - PASTE as many times as you have functions. The amount must be same as in line 22 above!
// A servo is coupled to an accessory[n]. It rotates based on accessory[n].output = 1 (CCW) or 0 (CW)
// If you have multiple servos you need to couple them to different accessories. However ...
// accessories may switch the same output pin (e.g. pin 13, which has the on board led attached)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ConfigureFunctionsAndServos()
{
servos[0].address = 200; // DCC address for this accessory
servos[0].outputPin = 34; // Arduino pin number for additional function output (not where servo is attached to)
servos[0].servo.attach(22); //Arduino pin number where servo is connected to
servos[0].offangle = 62; //Angle for DCC=off. For ECoS turnout is DCC off, straight is DCC on.
servos[0].onangle = 115; //Angle for DCC=on. For ECoS turnout is DCC off, straight is DCC on.

servos[1].address = 201;
servos[1].outputPin = 35;
servos[1].servo.attach(23);
servos[1].offangle = 85;
servos[1].onangle = 123;

servos[2].address = 202;
servos[2].outputPin = 36;
servos[2].servo.attach(24);
servos[2].offangle = 75;
servos[2].onangle = 125;

servos[3].address = 203;
servos[3].outputPin = 37;
servos[3].servo.attach(25);
servos[3].offangle = 70;
servos[3].onangle = 110;

servos[4].address = 204;
servos[4].outputPin = 38;
servos[4].servo.attach(26);
servos[4].offangle = 70;
servos[4].onangle = 125;

servos[5].address = 205;
servos[5].outputPin = 39;
servos[5].servo.attach(27);
servos[5].offangle = 50;
servos[5].onangle = 110;

servos[6].address = 206;
servos[6].outputPin = 40;
servos[6].servo.attach(28);
servos[6].offangle = 70;
servos[6].onangle = 110;

servos[7].address = 207;
servos[7].outputPin = 41;
servos[7].servo.attach(29);
servos[7].offangle = 70;
servos[7].onangle = 155;

servos[8].address = 208;
servos[8].outputPin = 42;
servos[8].servo.attach(30);
servos[8].offangle = 60;
servos[8].onangle = 110;

servos[9].address = 209;
servos[9].outputPin = 43;
servos[9].servo.attach(31);
servos[9].offangle = 70;
servos[9].onangle = 135;

servos[10].address = 210;
servos[10].outputPin = 44;
servos[10].servo.attach(32);
servos[10].offangle = 60;
servos[10].onangle = 110;

servos[11].address = 211;
servos[11].outputPin = 45;
servos[11].servo.attach(33);
servos[11].offangle = 70;
servos[11].onangle = 110;

} // END ConfigureFunctionsAndServos()

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DCC packet handler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
// Convert NMRA packet address format to human address
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;
address = address + 4;// Meter esta linea para Centrales de Z21 o z21

boolean enable = (data & 0x01) ? 1 : 0;

for(int i=0; i<maxservos; i++)
{
if(address == servos[i].address)
{
if(enable) servos[i].output = 1;
else servos[i].output = 0;
}
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);

ConfigureFunctionsAndServos();
for(int i=0; i<maxservos; i++)
{
pinMode (servos[i].outputPin, OUTPUT );
digitalWrite (servos[i].outputPin, LOW);
servos[i].angle = servos[i].offangle; // Set start up angle to avoid movement at power on
}

DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
pinMode(2,INPUT_PULLUP); //Interrupt 0 with internal pull up resistor (can get rid of external 10k)

pinMode(13,OUTPUT);
digitalWrite(13,LOW); //led off at startup

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main loop (run continuous)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
static int addr = 0;

DCC.loop(); // DCC library

if(++addr >= maxservos) addr = 0; // Next address to test

// Set servos output pin
if (servos[addr].output) digitalWrite(servos[addr].outputPin, HIGH);
else digitalWrite(servos[addr].outputPin, LOW);

// Every 'servotimer' ms, modify setpoints and move servos 1 step (if needed)
if (millis() > timetoupdatesetpoint)
{
timetoupdatesetpoint = millis() + servotimer;
for (int n=0; n<maxservos; n++)
{
if (servos[n].output) servos[n].setpoint=servos[n].onangle;
else servos[n].setpoint=servos[n].offangle;

if (servos[n].angle < servos[n].setpoint) servos[n].angle++;
if (servos[n].angle > servos[n].setpoint) servos[n].angle--;
servos[n].servo.write(servos[n].angle);
}
}

} //END MAIN LOOP


Desconectado
Mensajes: 2182
Registrado: 21 Mar 2014 12:52
puedes utilizar la EEPROM

// Arduino DCC Servo and Function Decoder
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Version: 1.4 - 2015-04-23
// Author: Ruud Boer
// This sketch turns an Arduino into a DCC decoder with max 12 servo motor outputs combined with function outputs.
// The DCC signal is optically separated and fed to pin 2 (=Interrupt 0). Schematics: http://www.mynabay.com
// Many thanks to http://www.mynabay.com for publishing their DCC monitor and -decoder code, which is used in this sketch.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTANT: GOTO lines 23 and 44 to configure some data!
// IMPORTANT: To avoid servo movement and possible high current draw at startup:
// - First start the Arduino, the software now sets the servo angle values to 'offangle'.
// - After a few seconds, switch the servo power on ... they will possibly show just a minor jitter.
// - This only works if you set all servo's to offangle before shutdown!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <DCC_Decoder.h>
#include <Servo.h>
#include <EEPROM.h>                                       //XXX línea añadida
#define kDCC_INTERRUPT 0

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in these 2 values ...
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const byte maxservos = 12; //The number of servos you have connected to this Arduino
const byte servotimer = 10; //Servo angle change timer. Lower value -> higher speed
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned long timetoupdatesetpoint = millis() + servotimer;

struct servoItem {
int address; // DCC address to respond to
byte output; // State of DCC accessory: 1=on, 0=off (ECoS: on=straight, off=turnout)
byte outputPin; // Arduino output pin for additional function (not where servo is attached to)
byte angle;
byte setpoint;
byte offangle;
byte onangle;
Servo servo;
};
servoItem servos[maxservos];

int EEPROMbase = 10; //XXX (Posicion de la EEPROM para el servo número 0)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fill in the data for every function and servo.
// COPY - PASTE as many times as you have functions. The amount must be same as in line 22 above!
// A servo is coupled to an accessory[n]. It rotates based on accessory[n].output = 1 (CCW) or 0 (CW)
// If you have multiple servos you need to couple them to different accessories. However ...
// accessories may switch the same output pin (e.g. pin 13, which has the on board led attached)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ConfigureFunctionsAndServos()
{
servos[0].address = 200; // DCC address for this accessory
servos[0].outputPin = 34; // Arduino pin number for additional function output (not where servo is attached to)
servos[0].servo.attach(22); //Arduino pin number where servo is connected to
servos[0].offangle = 62; //Angle for DCC=off. For ECoS turnout is DCC off, straight is DCC on.
servos[0].onangle = 115; //Angle for DCC=on. For ECoS turnout is DCC off, straight is DCC on.

servos[1].address = 201;
servos[1].outputPin = 35;
servos[1].servo.attach(23);
servos[1].offangle = 85;
servos[1].onangle = 123;

servos[2].address = 202;
servos[2].outputPin = 36;
servos[2].servo.attach(24);
servos[2].offangle = 75;
servos[2].onangle = 125;

servos[3].address = 203;
servos[3].outputPin = 37;
servos[3].servo.attach(25);
servos[3].offangle = 70;
servos[3].onangle = 110;

servos[4].address = 204;
servos[4].outputPin = 38;
servos[4].servo.attach(26);
servos[4].offangle = 70;
servos[4].onangle = 125;

servos[5].address = 205;
servos[5].outputPin = 39;
servos[5].servo.attach(27);
servos[5].offangle = 50;
servos[5].onangle = 110;

servos[6].address = 206;
servos[6].outputPin = 40;
servos[6].servo.attach(28);
servos[6].offangle = 70;
servos[6].onangle = 110;

servos[7].address = 207;
servos[7].outputPin = 41;
servos[7].servo.attach(29);
servos[7].offangle = 70;
servos[7].onangle = 155;

servos[8].address = 208;
servos[8].outputPin = 42;
servos[8].servo.attach(30);
servos[8].offangle = 60;
servos[8].onangle = 110;

servos[9].address = 209;
servos[9].outputPin = 43;
servos[9].servo.attach(31);
servos[9].offangle = 70;
servos[9].onangle = 135;

servos[10].address = 210;
servos[10].outputPin = 44;
servos[10].servo.attach(32);
servos[10].offangle = 60;
servos[10].onangle = 110;

servos[11].address = 211;
servos[11].outputPin = 45;
servos[11].servo.attach(33);
servos[11].offangle = 70;
servos[11].onangle = 110;

} // END ConfigureFunctionsAndServos()

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DCC packet handler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
// Convert NMRA packet address format to human address
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;
address = address + 4;// Meter esta linea para Centrales de Z21 o z21

boolean enable = (data & 0x01) ? 1 : 0;

for(int i=0; i<maxservos; i++)
{
if(address == servos[i].address)
{
if(enable) {servos[i].output = 1;}
else servos[i].output = 0;     
if(enable) EEPROM.update (i+EEPROMbase, 1) ;   //XXX linea añadida
else EEPROM.update (i+EEPROMbase, 0);      //XXX linea añadida
}
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Setup (run once)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);

ConfigureFunctionsAndServos();
for(int i=0; i<maxservos; i++)
{
pinMode (servos[i].outputPin, OUTPUT );
digitalWrite (servos[i].outputPin, LOW);
// servos[i].angle = servos[i].offangle; // Set start up angle to avoid movement at power on               //XXX linea comentada
servos[i].output = EEPROM.read(i+EEPROMbase);                                                              //XXX leemos el estado anterior para el servo "i"
if (servos[i].output == 0) servos[i].angle = servos[i].offangle; else servos[i].angle = servos[i].onangle; //XXX preguntamos por el estado anterior
}

DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
pinMode(2,INPUT_PULLUP); //Interrupt 0 with internal pull up resistor (can get rid of external 10k)

pinMode(13,OUTPUT);
digitalWrite(13,LOW); //led off at startup

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Main loop (run continuous)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
static int addr = 0;

DCC.loop(); // DCC library

if(++addr >= maxservos) addr = 0; // Next address to test

// Set servos output pin
if (servos[addr].output) digitalWrite(servos[addr].outputPin, HIGH);
else digitalWrite(servos[addr].outputPin, LOW);

// Every 'servotimer' ms, modify setpoints and move servos 1 step (if needed)
if (millis() > timetoupdatesetpoint)
{
timetoupdatesetpoint = millis() + servotimer;
for (int n=0; n<maxservos; n++)
{
if (servos[n].output) servos[n].setpoint=servos[n].onangle;
else servos[n].setpoint=servos[n].offangle;

if (servos[n].angle < servos[n].setpoint) servos[n].angle++;
if (servos[n].angle > servos[n].setpoint) servos[n].angle--;
servos[n].servo.write(servos[n].angle);
}
}

} //END MAIN LOOP


Te he añadido/modificado las líneas que tienen //XXX, básicamente lo que he hecho es guardar en la posición de la EEPROM dada por EEPROMbase+i el valor del estado del servo dado por servos[i].output y lo almaceno cada vez que se recibe una instrucción de cambio para ese servo.
Cuando el sketch arranca lee esos valores y los aplica

Es posible que la primera vez que lo ejecute te haga cosas raras, pues la EEPROM puede tener valores aleatorios, pero una vez que muevas cada aguja por lo menos una vez, los demás arranques ya debería recordar las posiciones.

Ya nos cuentas

Un saludo.

Ah, la posición EEPROMbase la he puesto a 10, por dejar algunas direcciones previas libres, pero vamos, lo puedes cambiar.


Desconectado
Mensajes: 323
Ubicación: Alto Palancia
Registrado: 03 Jul 2020 13:27
Buenas noches.

He leído el código un poco en diagonal, pero por lo que veo, se me ocurren dos posibilidades.

Si la centralita permite situar los desvíos en un valor de inicialización, se puede hacer lo mismo en el Arduino, y de esta forma estarían siempre sincronizados. Por ejemplo se podrían inicializar siempre en "vía directa", o elegir de forma más individualizada cada uno.

Otra opción podría ser guardar en la EEPROM (https://www.arduino.cc/en/Reference/EEPROM) los valores existentes.
La EEPROM tiene un número de escrituras limitado (100.000), así que si optas por escribir el valor cada vez, acabarás "quemando" la memoria. Claro, esto depende mucho de cuantos cambios de desvío realices. Podrían ser 3 años, o podrían ser 30. Si quieres complicarte un poco más, como la EEPROM tiene mucha más capacidad de la que necesitas, se puede hacer que vaya rotando las posiciones de memoria para extender el desgaste y que dure todavía más.
Otra opción, también más sencilla, es poner un pulsador en un pin libre, que haga que los Arduinos escriban los valores. Lo único malo de esto es que si te olvidas de pulsarlo antes de apagar, se pierden igualmente.

Un saludo.

EDIT: Se me han adelantado por 5 minutos :lol:


Desconectado
Mensajes: 801
Ubicación: Zaragoza
Registrado: 07 Oct 2008 21:26
Hay una alternativa "chapucera" pero que puede funcionar. En mi caso tengo el mismo problema pero como lo controlo por software el problema se soluciona, pues el programa resetea todos los desvios para adecuarlos a las posiciones memorizadas.
La app de la Z21 no tiene esa opción, pero podrías crear una ruta con los 28 desvíos, de forma que activando la ruta al encender se sincronizan todos.

Si quieres una solución más elegante, basada en programación, hay una forma de "despreocuparte" del "desgaste" de la EEPROM de arduino y es incorporar un módulo externo EEPROM como el AT24C256, tiene 256Kb y a diferencia de la de arduino puede alcanzar 1000000 de ciclismo de escritura, se pueden conectar hasta 4 de estos módulos por I2C y son baratos (los he visto por 2€). También hay disponibles módulos de 512 y 1024 Kb y en algunos montajes el chip EEPROM viene en un zócalo con lo que si se "agota" se puede cambiar solo el chip.


Desconectado
Mensajes: 261
Registrado: 28 Oct 2015 09:35
En mi caso he realizado lo que han comentado los compañeros, en la app z21 tengo una pantalla exclusiva con varias rutas para activar los servos o señales y así inicializar la posición o ajustar los servos si fuera necesario. Y en las pantallas donde tengo el diagrama de las estaciones la mayoría lo tengo asignado con diferentes rutas, así el que este mal posicionado se pondrá en su posición correcta de la ruta


Desconectado
Mensajes: 132
Registrado: 26 Feb 2016 20:17
Muchas gracias por el código.

Saludos cordiales.


Desconectado
Mensajes: 14
Registrado: 22 Jul 2017 17:33
Buenos días:
Matao, muchas gracias por el código ha funcionado, en mis tres arduinos, a la perfección.
La solución de Renfe276, también la he probado en la app de Z21 y muy bien también.
Muchas gracias a todos.


Desconectado
Mensajes: 2182
Registrado: 21 Mar 2014 12:52
Me alegro Jafala.

El único pero es que tras unos 100.000 cambios en las agujas, lo mismo te empieza a dar problemas, en ese caso cambia la línea
int EEPROMbase = 10; //XXX (Posicion de la EEPROM para el servo número 0)

a
int EEPROMbase = 10+maxservos; //XXX (Posicion de la EEPROM para el servo número 0)

Puede que el compilador no te lo admita entonces, dado que maxservos es 12 por
int EEPROMbase = 22; //XXX (Posicion de la EEPROM para el servo número 0)

Y en caso de volver a fallar ahora sería inicializarlo a 34, a 46, etc.

con esto, y cambiando una aguja una vez por minuto, 8 horas al día, tendrás unos 208 días antes de "quemar" la EEPROM

Otra posibilidad (y así no hay que estar trasteando) es que en cada arranque utilices unas posiciones de memoria diferentes, por ejemplo:

Al arrancar lee las posiciones 0 y 1 y las combinas para darte una EEPROMbaseantigua.
Si EEPROMbaseantigua > =1012 EEPROMbase = 10, sino, EEPROMbase=EEPROMbaseantigua+12
Ahora copias esas 12 posiciones empezando en EEPROMbaseantigua a las 12 que empiezan en EEPROMbase.
Almacenas en las posiciones 0 y 1 el valor de EEPROMbase (así en el próximo arranque sabrá dónde buscar)

Y listo, tendrás arduino para más de 40 años.

Un saludo


Desconectado
Mensajes: 14
Registrado: 22 Jul 2017 17:33
Buenos días:
Repito, "Matao", muchísimas gracias.
Un saludo.


Desconectado
Mensajes: 26
Registrado: 02 Ene 2016 23:53
Con este SKETCH todos los servos y todos los reles se mueven en la misma dirección, me explico por ejemplo si quiero que el sevo3
o el rele 4 se muevan al revés de los demás creo que no se puede o por lo menos yo no he podido.Os adjunto el mio que si se puede, esta hecho para 4 servos pero puede ser para más todo es cuestión de copiar y pegar por si os interesa.
Disculpadme porque es muy basico no tengo ni idea de programación esta hecho a base de muchas horas y pruebas.

/* Decoder Arduino Servo DCC y reles para polarizar cambios.
Placa Arduino NANO Atmega 328.
Version: SEPTIEMBRE 2020.
Modificado: Santiago Pedra.
Este sketch Comvierte un Arduino NANO en un decoder DCC con
salida para 4 servos con reles para polarizar cambios.
Guardando la ultima posicion cuando se apague.
La señal DCC es separada opticamente y alimenta el pin2
(=Interrupt 0).
UTILIZAR IDE ARDUINO 1.6.12 LLC O SUPERIOR
" OJO SI EL DESVIO ES IZQUIERDO O DERECHO Y LA POSICION
COMO ESTA MONTADO EN EL TABLERO "" */

#include <EEPROM.h>
#include <DCC_Decoder.h>
#include <Servo.h>
#define kDCC_INTERRUPT 0

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
const byte maxservos = 4; //Numero de servos que hay conectados a
//este Arduino.
const byte servoTimer = 10; //Tiempo de cambio de angulo del servo.
//A menor valor -> mayor velocidad.

//Servo1******
int sMin1=0; //Valor minimo del servo1
int sMax1=180; //Valor maxi del servo1
int sVar1;
//Servo2******
int sMin2=0; //Valor minimo del servo2
int sMax2=180; //Valor maximo del servo2
int sVar2;
//Servo3******
int sMin3=0; //Valor minimo del servo3
int sMax3=180; //Valor maximo del servo3
int sVar3;
//Servo4******
int sMin4=0; //Valor minimo del servo4
int sMax4=180; //Valor maximo del servo4
int sVar4;

int pn1=4; // Nº pin para el servo 1
int rele1=5; // Nº pin para el rele de servo 1
int pn2=7; // Nº pin para el servo 2
int rele2=8; // Nº pin para el rele de servo 2
int pn3=10; // Nº pin para el servo 3
int rele3=11; // Nº pin para el rele de servo3
int pn4=12; // Nº pin para el servo 4
int rele4=13; // Nº pin para el rele de servo4

int sState1; // Estado para servo 1
int sState2; // Estado para servo 2
int sState3; // Estado para servo 3
int sState4; // Estado para servo 4

// PONER EL Nº DE DIRRECCION QUE INTERESE DEL 0 AL 1023 :
int Dir1= 0; // Direccion de memoria EEprom para servo 1
int Dir2= 1; // Direccion de memoria EEprom para servo 2
int Dir3= 2; // Direccion de memoria EEprom para servo 3
int Dir4= 3; // Direccion de memoria EEprom para servo 4
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Gestion de paquetes DCC
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
/* comvierte los paquetes de direcciones NMRA a un formato humano
de direccion. */
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;
boolean enable = (data & 0x01) ? 1 : 0;
switch (address){

case 1: /* Direccion de accesorio INTELLIBOX poner una entre 1
y 255. Esta direccion es unica aunque se pude poner la
misma direccion en OTRO decoder para otras funciones. */

servo1.attach(pn1);
if ((enable==0) && (sState1==1)){
for(sVar1 = sMin1; sVar1 <= sMax1; sVar1 += 1){ //Derecho
//for(sVar1 = sMax1; sVar1 >= sMin1; sVar1 -= 1){ //Izquierdo
servo1.write(sVar1);
delay(servoTimer);
}
digitalWrite (rele1, LOW);
sState1 = 0;
}
if ((enable==1) && (sState1==0)){
for(sVar1 = sMax1; sVar1 >= sMin1; sVar1 -= 1){ //Derecho
//for(sVar1 = sMin1; sVar1 <= sMax1; sVar1 += 1){ //Izquierdo
servo1.write(sVar1);
delay(servoTimer);
}
digitalWrite(rele1,HIGH);
sState1 = 1;
}
servo1.detach();
EEPROM.update(Dir1,sState1);
delay(300);
break;


case 2: /* Direccion de accesorio INTELLIBOX poner una entre 1
y 255. Esta direccion es unica aunque se pude poner la
misma direccion en OTRO decoder para otras funciones. */
servo2.attach(pn2);
if ((enable==0) && (sState2==1)){
//for(sVar2 = sMin2; sVar2 <= sMax2; sVar2 += 1){ //Derecho
for(sVar2 = sMax2; sVar2 >= sMin2; sVar2 -= 1){ //Izquierdo
servo2.write(sVar2);
delay(servoTimer);
}
digitalWrite (rele2, LOW);
sState2= 0;
}
if ((enable==1) && (sState2==0)){
//for(sVar2 = sMax2; sVar2 >= sMin2; sVar2 -= 1){ //Derecho
for(sVar2 = sMin2; sVar2 <= sMax2; sVar2 += 1){ //Izquierdo
servo2.write(sVar2);
delay(servoTimer);
}
digitalWrite(rele2,HIGH);
sState2 = 1;
}
servo2.detach();
EEPROM.update(Dir2,sState2);
delay(300);
break;


case 3: /* Direccion de accesorio INTELLIBOX poner una entre 1
y 255. Esta direccion es unica aunque se pude poner la
misma direccion en OTRO decoder para otras funciones. */
servo3.attach(pn3);
if ((enable==0) && (sState3==1)){
for(sVar3 = sMin3; sVar3 <= sMax3; sVar3 += 1){ //Derecho
//for(sVar3 = sMax3; sVar3 >= sMin3; sVar3 -= 1){ //Izquierdo
servo3.write(sVar3);
delay(servoTimer);
}
digitalWrite (rele3, LOW);
sState3 = 0;
}
if ((enable==1) && (sState3==0)){
for(sVar3 = sMax3; sVar3 >= sMin3; sVar3 -= 1){ //Derecho
//for(sVar3 = sMin3; sVar3 <= sMax3; sVar3 += 1){ //Izquierdo
servo3.write(sVar3);
delay(servoTimer);
}
digitalWrite(rele3,HIGH);
sState3=1;
}
servo3.detach();
EEPROM.update(Dir3,sState3);
delay(300);
break;

case 4: /* Direccion de accesorio INTELLIBOX poner una entre 1
y 255. Esta direccion es unica aunque se pude poner la
misma direccion en OTRO decoder para otras funciones. */

servo4.attach(pn4);
if ((enable==0) && (sState4==1)){
for(sVar4 = sMin4; sVar4 <= sMax4; sVar4 += 1){ //Derecho
//for(sVar4 = sMax4; sVar4 >= sMin4; sVar4 -= 1){ //Izquierdo
servo1.write(sVar4);
delay(servoTimer);
}
digitalWrite (rele4, LOW);
sState4 = 0;
}
if ((enable==1) && (sState4==0)){
for(sVar4 = sMax4; sVar4 >= sMin4; sVar4 -= 1){ //Derecho
//for(sVar4 = sMin4; sVar4 <= sMax4; sVar4 += 1){ //Izquierdo
servo1.write(sVar4);
delay(servoTimer);
}
digitalWrite(rele4,HIGH);
sState4 = 1;
}
servo4.detach();
EEPROM.update(Dir4,sState4);
delay(300);
break;

}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// configuracion (se ejecuta una vez)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);

// EMPIEZA EL SERVO 1 SEGUN DATO GUARDADO EN LA MEMORIA
servo1.attach(pn1);
sState1=EEPROM.read(Dir1);

if (sState1==0){
{
servo1.write(sMax1); //Cambio derecho
//servo1.write(sMin1);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele1, LOW);
}
if (sState1==1){
{
servo1.write(sMin1); //Cambio derecho
//servo1.write(sMax1);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele1, HIGH);
}
delay(300);
servo1.detach();

// EMPIEZA EL SERVO 2 SEGUN DATO GUARDADO EN LA MEMORIA
servo2.attach(pn2);
sState2=EEPROM.read(Dir2);

if (sState2==0){
{
//servo2.write(sMax2); //Cambio derecho
servo2.write(sMin2);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele2, LOW);
}
if (sState2==1){
{
//servo2.write(sMin2); //Cambio derecho
servo2.write(sMax2);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele2, HIGH);
}
delay(300);
servo2.detach();

// EMPIEZA EL SERVO 3 SEGUN DATO GUARDADO EN LA MEMORIA
servo3.attach(pn3);
sState3=EEPROM.read(Dir3);

if (sState3==0){
{
servo3.write(sMax3); //Cambio derecho
//servo3.write(sMin3);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele3, LOW);
}
if (sState3==1){
{
servo3.write(sMin3); //Cambio derecho
//servo3.write(sMax3);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele3, HIGH);
}
delay(300);
servo3.detach();

// EMPIEZA EL SERVO 4 SEGUN DATO GUARDADO EN LA MEMORIA
servo4.attach(pn4);
sState4=EEPROM.read(Dir4);

if (sState4==0){
{
servo4.write(sMax4); //Cambio derecho
//servo4.write(sMin4);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele4, LOW);
}
if (sState4==1){
{
servo4.write(sMin4); //Cambio derecho
//servo4.write(sMax4);//Cambio izquierdo
delay(servoTimer);
}
digitalWrite(rele4, HIGH);
}
delay(300);
servo4.detach();



DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );

pinMode(2,INPUT_PULLUP); /*Interrupcion 0 con resistencia interna
pull up */
pinMode(rele1,OUTPUT); //Salida rele servo1
pinMode(rele2,OUTPUT); //Salida rele servo2
pinMode(rele3,OUTPUT); //Salida rele servo3
pinMode(rele4,OUTPUT); //Salida rele servo4

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// loop principal (se ejecuta continuamente)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loop()
{

DCC.loop(); // Libreria DCC
}
Saludos
Santiago


Desconectado
Mensajes: 2
Registrado: 24 Mar 2019 12:46
Hola a todos



En este código hay algo que no entiendo. A ver si hay alguien que pueda aclarar esta duda



Esta función trae como parámetro la dirección del DCC ( int address )


Supongamos que la dirección que viene por parámetro es 2, si sigues el código se convierte en 5
Si la dirección DCC es 3 se convierte en 9 y así sucesivamente.

address = 2

address -= 1; //(2-1 = 1)

address *= 4;// (1 * 4 = 4)

address += 1; //(4 + 1 = 5)

address += (data & 0x06) >> 1; // (5 + 0 = 5)



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DCC packet handler
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
// Convert NMRA packet address format to human address
address -= 1;
address *= 4;
address += 1;
address += (data & 0x06) >> 1;



Por mas vueltas que le doy no le veo sentido, la llamada a esta función trae como parámetro la dirección correcta en formato entero.
¿Qué sentido tienen esas operaciones con la variable address?


Agradezco cualquier aclaración sobre esta parte del código


Desconectado
Mensajes: 2182
Registrado: 21 Mar 2014 12:52
Bueno, yo no me he pegado mucho con las características de los paquetes DCC pero veo lo siguiente:

Mirando el código completo de la función
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
   // Convert NMRA packet address format to human address
   address -= 1;
   address *= 4;
   address += 1;
   address += (data & 0x06) >> 1;
   boolean enable = (data & 0x01) ? 1 : 0;
   // The DCC Accessory Address is now stored in "address" variable
   Serial.print(F("Basic addr: "));
   Serial.println(address, DEC);
   Serial.print(F("Activate Status: "));
   Serial.println(enable, DEC);
}

veo que de "data" que es un octeto, nos interesan los 3 bits "bajos"
el bit más bajo es el estado de activación (boolean enable = (data & 0x01) ? 1 : 0;)
los dos siguientes bits, se añaden a la dirección de la siguiente manera:
desplazamos la dirección pasada como parámetro dos bits a la izquierda, pero .... suponemos que tiene como base 1
        address -= 1;
   address *= 4;
   address += 1;


Lo que creo que básicamente está haciendo es coger el valor de la dirección pasada como parámetro, echarla a la izquierda dos posiciones (multiplicar por 4) y poner en esas dos posiciones los bits 1 y 2 del parámetro "data" (address += (data & 0x06) >> 1;)

Esto es, parece como si la dirección viniese a caballon entre el parámetro address y el data

Un saludo


Desconectado
Mensajes: 93
Registrado: 26 Ago 2011 12:44
hola,

No he trabajado con esa librería pero parece que es para la conversión de los datos de dirección de un paquete DCC que lee la librería con la dirección de una salida según lo ponemos en nuestro mando de la central:


La relación entre el paquete DCC de control de accesorios

Imagen

y las salidas de un decodificador típico de accesorios de 4 salidas

Imagen

saludos,

Paco


Desconectado
Mensajes: 2
Registrado: 24 Mar 2019 12:46
Hola






Utilizo una central DCC++ con Arduino Mega y el motor shield


El parámetro data recibido es 00000001 o 00000000 para abrir o cerrar el desvío o luz si fuera el caso. Así al menos lo he verificado haciendo un print de cada parámetro recibido

Suponiendo que data sea 00000000, al hacer el AND con 0x06 (00000110) el resultado es 0 y aun desplazando este resultado 1 bit a la derecha sigue siendo 0
Del mismo modo si data es 00000001, al hacer AND con 0x06 (00000110) el resultado sigue siendo 0 incluyendo el desplazamiento de 1 bit a la derecha

El bolean enable es quien toma el valor 1 o 0 según la operación AND entre el valor de data y 0x01


Pienso que las operaciones iniciales con el valor address son para alguna variante especifica de DCC que yo desconozco, porque me funciona sin mayor problema eliminado esas 4 primeras líneas de la función.
De este modo los servos responden a la dirección que manda la central DCC++


servos[0].address = 1; // DCC address for this accessory
servos[0].outputPin = 13; // Arduino pin number for additional accessory output
servos[0].servo.attach(3); //Arduino pin number where servo is connected to
servos[0].offangle = 68; //Angle for DCC=off
servos[0].onangle = 126; //Angle for DCC=on

servos[1].address = 2; // DCC address for this accessory
servos[1].outputPin = 14; // Arduino pin number for additional accessory output
servos[1].servo.attach(4); //Arduino pin number where servo is connected to
servos[1].offangle = 68; //Angle for DCC=off
servos[1].onangle = 126; //Angle for DCC=on

servos[2].address = 3; // DCC address for this accessory
servos[2].outputPin = 15; // Arduino pin number for additional accessory output
servos[2].servo.attach(5); //Arduino pin number where servo is connected to
servos[2].offangle = 68; //Angle for DCC=off
servos[2].onangle = 126; //Angle for DCC=on


etc.


Sin borrar las 4 primeras líneas, me obliga a configurar el address de servos[1].address a 5 y el de servos[2].address a 9, etc.



No me preocupa excesivamente porque borrando las lineas me funciona perfectamente, pero tengo la curiosidad de saber el porqué de esa cuatro líneas


Saludos


Desconectado
Mensajes: 22
Registrado: 12 Dic 2018 13:30
Hola ,
Sigo leyendo mucho aqui, y de vez en cuando pregunto para resolver las dudas planteadas, en este caso tambien uso Arduino para mover desvios con servos, y utilizo el UNO R3, pero cuando veo las conexiones "attach" para los servos, y veo pin 22, 23, 24,......pues me pierdo pues solo veo que desde la 2 que usa las entradas DCC, tengo la posibilidad de utilizar hasta la 13 , teniendo solamente 10 posibilidades, y no alcanzo a ver mas.

Alguien podria indicarme si se utiliza un" modulo Controlador de servos PCA9685", pues no veo en la declaracion del principio del programa la llamada a las librerias.

Tambien me gustaria conocer el esquema de trabajao con su cableado desde el Arduino.

Y conocer si se utiliza otro tipo de tablero que no sea el UNO R3.

Gracias por la atencion prestada.

Saludos cordiales.

Lukas


Volver a Digital, Electricidad e Informática

Síguenos en Facebook Síguenos en Youtube Síguenos en Instagram Feed - Nuevos Temas
©2017   -   Información Legal