Comandos en LibreServo (primera parte)

He dedicado mucho tiempo a la parte de comandos en LibreServo y creo que es una de las partes más importantes del proyecto, es cómo se presenta LibreServo ante el usuario. Ofrece una flexibilidad y posibilidades que yo nunca he visto en ningún fabricante.

La documentación de los comandos la dividiré en dos artículos, este artículo está más centrado en la descripción de los comandos y la segunda parte está centrada en ejemplos y explicación de ejecución en LibreServo.

Los comandos de LibreServo son los siguientes:

Comandos de movimiento

Son comandos específicos para el movimiento y control del servomotor. Los diferentes movimientos y sus curvas se explican más detenidamente el el artículo sobre curvas de movimiento.


Movimiento lineal [M]

  • S12M12000[:1000]

La anotación que vemos de 12000[:1000] indica que el comando M obliga a pasar un parámetro, pero el segundo parámetro es opcional. Además, nos indica que se utiliza el carácter ':' para separar los parámetros. Esta anotación se utiliza para el resto de comandos.

Volviendo al comando, el comando M es un comando en el que el servomotor se mueve a velocidad constante hasta la posición final.

param1: el primer parámetro indica la posición a la que queremos ir (un giro de 360 grados es 65.535). Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): el segundo parámetro indica en milisegundos, ms, el tiempo en el que deberá de completar el movimiento, si no se indica tiempo alguno LibreServo intentará llegar lo antes posible. Rango: 0, +2.147.483.647

Ejemplo:
S12M12000:1000; El Servomotor 12 deberá moverse a la posición 12000 en 1000 ms (1 segundo).

Movimiento trapezoidal [MT]

  • S12MT12000[:150]:1000;

El comando MT es un movimiento de aceleración y desaceleración constante calculada en base a una duración de la aceleración fijada.

param1: posición final. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): tiempo de aceleración y desaceleración en ms. Si no se especifica, se coge el valor por defecto guardado en flash (t_ramp_t). Si el tiempo de aceleración y desaceleración es mayor que el tiempo total de movimiento, se reducen para que entren en el tiempo total de movimiento. Rango: 0, +2.147.483.647
param3: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S12MT-8000:1000; El servomotor 12 deberá moverse a la posición -8000 en 1000ms. El tiempo de rampa será el que esté en t_ramp_t
S12MT-8000:150:1000; El servomotor 12 deberá moverse a la posición -8000 en 1000ms. El tiempo de rampa será de 150ms

Movimiento trapezoidal 50% [Mt]

  • S12Mt12000:1000;

Es igual que MT, pero el tiempo de aceleración será la mitad del tiempo total de movimiento y el tiempo de desaceleración la otra mitad.

param1: posición final. Rango: -2.147.483.646, +2.147.483.647
param2: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S12MT-8000:1000; El servomotor 12 deberá moverse a la posición -8000 en 1000ms. El tiempo de rampa será de 500ms (500*2 = 1000)

Movimiento trapezoidal acelerado [MA]

  • S12MA12000[:150]:1000;

Es un movimiento trapezoidal, pero en el que en vez de indicar el tiempo de aceleración, se indica la aceleración que se quiere y LibreServo calcula el tiempo requerido de aceleración y desaceleración.

param1: posición final. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): Aceleración y desaceleración de la rampa. Si no se especifica, se coge el valor por defecto guardado en flash (a_ramp_t). Si con la aceleración indicada no se llega al destino, se hará un movimiento lineal. Rango: 0, +2.147.483.647
param3: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S12MA-8000:1000; El servomotor 12 deberá moverse a la posición -8000 en 1000ms. La aceleración de la rampa será el que esté en a_ramp_t
S12MA11000:125:1000; El servomotor 12 deberá moverse a la posición -8000 en 1000ms. La aceleración de la rampa será de 125

Movimiento Senoidal [MS]

  • S12MS12000[:150]:1000;

El comando MS produce un movimiento con una aceleración y desaceleración variable en forma de seno, de ahí su nombre.

