12 de febrero de 2017

Configurar firewall en openSuse Leap 42.2

Aún teniendo los puertos abiertos en nuestro router, puede ser que el firewall de openSuse esté también bloqueando las conexiones de alguno de nuestros programas. Por ello, debemos abrir los puertos correspondientes en nuestro firewall.

Para cada programa, crearemos un archivo de texto con los puertos a abrir para que así nos aparezca la opción correspondiente en la configuración del firewall.

Lo primero que he hecho, es crearme una carpeta llamada "Configuraciones firewall" donde guardaré los distintos archivos para tenerlos disponibles para otras veces.

Una vez dentro de la carpeta, hacemos clic con el botón derecho del ratón y, en el menú contextual elegimos Crear nuevo > Archivo de texto... tal como se ve en la imagen:


Para nuestro ejemplo, lo nombraremos como "ktorrent" (sin extensión), ya que vamos a abrir los puertos para ese programa que nos permite descargar ISOs de nuestras distribuciones Linux favoritas:


Una vez creado nuestro archivo de texto, lo abriremos para editarlo.


El texto que debemos escribir es el siguiente:

## Name: KTorrent
## Description: Abre puertos para KTorrent incluido DHT

# space separated list of allowed TCP ports
TCP="6881"

# space separated list of allowed UDP ports
UDP="6881 7881 8881"

# space separated list of allowed RPC services
RPC=""

# space separated list of allowed IP protocols
IP=""

# space separated list of allowed UDP broadcast ports 

Por el texto, ya podemos deducir qué es cada cosa:
En la primera línea, indicamos el nombre del programa para el que vamos a abrir puertos.
En la segunda, escribimos una breve descripción de qué puertos abrimos.
En las siguientes líneas especificaremos los puertos TCP y UDP que vamos a usar, de forma que queden entrecomillados y separados por espacios.

[ Los puertos que he utilizado, son los que aparecen por defecto en ktorrent. De todas formas, conviene revisarlos en la configuración de vuestro ktorrent, esto es sólo un ejemplo ]

Guardamos el documento y, a continuación, lo copiaremos en la carpeta de servicios del firewall. La ruta donde lo copiaremos es "/etc/sysconfig/SuSEfirewall2.d/services/". Para poder escribir en esa dirección, necesitaremos permisos de administrador, así que podéis abrir vuestro gestor de archivos o bien, abriendo un terminal donde tenemos el archivo, poner lo siguiente:

sudo cp ktorrent /etc/sysconfig/SuSEfirewall2.d/services/

Se nos pedirá la contraseña de root y, tras escribirla, ya se habrá copiado nuestro documento.


Ahora que ya hemos copiado el archivo, ya podemos configurar el firewall para que permita las conexiones de nuestro ktorrent. Abrimos entonces Yast:


Evidentemente, se nos pedirá la contraseña de administrador. La ponemos y aceptamos:


Una vez que entremos en el "Centro de control", pulsaremos en "Cortafuegos" dentro de la sección "Seguridad y usuarios":


Una vez dentro del cortafuegos, iremos a la sección "Servicios autorizados":


En el desplegable donde están los servicios, tendremos la opción que hemos creado ("KTorrent"). Basta con seleccionarla y pulsar el botón "Añadir":


Una vez pulsado, lo veremos en la lista de servicios autorizados con la misma descripción que habíamos puesto en nuestro archivo de texto. Debemos pulsar "Siguiente":


Veremos un resumen. Ya sólo falta pulsar en "Terminar":


Y así tendremos nuestros puertos abiertos en el firewall de nuestro openSuse.

A continuación, os dejo varios archivos de configuración que utilizo:

aMule:
## Name: aMule
## Description: Abre puertos para aMule.

# space separated list of allowed TCP ports
TCP="40000 50000"

# space separated list of allowed UDP ports
UDP="40001 40003"

# space separated list of allowed RPC services
RPC=""

# space separated list of allowed IP protocols
IP=""

# space separated list of allowed UDP broadcast ports 

Heroes of the Storm:
## Name: Heroes of the Storm
## Description: Abre puertos para Heroes of the Storm.

# space separated list of allowed TCP ports
TCP="1119 6113 1120 3724"

# space separated list of allowed UDP ports
UDP="1119 6113 1120 3724"

# space separated list of allowed RPC services
RPC=""

# space separated list of allowed IP protocols
IP=""

# space separated list of allowed UDP broadcast ports 

ktorrent:
## Name: KTorrent
## Description: Abre puertos para KTorrent incluido DHT

# space separated list of allowed TCP ports
TCP="6881"

# space separated list of allowed UDP ports
UDP="6881 7881 8881"

# space separated list of allowed RPC services
RPC=""

# space separated list of allowed IP protocols
IP=""

# space separated list of allowed UDP broadcast ports 

Plex:
## Name: Plex Media Server
## Description: Abre puertos para Plex Media Server con broadcast
# space separated list of allowed TCP ports
TCP="3005 8324 32400 32469"

