Búsqueda

3/7/13

Evitar auto reset Arduino

Siempre se me olvida como hacer para evitar que Arduino haga un auto reset, cuando me conecto a él por el puerto de serie desde Linux. Así que, voy a escribirlo aquí, como nota mental y por si a alguien le sirve.

Para evitar el auto reset en  la placa Arduino Uno es necesario conectar un condensador de 10µF entre GND y Reset. Siempre con el lado negativo a GND (El que lleva una banda blanca y tiene la pata más corta). Os dejo una imagen con el esquema.

Si estamos usando la placa Arduino Mega necesitamos conectar una resistencia de 47Ω entre 3.3V y Reset. El esquema es el siguiente:

Otra posibilidad es conectar una resistencia de 120Ω entre 5.5V y Reset:
NOTA: Es muy importante poner exactamente las resistencias con esos valores puesto que un valor diferente puede hacer circular una intensidad que puede dañar el Arduino.


1/3/13

Primera versión de motor gráfico con WebGL

Bueno pues como dije en un post anterior estoy creando un motor gráfico para WebGL con la esperanza de realizar algún juego. Empecé explicando como se dibujaba un cubo sin texturas, pero la verdad es que me he enganchado al desarrollo y me falta tiempo para explicar todos los detalles para llegar al punto en el que me encuentro. Así que subiré el código a algún repositorio público para que podaís descargarlo. Pero antes quiero organizar un poco el código y poner comentarios para dejarlo todo lo más claro posible.

Componentes implementados:

- Control de colisiones
- Animaciones por keyframes cargados desde archivos .obj exportados desde Blender
- Control de la cámara
- Control de luces
- Control de entidades en la pantalla


De momento os dejo un vídeo con la primera versión del motor gráfico:




19/2/13

Dibujando un cubo sin texturas

Vamos a dibujar el siguiente cubo con WebGL explicando todos los detalles necesarios para entender como funciona OpenGL.

Podeis descargaros el proyecto completo desde aquí. El proyecto tiene la siguiente estructura:

Los archivos J3DI.js, J3DIMath.js y webgl-utils.js también los podéis encontrar en la wiki de WebGL. De estos archivos no es necesario cambiar nada, solo son librerias que usamos para configurar WebGL.

index.html


El archivo index.html sirve para crear el layout de la página.

En la cabecera importamos las librerías que vamos a usar:
<head>
  <script type="text/javascript" src="js/lib/jquery-1.8.3.js"></script>
  <script type="text/javascript" src="js/lib/J3DI.js"></script>
  <script type="text/javascript" src="js/lib/J3DIMath.js"></script>
  <script type="text/javascript" src="js/lib/webgl-utils.js"></script> 
A continuación incluimos los shaders. Los shaders son trozos de código que se ejecutan en la GPU de nuestra tarjeta gráfica, permitiendo una rápida transformación de los vertices de los objetos así como modificaciones en el color de los pixeles que forman el objeto. Este lenguaje de programación se llama GLSL.
  <script type="text/javascript" src="js/engine/shaders/default/vShader.js"></script>
  <script type="text/javascript" src="js/engine/shaders/default/fShader.js"></script>
Por último, incluimos los archivos render.js y scene.js.
  <script type="text/javascript" src="js/engine/render.js"></script>
  <script type="text/javascript" src="js/scene.js"></script>
</head>

En la etiqueta <body> definimos el canvas que va a usar WebGL para mostrarnos el cubo. Podemos personalizarlo como cualquier elemento HTML, en mi caso le he puesto un ancho de 800px y un alto de 500px.
<body onload="start()">
  <canvas id="example" style="width:800px;height:500px">
    Por favor, usa un navegador compatible (Firefox, Chrome, ...)
  </canvas>
</body>

 

scene.js

En este archivo lo único que definimos son los objetos que se van a mostrar en el canvas.
function initScene(){
  scene.elements = { "box": makeBox(gl)};
}

 

render.js

Este archivo será el verdadero motor gráfico. Es el que se encarga de inicializar OpenGL, posicionar la cámara, dibujar los objetos, ....

Función init