param1: posición final. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): tiempo de aceleración y desaceleración en ms. Si no se especifica, se coge el valor por defecto guardado en flash (t_ramp_s). Si el tiempo de aceleración y desaceleración es mayor que el tiempo total de movimiento, se reducen para que entren en el tiempo total de movimiento. Rango: 0, +2.147.483.647
param3: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S12MS50000:2000; El servomotor 12 deberá moverse a la posición 50000 en 2000ms. El tiempo de rampa será el que esté en t_ramp_s
S5MS50000:150:2000; El servomotor 5 deberá moverse a la posición 50000 en 2000ms. El tiempo de rampa será de 150ms

Movimiento Senoidal 50% [Ms]

  • S12Ms12000:1000;

Es igual que MS, pero el tiempo de aceleración será la mitad del tiempo total de movimiento y el tiempo de desaceleración la otra mitad.

param1: posición final. Rango: -2.147.483.646, +2.147.483.647
param2: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S8MT-8000:3000; El servomotor 8 deberá moverse a la posición -8000 en 3000ms. El tiempo de rampa será de 1500ms (1500*2 = 3000)

Movimiento Hermítico [MH]

  • S12MH12000[:0][:8000][:0]:1000;

Por norma, todos los movimientos presuponen que el servomotor empieza un movimiento de parado y termina parado, pero en esta curva indicamos el punto inicial de movimiento, la velocidad inicial, el punto final y la velocidad final y LibreServo calcula toda la ruta. Es ideal para cuando queremos interrumpir un movimiento y que el servomotor parta ya de la velocidad en la que estaba, para hacer movimientos encadenados complejos... o para generar curvas diferentes a los movimientos anteriores.

param1 (opcional): posición inicial. Si no se especifica es la que tuviera al empezar el movimiento. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): velocidad inicial. Si no se especifica es el que tuviera al empezar el movimiento. Rango: -2.147.483.646, +2.147.483.647
param3: posición final. Rango: -2.147.483.646, +2.147.483.647
param4 (opicional): velocidad final. Si no se especifica, es cero. Rango: -2.147.483.646, +2.147.483.647
param5: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S7MH12000:1000; El servomotor 7 se moverá a la posición 12000 en 1000ms. La posición y velocidad inicial del movimiento será la que esté justo al empezar la curva. Además presupone que la velocidad final que queremos será cero
S15MH5000:12000:1500; El servomotor 15 se moverá a la posición 12000 en 1500ms. La posición inicial es 5000, la velocidad inicial será la que esté justo al empezar la curva y la final se presupone que es cero
S3MH1300:0:-12000:-300:4000; El servomotor 3 se moverá a la posición -12000 en 4000ms. La posición inicial es 1300 con una velocidad inicial de cero y final de -300

Movimiento Continuo [MC]

  • S12MC65535[:1000]

Igual que el Movimiento Lineal, MC se comporta de la misma forma pero tiene en cuenta la velocidad del servomotor y no su posición.

param1: velocidad final a la que queremos ir (un giro de 360 grados es 65.535, velocidad de una vuelta por segundo sería 65535). Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): el segundo parámetro indica en milisegundos, ms, el tiempo en el que deberá alcanzar la velocidad, si no se indica tiempo alguno LibreServo intentará llegar lo antes posible. Rango: 0, +2.147.483.647
Ejemplo:
S9MC-131070:1000; El Servomotor 9 deberá moverse -2 vueltas por segundo (65535*2 = 131070) en 1000 ms (1 segundo)

Movimiento Continuo trapezoidal [MCT]

  • S12MCT65535[:150]:1000;
param1: velocidad final. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): tiempo de aceleración y desaceleración en ms. Si no se especifica, se coge el valor por defecto guardado en flash (t_ramp_t). Si el tiempo de aceleración y desaceleración es mayor que el tiempo total de movimiento, se reducen para que entren en el tiempo total de movimiento. Rango: 0, +2.147.483.647
param3: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S5MCT-32767:1000; El servomotor 5 deberá alcanzar la velocidad de menos media vuelta por segundo en 1000ms. El tiempo de rampa será el que esté en t_ramp_t
S4MCT-32767:150:1000; El servomotor 4 deberá alcanzar la velocidad de menos media vuelta por segundo en 1000ms. El tiempo de rampa será de 150ms

