Simulador de Quadrotor en Gazebo
Nuevo proyecto extraño que traigo a estas páginas. Dentro del Máster que ya os he comentado estoy realizando, y para una asignatura he realizado una implementación de un simulador de vuelo de un Quadrotor.
Para ello, he utilizado un simulador multirrobot ya existente, Gazebo, que forma parte del proyecto Player/Stage. A grandes rasgos, hay que implementar un Controlador que simule la física del quadrotor (para ello he utilizado el modelo desarrollado en la tesis doctoral de Samir Bouabdallah). Además, he desarrollado una pequeña interfaz en Qt, que utilizando libgazebo (librería de comunicación con Gazebo) permite interactuar con el quadrotor.
Al utilizar Gazebo, permite simulaciones multirrobot, adjuntar cámaras, mundos virtuales complejos...
Los fuentes, podéis descargarlos desde el proyecto que he abierto en Sourceforge.
Además, tenéis disponible la memoria del trabajo, con una explicación de "cómo" serían las líneas básicas de construcción de un simulador robótico (de un quadrotor) y las líneas generales de implementación del quadrotor en Gazebo.
Ahora en inglés.
I have developed a Quadrotor simulator using Gazebo. Gazebo is a 3D multirrobot simulator system, that is part of Player/Stage project. So, I have developed a Controller for Gazebo, that implements the dynamic model of Samir Bouabdallah to simulate the flight. I need to make several changes on the Gazebo core to get some information of the body of Quadrotor, to implement a new data structure to interact with or to set the absolute force applied to.
I have developed a Qt client application too. It is an example of how interact with Gazebo using libgazebo, and implements several loopback controllers that set the angular velocities of each rotor to control the flight.
You can download from Sourceforge.
In next post I will try to explain with more details.
Programando con Qt: Creando un widget sobre el que poder dibujar
Si algo distingue este blog, es el CAOS. Lo mismo hablo de AbanQ, que Qt, que Asterisk, que de la crisis, o me llevo dos meses sin escribir para de nuevo hacerlo sobre redes neuronales artificiales. Supongo que aquí plasmo un poco la realidad de mi día a día: Me enfrento a múltiples y diversas tecnologías para resolver múltiples y diversos problemas... pero la tecnología es sólo una pequeña parte de mi trabajo.
Y dentro de las líneas de caos, voy a dedicarme hoy a hablar un poquito de las Qt, mostrando un ejemplo; vamos a crear un widget muy sencillito: En él, y con el ratón pulsado, podremos dibujar, al más puro estilo Paint. La idea es utilizar este widget para capturar trazos de letras. Es decir, el usuario escribirá en él una letra. El widget esperará un tiempo prudencial, y avisará al código principal de que ya tiene la letra capturada. Este código está sacado de mi proyecto QtHandwriteRecog.
Ojo, la versión que pongo aquí NO ES LA IDEAL utilizando las posibilidades gráficas de Qt. Es una BURDA aproximación, pero que permite introducirse en algunos aspectos de las Qt sin llegar a un nivel de complejidad excesiva. Los que os estéis iniciando en las Qt lo entenderéis. Los expertos lo detestaréis. Pero a los primeros, os ayudará a ser los segundos, y detestarlo en un futuro. ;-)
Trabajando con Redes Neuronales y Qt
Si estaba poco liado, ahora algo más. Ando haciendo un Máster por la Universidad de Sevilla en Automática, Robótica y Telemática, y entre los múltiples requisitos, está el de realizar un trabajo por asignatura. Para el trabajo de la asignatura de Visión por Computador, escogí realizar una aplicación de reconocimiento de caracteres manuscritos utilizando redes neuronales.
Concremente, escogí como implementación de redes neuronales la Fast Artificial Neural Network, FANN, una excelente implementación realizada en C. Evidentemente, escogí como librería GUI para realizar el frontend, las Qt.
Los fuentes de la aplicación podéis descargarlos del proyecto que he abierto en Sourceforge, justo aquí.
La idea de funcionamiento de la aplicación es la siguiente:
- Se le indica a la aplicación los caracteres que se van a reconocer y el número de patrones de ejemplo que se le van a proporcionar. Eso generará un pequeño entrenamiento.
- Además se configuran algunos parámetros de la red neuronal (tipo de entrenamiento, tasa de aprendizaje, tasa de conexiones iniciales...). Los valores por defecto que vienen en la aplicación funcionan bastante bien.
- Se entrena la aplicación (y por extensión, las redes neuronales que dan soporte a la aplicación) con tu propia letra (la parte cutre es si no tenéis un lápiz óptico o algo así, que tendréis que hacerlo con vuestro ratón).
- A partir de aquí, la aplicación debe ser capaz de reconocer tu letra.
Podéis ver un ejemplo de funcionamiento en el vídeo que pongo a continuación. Puede descargarse aquí.
AbanQ: Integrando con JasperServer / JasperReports (II)
Bien, la idea es usar una librería C++ para interaccionar con webservices. Para ello, escogí el toolkit gSOAP. Librería en software libre que permite crear aplicaciones tanto clientes (consumidores) como servidores de webservices.
Nosotros vamos a hacer un uso muy parcial de la misma, ya que no vamos a instalar ningún servidor ni nada por el estilo, y sólo vamos a crear un consumidor. No me voy a meter en detalles con gSOAP (ya que se me escapa de los artículos) y sólo comentaré aquellos aspectos que nos interesan para integrar Webservices.
Lo primero, es obtener el WSDL de JasperServer. Para ello, y desde una instalación del mismo, se puede obtener sin más que abrir un navegador y solicitar http://servidor:puerto_tomcat/jasperserver/services/repository?wsdl
Bien. gSOAP proporciona dos ejecutables wsdl2h y soapcpp2 para generar los "proxys", esto es, código C++ que encapsula el acceso por webservices. Los ejecutamos tal que así: (INCLUDEGSOAP es una variable que apunta al directorio de includes de gsoap
AbanQ: Antes de seguir… cómo se compila
Bueno, antes de seguir con los artículos de cómo integrar JasperServer, u OpenKM, o introducir alguno de los cambios que propongo... creo que es mejor proporcionaros las herramientas para compilar estas versiones de AbanQ tanto en windows como en linux, para crear así los clientes con las opciones de debug, o quick.
He creado un .zip con mi versión actual de AbanQ, y digo "mi" versión, porque incluye los múltiples cambios que he ido publicando en este blog, y que enumero
- Formateado automático de los FLFieldDB que contienen números, de tal forma, que las cantidades tales como 100000 se representan como 100.000,00 Esto hace mucho más legible las cantidades. Aquí
- Desde QSA (el lenguaje de scripting) pueden accederse al manejo de los QComboBox (así, por ejemplo, he podido meter en algunos formularios objetos QComboBox y utilizarlos directamente sin necesidad de tener que estar asociados a columnas de bases de datos. Esto es especialmente útil para realizar filtrados de campos estáticos o no guardados en bases de datos).
- Los FLTableDB pueden presentar el resultado de Querys complejas, al agregarse una propiedad: qryVisualizacion. De esta forma, la riqueza visual de lo que pueden representar es mayor. La diferencia con la versión oficial de AbanQ, es que ese FLTableDB no es readonly, sino que se utiliza en la edición, creación y eliminación de registros. Aquí
- Cambios estéticos que afectan principalmente a la versión para Windows, ya que la original, no me gustaba (dejo el tema de windows por defecto, sin modificarlo). Aquí
- Los tamaños y posiciones de los formularios utilizados se almacenan, permitiendo una mejor experiencia del usuario. Aquí.
- Posibilidad de utilizar vistas cuando se utilice un motor PostgreSQL. Esto, entre otras cosas, permite una mejor integración de los datos de otros programas con AbanQ. Aquí
- Corrección de un bug por el que no se filtraban adecuadamente campos con valores int, uint o double. Aquí.
- Incorporación del estilo Windows XP (esto no lo incluye la versión original de AbanQ).
- El código de la integración con JasperServer que se verá en siguientes artículos.
Sólo tenéis que descomprimir el archivo .zip que os adjunto. Una vez hecho esto, si utilizáis Windows, debéis ajustar las variables señaladas en los archivos setenv.bat y build-config.bat. Si utilizáis Linux, debéis hacer lo mismo en el archivo setenv.h
Para compilar en Linux, necesitáis gcc, g++ y demás herramientas que seguro tendréis instaladas. Para compilar en Windows, necesitáis descargaros, MinGW. Además, es conveniente instalar el MinGW API for MS-Windows de aquí.
Compilación bajo Windows. Ubicados en el directorio donde habéis descomprimido las fuentes, ejecutar en este orden (por si no me explico bien haced un Inicio->Ejecutar-> cmd y cd al directorio en el que tengáis las fuentes ;-):
setenv.bat build-config.bat build-pthreads.bat build-qt.bat build-qsa.bat build-abanq.bat
Para los que estéis en Linux, es tan sencillo, como desde una consola, y en el directorio de las fuentes, ejecutar
setenv.sh compilar-qt.sh compilar-qsa.sh compilar-abanq.sh
Por defecto, la versión Windows viene preparada para compilar una versión final con un cliente quick, y la versión de Linux, para compilar una versión debug y con cliente "pesado" o completo.
Tened en cuenta que hay dependencias cruzadas, que no están muy bien resueltas: Por ejemplo, flbase depende de kugar, y kugar depende de flbase... así que al construir por primera vez, puede que os de error (la librería de flbase quiere enlazar a la de kugar, pero la de kugar no está construida porque faltan archivos objetos de flbase que no pueden construirse sin hacer previamente un moc de flbase...). Solución si os perdéis un poco en estos temas: entrad directamente en los directorios (src/flbase o src/kugar) y haced ahí el make.
Espero que con estas herramientas muchos os animéis a compilar y a introducir modificaciones, y corregir los muchos fallos que seguro he cometido. Cuanto más crezca la comunidad, mejor para todos.
Nota: Muchas de las modificaciones necesarias para compilar bajo Windows, las proporcionó juancrobles, a través del foro de AbanQ en Google, a través de diversos hilos y del fichero Modificaciones_abanq2.3-v1.1.zip disponible aqui.
AbanQ: Integrando con JasperServer / JasperReports (I)
No me gusta el editor de informes de AbanQ... ni me gusta Kugar, ni me gusta que Qt Designer como gestor de informes. El primero, porque creo que está muy por detrás de otros motores de generación de informes que existen en el mundo del software libre (aparte de que está abandonado como proyecto, para integrarlo en KOffice dentro de Kexi, y del segundo, porque no es un generador de informes.
Me gusta JasperReports: Es una herramienta muy completa, en software libre y que rivaliza con cualquier herramienta de generación de informes (he sido usuario/programador durante mucho tiempo de Crystal Reports y Oracle Reports y realmente, para mis necesidades y según mi experiencia, JasperReports está por encima).
Además, JasperReports, tiene una interfaz de usuario para la edición de informes, iReports. Si la probáis, veréis que es muy muy superior a Kugar o QtDesigner (utilizando esta como generación de informes) y por encima de Crystal Repors, por ejemplo.
Por si esto no fuera poco, dispone de JasperServer que es una aplicación, que actúa como servidor y/o repositorio de los diferentes documentos que generéis con las anteriores aplicaciones. En realidad, es mucho más, tratando de ser una herramienta de Bussiness Inteligence... permitiendo, junto con JasperAnalysis, ser una herramienta de análisis....
La idea de funcionamiento con estas herramientas es la siguiente:
Se instala JasperServer en vuestro servidor. (Yo lo tengo instalado en un Jboss con PostgreSQL). Os proporciona una aplicación web en la que podéis gestionar, administrar y utilizar los informes que vayáis definiendo. No sólo eso, permite programar informes, enviando los resultados a correo electrónico, generación automática de los informes de formato HTML, PDF, Excel, OOffice...
Utilizáis iReport en vuestro ordenador para crear los informes (bien sea con los asistentes o desde cero)... los informes permiten agregarles código Java, con lo cual podéis hacer cualquier cosa, repito cualquier cosa con los informes. Genero documentos, que nunca diríais que están generados por una herramienta de gestión de informes... pensaríais que son cartas escritas por una persona. Desde iReport, y mediante webservices podéis interactuar y manipular el repositorio de JasperServer de una manera muy cómoda, con lo que la creación, modificación o actualización de informes es una tarea sencilla y fácilmente asumible.
¿Cómo integrar esto con AbanQ? Queremos unir mundo Java y C++... además, queremos integrar un servidor de informes en nuestro AbanQ. Solución: WebServices. JasperServer permite acceder a todo su repositorio desde WebServices... Y eso es lo que haremos en AbanQ. Para ello, integraremos dentro de AbanQ, la librería de C++ gsoap.
Vamos a hacer una integración sencilla, pero funcional (cuando termine los artículos indicaré por dónde creo que deberían ir las líneas de mejora de esto).
AbanQ: Añadiendo una nueva columna de ordenación en el FLDataTable
El trabajo con sistemas ERP, y especialmente con AbanQ siempre se basan en la navegación por listados de datos (o grids de datos). No estoy muy seguro de que realmente ese sea el sistema más usable o adecuado, pero al menos es muy popular.
En mi afán de tratar de hacer la herramienta aún más usable, echaba en falta una segunda columna de ordenación. Si mi empresa factura todo a través de AbanQ, el número de datos en esa rejilla es grande. Puede filtrarse utilizando el campo de filtro directo que AbanQ provee, pero ese campo de filtro también limita la ordenación de los datos filtrados que se presentan. Tener una segunda columna, como aparece en la imágen, puede ayudar aún más a localizar datos rápidamente.

Bien, veamos cómo hacerlo.
Como siempre, tocaremos un poquito de código de AbanQ... y de Qt 3.3.
AbanQ: Ampliando la funcionalidad de los optionslist
Una de las ayudas que tiene AbanQ a la hora de construir formularios que presentan registros asociados, es sin duda la posibilidad de definir OptionsList. Para una columna de base de datos, podemos definir un conjunto de posibles valores que se almacenarán en la misma, utilizando el tag optionslist dentro de la definición del campo, en el .mtd de la tabla correspondiente. AbanQ, automáticamente, creará un combobox en la vista (el formulario) para que el usuario sólo pueda escoger uno de esos valores.
Pero esta solución, aunque muy buena, no es óptima. Si la columna es un campo de tipo varchar (o string, como se le llama en AbanQ), el optionslist, guarda siempre en esa columna la cadena entera. Supongamos, por ejemplo, una columna "tipo_articulo" y un options list
<optionslist>Articulo prefabricado, Materia prima, Producto intermedio, Producto terminado</optionslist>
El detalle, es que esas cadenas se almacenan constantemente en la columna de la base de datos. Eso no es mayor problema si queremos indexar sobre esa columna, por ejemplo... Quizás es más interesante, el poder guardar en lugar de esos valores, otros, según la siguiente relación
<optionslist>Articulo prefabricado, Materia prima, Producto intermedio, Producto terminado</optionslist> <optionsvalues>1,2,3,4</optionsvalues>
De esta forma, cuando el usuario escoga en el combo box "Artículo prefabricado" en la columna de la base de datos, se guardará un 1.
Bug en AbanQ: Filtrado de campos double, int o uint desde FLTableDB
Creo haber descubierto un bug en AbanQ. La manera de reproducirlo es la siguiente:
Desde un FLTableDB, pinchamos en la opción Ver/Ocultar filtro. Escogemos ahora cualquier campo del tipo "double", "int" o "uint", modificamos la operación a Igual a (cualquier otra también vale para reproducirlo) e introducimos un valor. Al intentar ejecutar el filtro, si tenéis una base de datos PostgreSQL os dará un error, indicando que no se puede ejecutar la función "upper" sobre el campo.
El lugar donde se produce el bug en el código está situado en FLTableDB.cpp, en las líneas 1132 hasta 1137, dentro del método tdbFilterBuildWhere, y es fácil de ver: (código correspondiente al fuente del build 15245 disponible en la web de AbanQ)
case QVariant::UInt:
case QVariant::Int:
case QVariant::Double:
case QVariant::String:
case QVariant::StringList: {
fieldArg = "upper(" + fieldName + ")";
Si os fijáis se aplica la función de base de datos "upper" a todos los campos. Esta función sirve para poner en mayúsculas una cadena de texto (AbanQ la utiliza para garantizar la comparación de cadenas de caracteres independientemente de que el usuario la introduzca en mayúsculas o minúsculas: se compara siempre en mayúsculas). El error está en que PostgreSQL se queja cuando a una columna integer o double precision se le hace un upper.
Así no es posible aplicar un filtro a este tipo de campos. ¿Solución? Super sencilla. Cambiad ese código por este, y recompilad
case QVariant::String:
case QVariant::StringList: {
fieldArg = "upper(" + fieldName + ")";
case QVariant::UInt:
case QVariant::Int:
case QVariant::Double:
Así, el upper sólo se aplica a las cadenas.
Mejorando la experiencia de usuario en AbanQ
La verdad, es que cada día que pasa, me sorprende más gratamente AbanQ. Primero porque examinando el código, es robusto, y está construido con criterio (es raro ver código creado utilizando paradigmas de programación orientado a objetos reales y especialmente utilizandos patrones de diseño adecuadamente, como el objeto FLObjectFactory, que implementa el patrón del mismo nombre...).
Pero siempre hay detalles que son mejorables, especialmente en la interfaz final del usuario, y en la llamada "experiencia de usuario" (qué dificultades o ayudas encuentra el usuario en el programa, siendo simplistas). Partimos de la base de utilizar la versión 2.3 y los módulos 2.2.
Existe una opción en el área de Facturación, dentro de Facturas, en el formulario maestro de Facturas de Proveedores: el botón "Asociar" (nombre mal elegido según mi punto de vista) que permite crear una factura de proveedor a partir de los albaranes emitidos por este. En este formulario, se pueden especificar unos parámetros de búsqueda para así obtener el listado de albaranes que cumplen esos criterios. Esos albaranes se agregan en un control QListView.
El problema de usabilidad viene cuando uno desea consultar algunos datos de ese QListView. Por ejemplo, no presenta ninguna opción de ordenación. ¿Es posible ordenarlo? Veamos como