# space separated list of allowed UDP ports
UDP="1900 5353 32410 32412 32413 32414"

# space separated list of allowed RPC services
RPC=""

# space separated list of allowed IP protocols
IP=""

# space separated list of allowed UDP broadcast ports 

Una vez que hemos creado un archivo para cada programa, podemos copiarlos todos con el siguiente comando:

sudo cp * /etc/sysconfig/SuSEfirewall2.d/services/


Lo siguiente sería volver a la configuración del cortafuegos y añadir cada uno de ellos:


Parece algo tedioso pero, al final, para mí, ha sido el método más cómodo para añadir servicios al cortafuegos de openSuse.

Espero que os haya servido de ayuda.


15 de febrero de 2016

Arduino y Processing 3: Mostrar los datos de dos sensores al mismo tiempo

Previamente, hemos visto enviar información desde Arduino a Procesing de una forma muy básica y, posteriormente, habíamos aprovechado la comunicación por puerto serie probando a controlar la dirección de caída de unas gotas de lluvia con un potenciómetro. Si deseáis revisar esas dos entradas, podéis encontrarlas en los siguientes enlaces:


En esta tercera entrega, veremos cómo recibir varios datos simultáneamente por nuestro puerto serie y los mostraremos gráficamente como si de un osciloscopio se tratase.

Para los datos, he decidido colocar dos fotorresistores en nuestra Arduino basándome en una entrada antigua en la que explicaba cómo utilizar un sensor de luz para controlar el brillo de una LED. Podéis leer esa entrada en el siguiente enlace:


El nivel de luz que recibamos en cada uno de los dos sensores, será el que enviemos por puerto serie hacia Processing y lo representaremos gráficamente. He aquí una imagen de ejemplo de cómo deberíamos verlo:


Empezaremos por preparar la Arduino y colocar los dos sensores. Las resistencias que he usado para las LEDs son de 330Ω y las de los sensores son de 10kΩ. Así es cómo he colocado los componentes:
Imagen creada con Fritzzing

Tal como había hecho en la entrada en la que se explicaba cómo usar un sensor de luz, he colocado una LED para cada sensor, de tal forma que, cuanta menos luz detecte, más brillo le daré a la LED correspondiente.

/* Definimos pines */
#define PIN_LED1 9   // Conectamos una LED en el pin 9
#define PIN_LED2 10  // Conectamos una LED en el pin 10
#define PIN_LUZ1 A0  // Conectamos un fotorresistor en el pin analógico A0
#define PIN_LUZ2 A5  // Conectamos un fotorresistor en el pin analógico A5

String dato;         // Para enviar un dato por el puerto serie

void setup()
{
  /* Establecemos los pines de las LED como salida */
  pinMode(PIN_LED1, OUTPUT);
  pinMode(PIN_LED2, OUTPUT);
  
  /* Establecemos los fotorresistores como entrada */
  pinMode(PIN_LUZ1, INPUT); 
  pinMode(PIN_LUZ2, INPUT); 
  
  /* Iniciamos el puerto serie */
  Serial.begin(9600);
}

void loop()
{
  /* Obtenemos valores de los fotorresistores (varían de 0 a 900) */
  int nivelDeLuz1 = analogRead(PIN_LUZ1);  // fotorresistor1
  int nivelDeLuz2 = analogRead(PIN_LUZ2);  // fotorresistor2
  
  /* Escalamos los valores para el brillo de las LED */
  nivelDeLuz1 = map(nivelDeLuz1, 0, 900, 0, 255);
  if(nivelDeLuz1 < 15){ // si el valor es muy bajo...
    nivelDeLuz1 = 0;    // ...lo hago 0 directamente
  }
  
  nivelDeLuz2 = map(nivelDeLuz2, 0, 900, 0, 255);
  if(nivelDeLuz2 < 15){
    nivelDeLuz2 = 0;
  } 
  
  /* Nos aseguramos de que los niveles de luz son correctos */
  nivelDeLuz1 = constrain(nivelDeLuz1, 0, 255);
  nivelDeLuz2 = constrain(nivelDeLuz2, 0, 255);   
  
  /* Aplicamos el brillo a las LED */
  analogWrite(PIN_LED1, nivelDeLuz1);
  analogWrite(PIN_LED2, nivelDeLuz2);
  
  /* Enviamos dato por puerto serie */
  dato = "";
  dato += nivelDeLuz1;
  dato += ",";
  dato += nivelDeLuz2;
  Serial.println(dato);
  
  delay(50); // pequeña pausa para no saturar el puerto serie
}


En general, el código parece fácil de entender. Debemos de tener en cuenta el uso la función constrain para evitar valores no deseados.

Supongamos el código siguiente:

  DATO = constrain(X, A, B);   

Si el valor de X es menor que A, el valor de DATO será A. Si el valor de X es mayor que B, el valor de DATO será B. Y, finalmente, si el valor de X está entre A y B, el valor de DATO será X. Con ello, nos aseguramos que el valor de DATO estará siempre entre A y B.