Movimiento Continuo Senoidal [MCS]

  • S12MCS65535[:150]:1000;
param1: velocidad final. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): tiempo de aceleración y desaceleración en ms. Si no se especifica, se coge el valor por defecto guardado en flash (t_ramp_s). Si el tiempo de aceleración y desaceleración es mayor que el tiempo total de movimiento, se reducen para que entren en el tiempo total de movimiento. Rango: 0, +2.147.483.647
param3: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S6MCS65535:2000; El servomotor 6 deberá alcanzar la velocidad de una vuelta por segundo en 2000ms. El tiempo de rampa será el que esté en t_ramp_s
S2MCS65535:150:2000; El servomotor 2 deberá alcanzar la velocidad de una vuelta por segundo en 2000ms. El tiempo de rampa será de 150ms

Movimiento Contínuo Hermítico [MCH]

  • S12MCH12000[:0][:8000][:0]:1000;

En este comando pasamos la velocidad inicial y final del movimiento así como la aceleración inicial y final que queramos y LibreServo calcula toda la ruta. Es ideal para cuando queremos interrumpir un movimiento y que el servomotor parta ya de la velocidad en la que estaba, para hacer movimientos encadenados complejos... o para generar curvas diferentes a los movimientos anteriores.

param1 (opcional): velocidad inicial. Si no se especifica es el que tuviera al empezar el movimiento. Rango: -2.147.483.646, +2.147.483.647
param2 (opcional): aceleración inicial. Si no se especifica es el que tuviera al empezar el movimiento. Rango: -2.147.483.646, +2.147.483.647
param3: velocidad final. Rango: -2.147.483.646, +2.147.483.647
param4 (opicional): aceleración final. Si no se especifica, es cero. Rango: -2.147.483.646, +2.147.483.647
param5: tiempo total de movimiento. Rango: 0, +2.147.483.647

Ejemplo:
S3MCH65535:1000; El servomotor 3 alcanzará la velocidad de una vuelta por segundo en 1000ms. La velocidad y aceleración inicial del movimiento será la que esté justo al empezar la curva. Además presupone que la velocidad final que queremos será cero
S7MCH65535:-32767:1500; El servomotor 7 alcanzará la velocidad de menos media vuelta por segundo en 1500ms. La velocidad inicial es de una vuelta por segundo, la aceleración inicial será la que esté justo al empezar la curva y la final se presupone que es cero
S16MCH0:10:131070:-300:4000; El servomotor 16 alcanzará la velocidad de dos vueltas por segundo en 4000ms. La velocidad inicial es de cero con una aceleración inicial de 10 y final de -300

Movimiento PWM [MP]

  • S12MP500[:1000];

Para controlar directamente el PWM del motor, utilizamos el comando MP.

param1: PWM del motor. Rango: -1800, +1800
param2 (optional): Tiempo que durará el comando. Si no introducimos tiempo el comando acabará al momento pero dejará el motor con el PWM que hayamos introducido. Si introducimos tiempo, al acabar éste, el motor se parará.

Ejemplo:
S12MP-500; El servomotor 12 pondrá un PWM de 500 con dirección negativa
S10MP300:1000; El servomotor 10 pondrá un PWM de 300 durante 1000ms

Motor Libre [MF]

  • S12MF;

El comando MF deshabilita el motor. Lo que hace es apagar el puente en H. En cuanto llegue otro comando de movimiento, el puente en H se habilita de manera automática.

Ejemplo:
S14MF; El servomotor 14 deshabilita el motor

Espera Motor [MW]

  • S12MW250;

El comando MW funciona como un Delay. Introduce una espera. Es útil para cuando queramos mandar de un mismo comando varias tareas que queremos que se hagan separadas en el tiempo y no una detrás de otra.

param1: Los milisegundos de espera: Rango: 0, +2.147.483.647

Ejemplo:
S17MW500; El servomotor 17 espera 500ms

Comandos de luz y sonido


LED RGB [L]

  • S12L150:25:210;

El comando L controla el color e intensidad del LED RGB que trae incorporado LibreServo. Teóricamente podría mostrar cualquier color que queramos.