Inicializamos el contexto de OpenGL.
function init()
{
    var gl = initWebGL("example");
    if (!gl) {
      return;
A continuación definimos los shaders. El contenido del vertex shader, que es el que se encarga de realizar transformaciones en los vértices del modelo, lo leemos de la variable defaultVShader. Esta variable la hemos declarado al importar el archivo "js/engine/shaders/default/vShader.js" en el tag head de index.html.
  vshader = $("<script id='vshader' type='x-shader/x-vertex'></script>");
  vshader.append(defaultVShader);
  $("body").append(vshader);
El contenido del fragment shader, que es el que se encarga de dar color a los pixeles que ocupa el modelo en pantalla y de aplicar las texturas, lo leemos de la variable defaultFShader. Esta variable la hemos declarado al importar el archivo "js/engine/shaders/default/fShader.js" en el tag head de index.html.
  fshader = $("<script id='fshader' type='x-shader/x-fragment'></script>");
  fshader.append(defaultFShader);
  $("body").append(fshader);
Después declaramos un programa o configuración. Para declarar un programa necesitamos:
  1. Un contexto de OpenGL, 
  2. Vertex shader. Le pasamos el id del vertex shader definido previamente.
  3. Fragment shader. Le pasamos el id del fragmente shader definido previamente.
  4. Una lista de atributos que necesitan los shaders para ejecutarse, en nuestro caso "vNormal" y "vPosition"
  5. Un color de fondo
  6. Valor inicial de depth, también llamado z-buffer que se usa cuando dos objetos ocupan el mismo pixel en la pantalla, determinar cual de ellos se muestra.
Podemos definir varios programas en OpenGL. Como hemos visto en cada programa se usan dos shaders esto nos permite realizar diferentes transformaciones en los objetos de la escena. Por ejemplo, podemos definir un programa que dibuje los objetos en blanco y negro y otro que los dibuje en color. 
  program = simpleSetup(
    gl,
    "vshader", "fshader",
    [ "vNormal", "vPosition"],
    [ 0, 0, 0.5, 1 ], 10000);
Inicializamos las matrices necesarias para realizar las transformaciones en los vértices del modelo.
  render.mvMatrix = new J3DIMatrix4();
  render.normalMatrix = new J3DIMatrix4();
  render.mvpMatrix = new J3DIMatrix4();
Por último, devolvemos el contexto de OpenGL inicializado.
  return gl;
}

Función reshape

Esta función redimensiona toda la escena siempre que cambie el tamaño del canvas.
function reshape(gl){
  var canvas = document.getElementById('example');
  if (canvas.clientWidth == canvas.width && canvas.clientHeight == canvas.height)
    return;
  canvas.width = canvas.clientWidth;
  canvas.height = canvas.clientHeight;
Indica el tamaño del rectangulo donde se visualizará la escena. En este caso es el tamaño del canvas:
  gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight); 
Establecemos como queremos visualizar la escena, en este caso cada objeto debe ser proyectado en perspectiva a la pantalla. Como en el mundo real, los objetos lejanos parecen más pequeños que los objetos que están cerca de la camara. Existe otro tipo de proyección que es ortográfica en la que todos los objetos, se proyectan en la pantalla con su tamaño real, independientemente de la posición en la que se encuentren.
  render.perspectiveMatrix = new J3DIMatrix4();
  render.perspectiveMatrix.perspective(30, canvas.clientWidth /  canvas.clientHeight, 
                                                                              1, 10000);
Por último, posicionamos la cámara en el punto (0,0,7) con:
  render.perspectiveMatrix.lookat(0, 0, 7, 0, 0, 0, 0, 1, 0);
}

Función drawPicture