Para enviar el dato por el puerto serie, lo haremos con una variable tipo String. Como vemos al final del código, la inicializamos como vacía y luego la "construimos" poco a poco añadiendo los dos niveles de luz separados por una coma ",". Eso lo usaremos posteriormente para separarlos al recibirlos en Processing.

Tal como está ahora mismo nuestra Arduino, ya podemos comprobar el funcionamiento correcto de los sensores fijándonos en las dos LED y abriendo el Monitor Serie del IDE Arduino:


Una vez comprobado el correcto funcionamiento de nuestra Arduino, vamos con Proccessing.

Al igual que en la entrega anterior, tendremos dos archivos: uno para el programa principal, y otro con una clase. Podemos verlo a continuación:


Empezamos por la clase Punto, que nos servirá para gestionar cada uno de los puntos de la gráfica y el desplazamiento hacia la izquierda.

Este es el código que he utilizado:

class Punto {
  float x;        // Coordenada horizontal
  float y;        // Coordenada vertical
  int velocidad;  // Píxels que desplazo a la izquierda en cada movimiento
  
  Punto(){
    x = width;
    y = height / 2;
    velocidad = 5;
  }
  
  /**
   * @param c_vertical Coordenada vertical
   */
  Punto(float c_vertical){
    this();  
    setY(c_vertical);
  }
  
  
  /**
   * @param c_horizontal Coordenada horizontal
   * @param c_vertical Coordenada vertical
   */
  Punto(float c_horizontal, float c_vertical){
    this();
    setX(c_horizontal);
    setY(c_vertical);
  }
  
  /**
   * Desplaza el punto hacia la izquierda
   */
  void desplazar(){
    setX(x - velocidad);
  }
  
  /**
   * Dibuja el punto
   */
  void dibujar(){
    ellipseMode(CENTER);
    ellipse(x, y, 2, 2);
  }
  
  /**
   * Establece el valor de la coordenada horizontal del punto
   * @param nuevoX La nueva coordenada horizontal
   */
   void setX(float nuevoX){
     x = nuevoX;
   }
   
  /**
   * Establece el valor de la coordenada vertical del punto
   * @param nuevoY La nueva coordenada vertical
   */
   void setY(float nuevoY){
     y = nuevoY;
   }
   
  /**
   * Establece la velocidad de movimiento hacia la izquierda del punto
   * @param velocidad La nueva velocidad
   */
   void setVelocidad(int v){
     velocidad = v;
   }
  
  
  /**
   * Devuelve el valor de la coordenada horizontal del punto
   * @return x La coordenada horizontal
   */
   float getX(){
     return x;
   }
   
  /**
   * Devuelve el valor de la coordenada vertical del punto
   * @return y La coordenada vertical
   */
   float getY(){
     return y;
   }
   
  /**
   * Devuelve la velocidad de movimiento hacia la izquierda del punto
   * @return velocidad La velocidad
   */
   int getVelocidad(){
     return velocidad;
   }
}

Hay algún método que no utilizo, como por ejemplo "dibujar()", que dibujaría un punto en la posición del punto (valga la redundancia). Si posteriormente hacéis alguna modificación en el archivo principal para experimentar, puede seros de ayuda tener esos métodos creados.

A continuación, podemos ver el código que he utilizado para el archivo principal:

import processing.serial.*;   // Para usar el puerto serie

ArrayList<Punto> onda1;       // Conjunto de puntos para representar la onda1
ArrayList<Punto> onda2;       // Conjunto de puntos para representar la onda2
int valores[] = {0, 0};       // Array para obtener los dos valores del puerto serie
float altura[] = {0.0, 0.0};  // Array para las alturas recibidas

Serial puerto;                // Puerto serie

void setup(){
   /* Configuración de ventana */
  size(800, 600);             // Tamaño de ventana 
  frameRate(30);              // FPS
  smooth();                   // Suavizado activado  
  
  /* Inicialización de variables */
  onda1 = new ArrayList<Punto>();
  onda2 = new ArrayList<Punto>();
  
  /* Configuración de puerto serie */
  String nombrePuerto = Serial.list()[0];
  println("Puerto establecido a " + nombrePuerto + ".");
  puerto = new Serial(this, nombrePuerto, 9600);
  puerto.bufferUntil('\n');   // guardo datos hasta que encuentro salto de línea
}