param1: Intensidad color rojo. Rango: 0, +255
param2: Intensidad color verde. Rango: 0, +255
param3: Intensidad color azul. Rango: 0, +255

Ejemplo:
S7L150:25:210; El LED del servomotor 7 toma un color lila

LED Arcoíris [LR]

  • S12LR;

El comando LR indica al LED que empiece a rotar por los colores de manera automática.


Ejemplo:
S9LR; El LED del servomotor 9 empiza a rotar en colores e intensidades de manera automática

Tono [T]

  • S12T2093:200:50;

El comando T intenta generar un tono valiéndose del propio motor del servomotor. ¡No hace falta ningún altavoz para generar tu música preferida! Se recomienda utilizar frecuencias altas, por encima de 1500Hz, para que funcione mejor, octava sexta o séptima en adelante dependiendo de cada servomotor. En frecuencias bajas puede que no suene y en vez de ello vibre todo el servomotor.

param1: Frecuencia del tono/nota. Se recomienda usar frecuencias por encima de la sexta octava musical. Rango: 0, +2.147.483.647
param2: Duración de la nota en milisegundos. Rango: 0, +2.147.483.647
param3: Amplitud de la nota, su volumen. Rango: 0, +100

Ejemplo:
S12T3136:200:50; El servomotor 12 genera un tono de SOL6 durange 200ms con una amplitud del 50%
Frecuencia notas musicales Frecuencia notas musicales @ciudadpentagrama

Comandos de lectura de variables

Los comandos de lectura de variables se ejecutan desde un administrador de tareas independiente. Dentro de las variables a recuperar, existen variables RAM que son sólo de lectura y que no se guardan tras apagar LibreServo y existen variables FLASH, que son de lectura y escritura y que se pueden modificar y/o guardar para que en el siguiente arranque de LibreServo mantenga el valor que nosotros le hemos dado.

Las variables son:

IDNombreR/WDefiniciónValor por defecto
0Temp_internaRTemperatura en grados (x10) medida internamente en el microcontrolador
1Temp_externaRTemperatura en grados (x10) medida externamente en el sensor de temperatura NTC
2Temp_interna_rawRLectura directa (12 bits) del sensor de temperatura interno al microcontrolador
3Temp_interna_kalmanRLectura del sensor de temperatura interno al microcontrolador tras filtro Kalman
4Temp_externa_rawRLectura directa (12 bits) del sensor de temperatura externo NTC
5Temp_externa_kalmanRLectura del sensor de temperatura externo NTC tras filtro Kalman
6VoltageRVoltage, tensión de alimentación de LibreServo (x100)
7Voltage_rawRLectura (12 bits) de la tensión de alimentación
8Voltage_kalmanRLectura de la tensión de alimentación tras filtro Kalman
9CorrienteRCorriente consumida por el servomotor en mA
10Corriente_rawRLectura (12 bits) de la corriente consumida por el servomotor
11Corriente_kalmanRLectura de la corriente tras filtro Kalman
12Encoder_rawRLectura posición encoder (16 bits)
13Encoder_kalmanRLectura posición encoder tras filtro Kalman
14Velocidad_encRVelocidad del servomotor calculada con la posición del encóder
15Aceleracion_encRAceleración del servomotor calculada con la posición del encóder
16Velocidad_simRVelocidad del servomotor calculada con la posición que queremos del servomotor
17Aceleracion_simRAceleración del servomotor calculada con la posición que queremos del servomotor
18Posicion_objetivoRPosición que LibreServo está marcando
19ErrorRDiferencia entrePosición objetivo y la lectura del encóder tras filtro Kalman (Encoder_kalman)
20DErrorRError diferencial (PID)
21PDTermRTérmino PD del PID
22ItermRTérmino Integral del PID
23PWMRPWM del motor
24PWM_preRPWM deseado antes de mirar si el consumo de corriente es excesivo
99Version_LSRVersión interna de LibreServo
100ID ServomotorR/WID del servomotor, por el que escuchará los comandos1
101q_corrienteR/WIncertidumbre proceso corriente (x1000) (Kalman)1200
102q_temp_extR/WIncertidumbre proceso temperatura NTC (x1000) (Kalman)1200
103q_temp_intR/WIncertidumbre proceso temperatura interna STM32 (x1000) (Kalman)1200
104q_voltsR/WIncertidumbre proceso voltaje (x1000) (Kalman)1200
105q_encoderR/WIncertidumbre proceso encoder (x1000) (Kalman)1200
106varianza_corrienteR/WVarianza corriente (x1000) (Kalman)1000
107varianza_temp_extR/WVarianza temperatura NTC (x1000) (Kalman)2500
108varianza_temp_intR/WVarianza temperatura interna STM32 (x1000) (Kalman)150
109varianza_voltsR/WVarianza voltaje (x1000) (Kalman)150
110varianza_encoderR/WVarianza encoder (x1000) (Kalman)5000
111vel_serieR/WVelocidad puerto Serie115200
112corte_temp_extR/WTemperatura en grados (x10) en el NTC que para el motor800
113corte_temp_intR/WTemperatura en grados (x10) interna del STM32 que para el motor800
114corte_volts_altoR/WVoltaje (x100) que si supera para el motor1600
115corte_volts_bajoR/WVoltaje (x100) que si no supera para el motor450
116corte_corrienteR/WMáxima corriente en mA. Control de torque/par7000
117uso_crcR/WUso CRC (0=False, 1=True, 2=Both)2
118CRC_START_CCITTR/WCRC valor inicial0x1D0F
119CRC_POLY_CCITTR/WCRC polinomio0x1021
120K_P_LSR/WConstante P PID modo servomotor200
121K_D_LSR/WConstante D PID modo servomotor1000
122K_I_LSR/WConstante I PID modo servomotor170
123K_P_MR/WConstante P PID modo motor200
124K_D_MR/WConstante D PID modo motor1000
125K_I_MR/WConstante I PID modo motor170
126offset_corrienteR/WCompensación corriente (x1000) (0-222 -> -1000 - +1000)111
127offset_temp_intR/WCompensación temperatura interna (x10) (0-300 -> -150 - +150)150
128offset_temp_extR/WCompensación temperatura NTC (x10) (0-300 -> -150 - +150)150
129envio_si_leoR/WEnviar datos por el puerto serie si leo otros datos por el puerto (0=False, 1=True, 2=True cancelar sólo el comando de envío actual)2
130saludo_inicialR/WSaludo inicial (0=False, 1=True)1
131min_posicionR/WLímite posición mínima (0-4294967294 -> -2147483647 - +2147483647)2147483647
132max_posicionR/WLímite posición máxima (0-4294967294 -> -2147483647 - +2147483647)2147483647
133limit_posicionR/WUtilizar límites posición (0=False, 1=True)0
134t_ramp_tR/WTiempo por defecto rampa trapezoidal200
135t_ramp_sR/WTiempo por defecto rampa senoidal200
136a_ramp_tR/WAceleración por defecto en rampa trapezoidal100
137deadbandR/WDeadband5

GET [G]

  • S12G116;

El comando G pide a LibreServo un parámetro/variable interno que nos devolverá por el puerto Serie. El comando G como el resto de comandos GX van en un administrador de tareas separado del principal.

param1: ID de la variable de la que queremos ver su valor.

Ejemplo:
S11G13; Leer la posición del servomotor 11

Get Varios [GS]

  • S12GS5[,7,8,100,102]:10:500;

El comando GS nos devuelve no sólo una variable, sino varias variables que querramos (hasta un máximo de 15). Además, permite programar que nos devuelva los valores cada X milisegundos.

param1: Parámetro donde indicamos el ID o IDs de las variables a leer separados por comas ','. Rango: 0, +137.
param2: Número de veces que queremos que nos envíe el valor de las variables. Rango: 1, +2.147.483.647
param3: Cada cuántos milisegundos queremos que nos envíe el valor de las variables. Rango: 1, +2.147.483.647

Ejemplo:
S12GS9,23:1000:1; Leer del servomotor 12 el consumo de corriente y el PWM del motor 1000 veces con un tiempo entre lecturas de 1 milisegundo. Estará un segundo enviando datos
S5GS0,1:1,1; Leer las temperaturas del servomotor 5. Sólo se enviarán una vez