Esta función es la que se encarga de mostrar todos los objetos de la escena en pantalla. Comienza llamando a la función explicada en el apartado anterior y posteriormente limpia el canvas con el color de fondo.
function drawPicture(gl)
{
  reshape(gl);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Crea la matriz de transformación para pasar las coordenadas del modelo a coordenadas del mundo. En este caso rotamos el modelo 20º sobre el eje X y otros 20º sobre el eje Y
  render.mvMatrix.makeIdentity();
  render.mvMatrix.rotate(20, 1,0,0);
  render.mvMatrix.rotate(20, 0,1,0);
Copia la matriz anterior para realizar la misma operación con las normales de los vertices del objeto.
  render.normalMatrix.load(render.mvMatrix);
Creamos la matriz que transforma las coordenadas de los vertices del modelo a sus correspondientes en la pantalla, multiplicando (render.mvMatrix) x (render.perspectiveMatrix).
  render.mvpMatrix.load(render.perspectiveMatrix);
  render.mvpMatrix.multiply(render.mvMatrix);
Pulsa aquí para entender mejor todas estas transformaciones.

Indicamos con que programa queremos mostrar los objetos en la escena. Usaremos el programa definido en el metodo init().
  gl.useProgram(program);
Situamos la luz en el punto (0,0,1) 
  gl.uniform3f(gl.getUniformLocation(program, "lightDir"), 0, 0, 1);
Pasamos la matriz para transformar las normales al programa. Para calcular las normales no necesitamos saber donde esta la cámara ni tampoco el tipo de proyección por eso se usa una matriz que solo transforma las coordenadas desde el modelo al mundo. Una vez realizada esta transformación podremos saber como se debe iluminar el objeto.
  render.normalMatrix.setUniform(gl, 
                        gl.getUniformLocation(program, "u_normalMatrix"), false);
Pasamos la matriz de transformación desde el modelo a la pantalla.
  render.mvpMatrix.setUniform(gl, 
                        gl.getUniformLocation(program, "u_modelViewProjMatrix"), false);
Indica a OpenGL que queremos utilizar los atributos 0 y 1, en nuestro caso estos atributos son vNormal y vVertex.
  gl.enableVertexAttribArray(0);
  gl.enableVertexAttribArray(1);
Mostramos todos los elementos de la escena.
for(index in scene.elements){
  element = scene.elements[index];
Asignamos los vertices del objeto al buffer y lo usamos para establecer el attributo vVertex del shader, en nuestro caso es el número 1, además le decimos que coja los float de 3 en 3.
  gl.bindBuffer(gl.ARRAY_BUFFER, element.vertexObject);
  gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);
Hacemos lo mismo con las normales, como veis en esta caso el primer argumento es un 0 ya que ese es el indice de vNormal en nuestro shader.
  gl.bindBuffer(gl.ARRAY_BUFFER, element.normalObject);
  gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
Por último, le indicamos los indices necesarios para formar los triangulos del objeto         
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, element.indexObject);     
  gl.drawElements(gl.TRIANGLES, element.numIndices, gl.UNSIGNED_BYTE, 0);
}

18/2/13

Sistemas de coordenadas 3D

Generalmente cuando trabajamos con objetos en 3D podemos distinguir cuatro tipos de sistemas de coordenadas:
  • Model: Son las coordenadas en las que se modela el objeto. Por ejemplo, cuando modelamos un objeto siempre lo hacemos cerca del origen (Punto (0,0,0)).
  • World: Son las coordenadas del objeto en el mundo. Como mundo podemos entender el sistema de coordenadas de OpenGL. Donde se encuentran todos los demás objetos de la escena.
  • View: Son las coordenadas de como se ve el objeto desde una cámara situada en cierto punto.
  • ViewPort: Son las coordenadas en 2D del objeto, es decir, se proyecta su forma sobre la pantalla.
Por lo tanto, para mostrar un objeto necesitamos transformar sus coordenadas desde Model hasta ViewPort. Para ello aplicamos una transformación que realice un cambio de sistema de coordenadas desde Model a World con una matriz A:
Model x A = World (Segunda imagen)
Después, aplicamos a esas coordenadas otra transformación con una matriz B, para pasar al sistema de coordenadas de una cámara virtual que enfoca a nuestro objeto:
World x B = View (Tercera imagen)
Por último, realizamos una transformación lineal con una matriz C, desde el sistema de coordenadas View a ViewPort. Esto no es más que una proyección de nuestro objeto sobre un plano 2D, que en nuestro caso es la pantalla.
View x C = ViewPort (Cuarta imagen)
Así podremos calcular de forma sencilla las coordenadas que ocupa sobre la pantalla nuestro objeto. Pero realizar tres transformaciones por cada punto del modelo es ineficiente y como las transformaciones matriciales se pueden concatenar podemos calcular las coordenadas con una sola transformación.

Como Model x A = World y World x B = View entonces si sustituimos World:
Model x A x B = View
Y como View x C = ViewPort si sustituimos View:
Model x A x B x C = ViewPort
Si calculamos la matriz T = A x B x C obtendremos la matriz que realiza la transformación desde Model a ViewPort.
Model x T = ViewPort

16/2/13

Primeros pasos con WebGL

Hace tiempo empecé a desarrollar un juego para Android en 3D. Primero empecé con OpenGL 1.0, después migré el código a OpenGL 2.0 ES y ahora quiero migrar el código a WebGL porque veo mucho potencial, el juego podría usarse en cualquier sistema y en la mayoría de navegadores.

Para los que no lo sepan, WebGL es una implementación de OpenGL que se ejecuta en los navegadores web (Firefox, Chrome, ...). Aquí tenéis información detallada
http://www.khronos.org/webgl/wiki/Main_Page

Así es como llevo mi motor 3D para Android con OpenGL 2.0 ES



El motor gráfico lo he creado desde cero, más que nada porque no he visto ninguno gratuito que me llamara la atención y además me gusta saber como funcionan las cosas a bajo nivel.