void draw(){
  background(0);              // Pintamos color de fondo
  
  if(valores != null){
    altura[0] = map((float) valores[0], 0, 255, 0, height);
    altura[1] = map((float) valores[1], 0, 255, 0, height);
    
    onda1.add(new Punto(altura[0]));
    onda2.add(new Punto(altura[1]));
    
    fill(#FF0000);           // relleno color rojo (para el texto) 
    text("Valor 1: " + altura[0], 20, 30);
    fill(#FFFF00);           // relleno color amarillo (para el texto) 
    text("Valor 2: " + altura[1], 20, 50);
    
    noFill();                // sin relleno
    strokeWeight(2);         // grosor del lápiz
    stroke(#FF0000);         // color del lápiz
    dibujaCurva(onda1);
    stroke(#FFFF00);         // color del lápiz
    dibujaCurva(onda2);
  }
}

void dibujaCurva(ArrayList<Punto> onda){
  beginShape();                               // empieza curva
  for(int i = 0; i < onda.size(); i++){
    Punto punto = onda.get(i);
    punto.desplazar();       
    curveVertex(punto.getX(), punto.getY());  // añado un punto a la curva
    
    // punto.dibujar();                       // dibujo el punto
    
    /* Borrar punto si se ha desplazado demasiado a la izquierda */
    if(punto.getX() < -width){
      onda.remove(i);
    }
  }
  if(onda.size() > 0){
    curveVertex(onda.get(onda.size() - 1).getX() + 1, onda.get(onda.size() - 1).getY());
    line(onda.get(onda.size() - 1).getX(), onda.get(onda.size() - 1).getY(), width, onda.get(onda.size() - 1).getY());     
  }
  /* Dibujar curva */
  endShape();                                   // termina curva 
}

void serialEvent(Serial p){
  String dato = p.readStringUntil('\n'); // leemos el buffer del puerto serie
  
  if(dato != null){
    dato = trim(dato); 
    valores = int(split(dato, ',')); 
  }
}

La gran diferencia respecto a cómo recogíamos datos del puerto serie en la primera y segunda entradas, es que ahora hacemos uso de serialEvent. En vez de escuchar permanentemente el puerto en la sección draw(), ahora guardamos lo recibido en el puerto serie ya en la sección setup() usando bufferUntil y luego en la nueva sección de serialEvent es cuando recogemos el dato propiamente dicho.

Como valores es un array, utilizamos la función split para separar los valores contenidos en dato y que están separados por el símbolo coma ",", tal como vemos al final del código:

    valores = int(split(dato, ',')); 

Para dibujar la curva, enviamos el conjunto de puntos al método dibujaCurva y hacemos uso de curveVertex.

Para dibujar una curva dando los puntos por los que pasa, primero hacemos una llamada a beginShape() para indicar que empezamos a dibujar. Lo siguiente es ir añadiendo puntos con curveVertex() y, para terminar, usaremos endShape(), que es cuando se dibuja la curva.

Aquí vemos un ejemplo de cómo podríamos dibujar una curva:
void setup(){
  size(240, 120);  // tamaño de ventana
}
void draw(){
  background(0);   // fondo negro
  strokeWeight(2); // grosor de lápiz
  stroke(#00FF00); // lápiz verde
  noFill();        // sin relleno
  smooth();        // suavizado
  
  beginShape();         // empieza curva  
  curveVertex(0, 20);   // añado un punto a la curva
  curveVertex(20, 20);  // añado un punto a la curva
  curveVertex(40, 60);  // añado un punto a la curva
  curveVertex(60, 20);  // añado un punto a la curva
  curveVertex(80, 60);  // añado un punto a la curva
  curveVertex(100, 20); // añado un punto a la curva
  curveVertex(120, 20); // añado un punto a la curva
  endShape();           // termino curva
}
  
Si lo ejecutamos, el resultado será el siguiente:


Como vemos, no se ha dibujado ni el primer punto ni el último, de ahí el último if que utilizo en el método dibujaCurva, para añadir un punto más y que se dibuje correctamente.

A continuación, podemos ver un vídeo con el programa en funcionamiento:


Espero que os haya gustado.

Un saludo: Roi

12 de febrero de 2016

Arduino y Processing 2: Lluvia controlada por puerto serie

En una entrada anterior habíamos visto cómo comunicarnos de una forma muy básica desde nuestra Arduino con Processing a través del puerto serie. Por si deseáis revisarla, podéis encontrarla en el siguiente enlace: Arduino y Processing 1: Comunicación por puerto serie.

Esta vez, vamos a ver cómo "dibujar" lluvia en Processing y controlar la dirección en la que cae con un potenciómetro en Arduino.

Para hacernos una idea de cómo debe funcionar, veamos el siguiente vídeo:


Aunque la calidad de imagen de la animación de Processing no ha sido la mejor, nos sirve perfectamente para entender qué deseamos hacer.

Lo primero, será preparar nuestra Arduino. Necesitamos un potenciómetro, una LED y una resistencia de 330 Ohm (o la que creáis conveniente) para la LED. El montaje que he realizado es el siguiente:

Imagen realizada con Fritzing
En realidad, la LED sólo la utilizo para ver que los datos del potenciómetro se ven correctamente, ya que la intensidad de la LED variará según el valor obtenido. Por supuesto, toda la parte relativa a la LED podría eliminarse del código, lo dejo a vuestra elección.

A continuación, veamos el código que he utilizado en la Arduino:
#define PIN_POT A0       // pin de potenciómetro (analógico) 
#define PIN_LED 9        // pin de la LED (analógico)

int valor_POT = 0;       // para guardar el valor del potenciómetro
int brillo = 0;          // brillo de la LED


void setup() {
  pinMode(PIN_POT, INPUT);  // configuro pin del potenciómetro como Entrada
  pinMode(PIN_LED, OUTPUT); // configuro pin de la LED como Salida
  Serial.begin(9600);       // inicializo puerto serie
}

void loop() {
  valor_POT = analogRead(PIN_POT);             // obtengo el valor del potenciómetro (0 a 1023)
  brillo = map(valor_POT, 0, 1023, 0, 255);    // calculo el valor del brillo de la LED
  analogWrite(PIN_LED, brillo);                // cambio el brillo de la LED
  Serial.println(valor_POT);                   // envío el valor por el puerto serie
  delay(100);                                  // pequeña pausa para no saturar el puerto
}

Si cargamos el programa a nuestra Arduino, podremos ver como el brillo de la LED aumenta y disminuye según la posición en la que pongamos el potenciómetro.

Ahora que ya tenemos preparada la Arduino, vamos con Processing.

Necesitaremos dos archivos. Uno será el que gestione la animación y la comunicación por el puerto serie y, el otro, lo usaremos para crear la clase Gota, que gestionará el movimiento de una gota y también la dibujará.


Empezamos primero por la clase Gota. Este es el código que he utilizado:

class Gota {
  float x;        // Coordenada horizontal
  float y;        // Coordenada vertical
  float longitud; // Longitud de la gota
  float theta;    // Ángulo de la gota (que variará según lo obtenido por el puerto serie)
  int velocidad;  // Píxels que aumento en cada movimiento
  
  Gota(){
    x = random(width);   // Valor horizontal aleatorio, para que salga de cualquier sitio
    y = 0;               // Las gotas caen de la parte superior
    longitud = 10;       // El largo de la gota
    theta = radians(60); // Ángulo en radianes
    velocidad = 16;      // Para controlar la velocidad a la que cae la gota
  }
  
  /**
   * @param l Longitud de la gota
   * @param a Ángulo de la gota en grados
   */
  Gota(float l, float a){
    this();              // Llamo al constructor sin parámetros, para no repetir...
    longitud = l;        // Longitud que he recibido como parámetro
    theta = radians(a);  // Ángulo que he recibido como parámetro, en radianes
  }
  
  /**
   * Desplaza la gota hacia abajo y la dibuja
   */
  void caer(){
    pushMatrix();        // guardo posición actual del "lienzo"
    x = x % width;       // si la gota llega al borde, aparece por el otro
    y = y % height;      // si la gota llega al fondo, aparece por arriba
    if(y == 0)           // si la gota está arriba de todo...
       setX(random(width)); // ...obtengo una posición horizontal aleatoria
    if(x <= 0)           // si la gota se ha ido por el borde izquierdo...
      setX(width);       // ...la coloco a la derecha del todo
    translate(x, y);     // colocamos el lienzo en la posición deseada
    rotate(-theta);      // giramos lienzo los grados que queremos
    line(0, 0, 0, longitud); // dibujamos en el lienzo una línea con el largo deseado
    x += sin(theta) * velocidad; // desplazamos la gota proporcionalmente al ángulo
    y += cos(theta) * velocidad; // desplazamos la gota proporcionalmente al ángulo
    popMatrix();         // vuelvo al estado inicial del lienzo    
  }
  
  /**
   * Establece el valor de la coordenada horizontal de la gota
   * @param nuevoX La nueva coordenada horizontal
   */
   void setX(float nuevoX){
     x = nuevoX;
   }
   
  /**
   * Establece ángulo de la gota en radianes
   * @param newAngle El nuevo ángulo en grados
   */
   void setAngle(float newAngle){
     theta = radians(newAngle);
   }
}

Ahora que ya tenemos nuestra clase Gota creada, vamos con el programa principal. La base de comunicación, la habíamos visto ya en una entrada anterior. Simplemente hemos añadido lo necesario para gestionar el dato recibido: Aquí está el código necesario:

import processing.serial.*;   // Para usar el puerto serie

ArrayList<Gota> lluvia;       // Para el conjunto de gotas
static int num_gotas = 1500;  // Para limitar el número máximo de gotas
float theta = 45;             // Ángulo
float longitud = 15;          // Largo de la gota 
Serial puerto;                // Puerto serie
String dato, dato_AUX;        // Dato recibido por el puerto serie

void setup(){
   /* Configuración de ventana */
  size(800, 600);             // Tamaño de ventana 
  background(0);              // Color de fondo
  frameRate(60);              // Fotogramas por segundo 
  
  /* Configuración de pintura */
  stroke(#A0DBFF);            // Cambiamos el color del lápiz a un tono azul 
  
  /* Inicialización de variables */
  lluvia = new ArrayList<Gota>();
  dato = "1";              
  dato_AUX = "1"; 
  
  /* Configuración de puerto serie */
  String nombrePuerto = Serial.list()[0];
  println("Puerto establecido a " + nombrePuerto + "."); // Mostrar el puerto elegido
  puerto = new Serial(this, nombrePuerto, 9600);
}

void draw(){
  background(0);              // Pintamos color de fondo
  
  if(puerto.available() > 0){            // si el puerto está disponible...
    dato = puerto.readStringUntil('\n'); //...leo hasta encontrar un salto de línea
  }
  if(dato == null){                      // Si he recibido un dato nulo...
    dato = dato_AUX;                     // ...utilizo el anterior
  } else {                               // Si el dato NO es nulo...
    if(trim(dato).equals(dato_AUX) == false){ // ...y es distinto del anterior...
      println("Ángulo: " + map((float) int(dato_AUX), 0, 1023, -90, 90));
      dato_AUX = trim(dato);             // Guardo el dato borrando los espacios en blanco
    }    
  }
  
  /* Ángulo */
  theta = map((float) int(dato_AUX), 0, 1023, -90, 90); // obtengo el ángulo (de -90º a 90º)
  
  if(lluvia.size() < num_gotas && random(10) < 1) // Si hay sitio para más gotas...
    lluvia.add(new Gota(longitud, theta));        // ...añado una nueva
  
  for(Gota gota : lluvia){ // Reviso todas las gotas del conjunto
    gota.setAngle(theta);  // Establezco el ángulo en que deben orientarse
    gota.caer();           // Las desplazo y dibujo
  }
}


Además de comprobar que no excedamos el número de gotas, también he añadido una condición que hará que no se creen todas al mismo tiempo, si no que caigan aleatoriamente. Es decir, si hay sitio para más gotas, obtengo un número aleatorio entre 0 y 9 y, si ha salido cero, entonces sí creo la gota... y si no, pues no la creo. Por eso el último "if" utiliza esa segunda condición. Si no fuera así, caerían las gotas todas al mismo tiempo y el efecto sería completamente diferente:

  if(lluvia.size() < num_gotas && random(10) < 1)
    lluvia.add(new Gota(longitud, theta));

A continuación, podéis ver una imagen del resultado final:



Os recomiendo variar varios parámetros del código para ver cómo afecta la velocidad, longitud de la gota, número de gotas... incluso los fotogramas por segundo.

En la clase Gota, en el método caer, podéis cambiar line() por ellipse(), por ejemplo, y ver cómo caen pequeños círculos en vez de líneas (aunque así no apreciaréis el ángulo). Lo divertido está en experimentar.

Espero que os haya gustado.

Un saludo: Roi.

5 de febrero de 2016

Iniciar Telegram Desktop en la bandeja de sistema en openSuse 13.2

Seguramente conocéis el programa de mensajería Telegram. Para Linux, tenemos el cliente nativo Telegram Desktop y que es muy sencillo de instalar. Tan solo tendremos que descargarlo, descomprimirlo y, al ejecutar el archivo Telegram, ya se instalará y se creará un enlace en nuestro menú para poder ejecutarlo.


Como seguramente habéis notado, cuando dejamos una aplicación abierta, al reiniciar el equipo, ésta se ejecuta automáticamente al arrancar. Esto es especialmente útil, por ejemplo, para un programa de mensajería, ya que así no tendremos que abrirlo cada vez que encendemos el equipo para poder estar "online". 

En mi caso, y tal como se puede suponer por el título, lo he instalado en openSuse 13.2 64bit con KDE.

El problema con el que nos encontramos con Telegram Desktop es que, si dejamos el programa abierto (lo más habitual), se iniciará pero en modo ventana, tal como se ve en la siguiente imagen:


Si, por otro lado, lo cerramos durante nuestra sesión, en el siguiente arranque no se cargará automáticamente, lo cual también es un problema.

Para solucionarlo, vamos a utilizar las opciones de arranque de KDE.

Lo primero que necesitamos, es ir a Preferencias del sistema, que encontraremos en Aplicaciones > Sistema:


Una vez abiertas las Preferencias del sistema, debemos pulsar en Arranque y apagado en la sección de Administración del sistema:


Se abrirá una nueva ventana. En ella, debemos pulsar en el botón Añadir programa:


Veremos ahora un listado con las aplicaciones que tenemos en nuestro menú. Tendremos que seleccionar Telegram Desktop (no tiene por coincidir con donde lo tengo yo) y pulsar el botón Aceptar:


Ahora, se nos mostrarán las propiedades del acceso. Debemos ir a la pestaña Aplicación:


En Orden, debemos modificar el final de forma que, tras la palabra Telegram, aparezca -startintray %u, para forzar que arranque en la bandeja del sistema. Por ejemplo, podría quedarnos una línea similar a esta:

/home/tuUsuario/rutaDondeHasInstaladoTelegram/Telegram -startintray %u

Tras realizar el cambio, pulsaremos Aceptar. Veamos una imagen de cómo ha quedado en mi caso:


Una vez aceptado el cambio, veremos una línea más en la sección de Autoarranque:


Con esto, hemos conseguido que, si cerramos Telegram antes de finalizar la sesión, vuelva a cargarse automáticamente al encender el equipo y, además, que lo haga en la bandeja del sistema.

Si reiniciamos ahora el equipo sin haber cerrado previamente Telegram, seguiríamos teniendo el problema de que arranca en modo ventana, ya que se restaura la aplicación por haberla dejado abierta.

Para que eso no ocurra, en la misma ventana en la que estábamos, tenemos que ir a la sección Gestión de sesiones y, en la lista de Aplicaciones a excluir de las sesiones, añadiremos "Telegram" (es importante que la T sea mayúscula) tal como vemos en la siguiente imagen:


Tras haber aplicado este último cambio, nuestra sesión no recordará el estado de la aplicación Telegram, con lo que siempre que arranquemos hará caso de lo que hemos añadido en la sección Autoarranque.

A partir de ahora, Telegram ya se iniciará con nuestro sistema y en la bandeja de sistema, tal como vemos en la siguiente imagen:


Espero que os haya sido de ayuda.

Un saludo.



4 de febrero de 2016

Arduino y Processing 1: Comunicación básica por puerto serie

Hace tiempo que había publicado una entrada de cómo comunicarnos con nuestra Arduino desde Python. Esta vez vamos a ver cómo puedo comunicarme desde Arduino con un programa realizado en Processing.

En esta explicación he utilizado el IDE Arduino 1.6.0 con una Arduino UNO, el IDE de Processing 3.0.1 y tengo todo instalado en openSuse 13.2 64bit.

Para ver cómo comunicar nuestra Arduino con Processing, empezaremos por algo muy básico. Vamos primero con la Arduino. Este es el código que he utilizado:

void setup() {
  Serial.begin(9600);

}

void loop() {
  Serial.println("Hola!");
  delay(100);
}

Como veis, es muy simple. En la sección setup, utilizo Serial.begin(9600) para inicializar el puerto serie y, en la sección loop, imprimo por el puerto serie la palabra "Hola!", seguida de una espera de 100 milisegundos para no saturar el puerto serie.

Con esto, ya tenemos nuestra Arduino enviando una y otra vez la palabra "Hola!" a través del puerto serie.

Vamos ahora con la parte de Processing.

Lo primero que necesitamos saber es en qué puerto tenemos conectada la Arduino. Para ello, primero ejecutamos el siguiente código en Processing:

import processing.serial.*; // librería necesaria para comunicación serie

void setup(){
  println(Serial.list());
}
Con esto, podremos ver en el terminal de Processing la lista de puertos de una forma similar a esta:

 
Vamos al IDE de Arduino y, en el menú Herramientas, podemos ver el puerto en la que tenemos conectada nuestra placa:


En mi caso, está en /devtty/ACM0. Si comprobamos la lista que se nos ha mostrado en Processing, el primer elemento corresponde a mi puerto. Como en el listado se numeran como 0, 1, 2... nos quedamos con que mi puerto es el número 0 de la lista.
Volvemos a Processing, borramos la línea que imprime la lista y ampliamos el código, quedando así:

import processing.serial.*;

Serial puerto; // creamos un objeto de la clase Serial
String dato;   // para los datos recibidos por el puerto serie

void setup(){
  String nombrePuerto = Serial.list()[0];
  println("Puerto establecido a " + nombrePuerto + ".");
  puerto = new Serial(this, nombrePuerto, 9600);
}

void draw(){
  if(puerto.available() > 0){
    dato = puerto.readStringUntil('\n');
  }
  println("Dato recibido: " + dato);
}
Hemos añadido dos variables, una para gestionar el puerto y otra para guardar el dato recibido.

Antes hemos averiguado qué puerto es el nuestro, ahora guardamos su nombre obteniéndolo con Serial.list()[0], donde el número 0 es el número de puerto en la lista.

El println que he utilizado, podéis omitirlo. Simplemente es para ver que el nombre elegido es el correcto.

En la sección setup, la última línea es para inicializar el puerto. Como podemos observar, le pasamos el nombre del puerto y la velocidad, que es la misma que habíamos indicado en nuestra Arduino también.

No vamos a dibujar nada en la sección draw. De momento, solamente mostramos datos en el terminal de Processing.

Con la primera línea, comprobamos si el puerto está disponible. Si sí lo está, guardamos el dato en la variable con puerto.readStringUntil('\n'), que lee todos los datos hasta que encuentra un salto de línea.

Una vez hecho esto, mostramos el dato.

A continuación, vemos una imagen de cómo ha quedado la ejecución:


Como vemos, se está recibiendo la palabra "Hola!" una y otra vez. También notaréis que, a veces nos aparece algún "null". Eso es normal, simplemente habría que tenerlo en cuenta en nuestra programación para obviarlo.

Para continuar viendo cómo comunicarnos por el puerto serie con nuestra Arduino y processing, podéis echarle un ojo a la siguiente entrega: Arduino y Processing 2: Lluvia controlada por puerto serie.

Espero que os haya sido de ayuda para poder empezar con vuestros proyectos de Arduino con Processing.

Un saludo.

11 de enero de 2016

Mad Catz R.A.T. 5 en openSuse 13.2

Recientemente he adquirido un ratón Mad Catz R.A.T. 5. Tal como había leído antes de comprarlo, ha sido enchufarlo y ver que no funcionaba como debiera en Linux y, más concretamente, en openSuse 13.2. La rueda horizontal no funcionaba, los botones laterales de adelante y atrás tampoco y, lo peor... ¡se perdía el foco del ratón y no podía hacer clic!


Para poder hacer clic, tenía que hacer varios clics con el secundario y el principal hasta que en algún momento se reestablecía el foco pero claro, trabajar así es inviable.

Basándome en la configuración del R.A.T. 7 que encontré en el artículo "Fixing the Mad Catz R.A.T 7 mouse under openSUSE / Linux" del blog de Andre Ritcher, la configuración de ratones Mad Catz de la wiki de Archlinux y la configuración de un R.A.T. 5 en la comunidad de Linux Mint, he conseguido que funcionen tanto el foco, como los botones adelante y atrás y la rueda horizontal.

Vamos a ver cómo podemos hacerlo paso a paso.

Lo primero que necesitamos, es abrir el gestor de archivos en modo superusuario. Para ello, vamos al Lanzador de aplicaciones y, en la sección Administrador de archivos que encontramos dentro de Sistema, pulsamos en Gestor de Archivos - (Modo Superusuario):


Al hacerlo, se nos pedirá la contraseña de root. La pondremos y pulsaremos el botón Aceptar:


Una vez que Dolphin ya esté abierto, tendremos que ir a la siguiente carpeta (esta es la que corresponde a openSuse 13.2):
/etc/X11/xorg.conf.d/
Bastará con escribirlo en la barra de direcciones y pulsar Enter, como vemos a continuación:


Una vez que estamos en la carpeta correcta, debemos crear un archivo llamado "50-rat5.conf". Para ello, haremos clic con el botón derecho del ratón en cualquier zona vacía de la carpeta y, en el menú Crear archivo, elegiremos Archivo de texto... tal como se ve en la imagen:


Se nos pedirá el nombre y, tal como he comentado antes, tendremos que escribir "50-rat5.conf" y pulsar Aceptar:


Una vez creado, debemos hacer clic sobre el archivo para editarlo:


Aquí vemos una imagen del editor de texto con la configuración que he utilizado:


Como todos sabemos, es mucho más práctico copiar y pegar... así que aquí tenéis el texto:
Section "InputClass"
    Identifier "Mad Catz R.A.T. 5"
    MatchProduct "Mad Catz Mad Catz R.A.T.5 Mouse"
    MatchDevicePath "/dev/input/event*"
    Option "Buttons" "21"
    Option "ButtonMapping" "1 2 3 4 5 0 0 8 9 7 6 10 0 0 0 0 0 0 0 0"
    Option "ZAxisMapping" "4 5 11 10"
    Option "AutoReleaseButtons" "13 14 15"
EndSection 
El 8 y el 9 son los botones para avanzar y retroceder página en el navegador... la primera vez había probado con 9 y 8 en vez de 8 y 9 y me habían quedado con la función al revés... pero para gustos.

Una vez guardado el archivo de texto, es necesario finalizar la sesión y volver a acceder y, con esto, ya funcionará correctamente vuestro Mad Catz R.A.T. 5.

Espero que os haya sido de ayuda.

Un saludo: Roi

---

P.D.: Este mismo método también funciona en openSuse Leap 42.1 
En openSuse Leap 42.2 ya no es necesario utilizarlo, me funciona correctamente.

3 de noviembre de 2015

Forzar uso de HTML5 en la reproducción de Youtube en Firefox

Hace ya tiempo que los navegadores más conocidos bloquean por defecto el plugin de Flash. Estos navegadores, son compatibles con HTML5 y resulta bastante molesto tener que permitir la ejecución de Flash cada vez que queremos reproducir un vídeo de Youtube (ya sé que podría elegir "permitir siempre", pero hay que ir olvidándose de Flash).

Aunque siempre se me reproducían los vídeos de Youtube sin hacer nada en Firefox, por algún motivo han vuelto a ejecutarse con Flash, probablemente por alguna actualización del navegador.

Si ese es vuestro caso, al acceder a algún vídeo, se os pedirá activar el plugin de Flash:


Para indicarle a Youtube que lo que queremos es que reproduzca el vídeo utlizando HTML5 en vez de Flash, debemos acceder a la página https://www.youtube.com/html5. En ella, veremos el botón "Solicitar el reproductor HTML5". Simplemente, debemos pulsarlo:


Una vez pulsado, ya podemos volver a nuestro vídeo y reproducirlo sin problemas:


Si por el motivo que sea, preferimos volver a utilizar Flash, sólo tendremos que acceder de nuevo a la web https://www.youtube.com/html5 y pulsar sobre el botón "Utilizar el reproductor predeterminado":


Siempre que podamos evitarlo, es recomendable no utilizar el plugin de Flash

Un saludo: Roi.