Get Varios con Cabecera [Gs]

  • S12Gs5[,7,8,100,102]:10:500;

El comando Gs es igual que el comando GS con una diferencia, nos envía en un primer momento una línea con el nombre de todas las variables que queremos separado por comas, esto es muy útil para sacar a un fichero .csv la salida, o para ver las variables dibujadas en el Serial Plotter de Arduino. El comando Gs nos devuelve no sólo una variable, sino varias variables que querramos (hasta un máximo de 15). Además, permite programar que nos devuelva los valores cada X milisegundos.

param1: Parámetro donde indicamos el ID o IDs de las variables a leer separados por comas ','. Rango: 0, +137.
param2: Número de veces que queremos que nos envíe el valor de las variables. Rango: 1, +2.147.483.647
param3: Cada cuántos milisegundos queremos que nos envíe el valor de las variables. Rango: 1, +2.147.483.647

Ejemplo:
S3Gs9,23:1000:1; Leer del servomotor 3 el consumo de corriente y el PWM del motor 1000 veces con un tiempo entre lecturas de 1 milisegundo. Estará un segundo enviando datos. Envía una línea inicial de cabecera
S9Gs0,1:1,1; Leer las temperaturas del servomotor 9. Sólo se enviarán una vez y con cabecera

Espera Get [GW]

  • S12GW250;

El comando GW funciona como un Delay. Introduce una espera en el administrador de tareas de la lectura de variables. Es útil para cuando queramos empezar a recibir datos pero tras una espera para coincidir con algún comando de motor específico.

param1: Los milisegundos de espera. Rango: 0, +2.147.483.647

Ejemplo:
S16GW500; El servomotor 16 espera 500ms en el administrador de tareas de la lectura de variables

Set [S]

  • S12S111:9600;

Con el comando S cambiamos el valor de las variables de LibreServo que sean escribibles.

param1: ID variable a modificar. Rango: 0, +137
param2: Nuevo valor de la variable. Rango: -2.147.483.646, +2.147.483.647

Ejemplo:
S1S100:10 Cambia el ID del servomotor 1 a 10
S10S111:9600 Cambia la velocidad del puerto serie [variable 111] del servomotor 10, a 9600 bps

Guardar [SV]

  • S12SV;

El comando SV guarda la configuración actual de LibreServo, el valor de las variables modificables, en la Flash del microcontrolador, así la configuración no se perderá al apagar el servomotor.


Ejemplo:
S39SV; Guarda el valor de todas las variables modificables del servomotor 39 en Flash

Reset variable [RV]

  • S12RV116

El comando RV devuelve el valor de una variable al valor que tenga en flash. Si justo antes se ha guardado la variable con el comando SV, dicha variable tendrá en memoria el mismo valor que en flash.

param1: ID variable a resetear. Rango: 0, +137

Ejemplo:
S23RV137; Devuelve el valor en flash del servomotor 23 a la variable deadband

Reset variable valor por defecto [Rv]

  • S12Rv116

El comando Rv devuelve el valor de una variable al valor de defecto especificado en la tabla. Y guarda dicha variable en flash.

param1: ID variable a resetear. Rango: 0, +137

Ejemplo:
S18Rv117; La variable 117 (uso_crc) del servomotor 18, vuelve a su valor por defecto, 2

Reset Servo [RS]

  • S12RS;

El comando RS devuelve el valor de todas las variables del servomotor al que tengan en flash.


Ejemplo:
S10RS; El servomotor 10 devuelve el valor que tenga en flash a todas sus variables

Reset Servo por defecto [Rs]

  • S12Rs

El comando Rs cambia el valor de todas las variables a su valor por defecto y lo guarda en flash.


Ejemplo:
S45Rs; El servomotor 45 devuelve el valor de todas sus variables a su valor por defecto y las guarda en flash

Suscripción

Recibe un email por cada nuevo artículo.

Esta pregunta es para comprobar si usted es un visitante humano y prevenir envíos de spam automatizado.

4 + 5 =
Resuelva este simple problema matemático y escriba la solución; por ejemplo: Para 1+3, escriba 4.