Iré publicando paso a paso todo lo necesario para implementar este motor gráfico en WebGL. Aunque solo sirva como nota mental. Mi intención es aprender y compartir la información con cualquiera que le interese.

Por último quiero dejar claro que no me dedico a esto, es solo un pasatiempo.

20/1/13

Instalar LAMP en Lubuntu

Nuestra intención es configurar un mini pc con android MK802 para que nos sirva de servidor de desarrollo. Por lo que vamos a instalar el servidor web Apache, PHP y MySQL como base de datos.

Instalando Apache:


Para instalar apache abrimos un terminal y escribimos:
sudo apt-get install apache2
A continuación aparecera un mensaje preguntandonos si queremos instalarlo. Pulsamos "Y" y presionamos enter. Si no aparece nada es posible que no tengamos definidos los repositorios de ubuntu correctamente.

Podemos comprobar que se ha instalado correctamente escribiendo en cualquier navegador.
http://localhost/ 

Instalando MySQL


Escribimos en un terminal.
$sudo apt-get install mysql-server
Cuando se haya instalado nos preguntará por un usuario y contraseña para la base de datos.

Para comprobar que se ha instalado correctamente, escribimos en un terminal:
$ sudo mysql -p
Nos aparecerá lo siguiente:
miniand@miniand:~$ sudo mysql -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 37
Server version: 5.5.22-0ubuntu1 (Ubuntu)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

Instalando PHP:


Para instalar PHP escribimos en un terminal:
$sudo apt-get install php5 libapache2-mod-php5
Una vez instalado reinciamos el servidor:
$sudo /etc/init.d/apache2 restart
Para comprobar que se ha instalado correctamente, creamos en el directorio /var/www un archivo llamado index.php con el siguiente contenido:
<?php phpinfo(); ?>
Es importante que dicho archivo tenga configurados los permisos para que el usuario www-data pueda leerlo. El usuario www-data representa al servidor Apache. Si no tiene permisos de lectura no podrá ejecutar el archivo.

Una vez configurados los permisos podemos acceder a la siguiente url para comprobar que PHP esta funcionando.
http://localhost/index.php
Para terminar es necesario configurar PHP para que trabaje con MySQL. Para ello es necesario editar el archivo:
/etc/php5/apache2/php.ini
Buscamos la línea:
;extension=mysql.so
Y eliminamos el ";" para descomentarla. Si por casualidad no existe dicha línea la debemos crear nosotros.

También es necesario verificar que tenemos el modulo mysql.so. Para ello es necesario examinar el directorio donde están las extensiones de PHP, en mi caso:
/usr/lib/php5/20090626+lfs
Si no se encuentra el archivo mysql.so en ese directorio, escribimos en el terminal:
$sudo apt-get install php5-mysql
Para terminar reiniciamos el servidor.
$sudo /etc/init.d/apache2 restart

Prueba de PHP + MySQL


Creamos un archivo llamado testMysql.php en el directorio /var/www es importante que tenga los permisos de lectura correctos para que pueda ejecutarlo el usuario www-data.

Ponemos en el archivo:
<?
 $my_connection=mysql_connect("","root","tupassword") or die ("could not connect to server".mysql_error());

 $dummy=mysql_select_db("mysql",$my_connection) or die ("could not open database".mysql_error());
 echo "success";
 echo "<br/>";
 $strSQL="SELECT * FROM db WHERE user LIKE '%'; ";
 $result=mysql_query($strSQL);
 $numrows=mysql_numrows($result);
 echo $numrows;
?>
Por último, escribimos en el navegador:
http://localhost/testMysql.php 
Nos debería aparecer algo parecido a:
success
1

22/3/11

SOS Alarm

SOS Alarm permite enviar un mensaje de texto con tus coordenadas, al contacto que elijas, cuando el móvil detecta una fuerza determinada. Los intervalos de fuerza son 1G, 2G y 3G (sensibilidad alta, media o baja respectivamente).

Es útil para cuando tienes un accidente grave, el teléfono envía un mensaje al número de telefono indicado, con la aceleracion/deceleración que has sufrido y el lugar en el que te encuentras. Además este mensaje no se envia de forma instantánea, sino que espera 20 segundos para que puedas cancelarlo si te encuentras bien. Durante ese tiempo el teléfono vibra y reproduce una alarma. Para cancelar el envio del mensaje basta con encender la pantalla si esta apagada o pulsar el botón cancelar de la aplicación.




















https://market.android.com/details?id=es.android.accelerometer